如何对每个块中的字段上不同长度的数据块进行排序

如何对每个块中的字段上不同长度的数据块进行排序

<我有一个 RDF 文件,其中包含由和描绘的不同行数的数据块/>。在每个块内,都有一个由 标识的字段name="some name"。我需要根据 的值对块进行排序,name而不更改每个块中任何行的顺序。此外,每个块中都有一个带有数字的字段。我需要对这些字段重新编号1n基于每个块的排序位置。

这是 3 个块的示例:

<RDF:Description RDF:about="rdf:#$CHROME1"
 NS1:name="AAA Carolinas"
  NS1:urlToUse=""
  NS1:whereLeetLB="off"
  NS1:leetLevelLB="1"
  NS1:hashAlgorithmLB="md5"
  NS1:passwordLength="16"
  NS1:usernameTB="user"
  NS1:counter=""
  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV123456789"
  NS1:prefix="6%Fl"
  NS1:suffix="I$5g"
  NS1:protocolCB="false"
  NS1:subdomainCB="true"
  NS1:domainCB="true"
  NS1:pathCB="false"
  />
<RDF:Description RDF:about="rdf:#$CHROME2"
 NS1:name="Adobe Forums"
  NS1:urlToUse="adobeforums.com"
  NS1:whereLeetLB="off"
  NS1:leetLevelLB="1"
  NS1:hashAlgorithmLB="md5"
  NS1:passwordLength="12"
  NS1:usernameTB="username"
  NS1:counter=""
  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"
  NS1:prefix=""
  NS1:suffix=""
  NS1:protocolCB="false"
  NS1:subdomainCB="true"
  NS1:domainCB="true"
  NS1:pathCB="false"
  NS1:pattern0="*adobeforums.com*"
  NS1:patternenabled0="true"
  NS1:patterndesc0=""
  NS1:patterntype0="wildcard"
  />
<RDF:Description RDF:about="rdf:#$CHROME3"
 NS1:name="Adorama"
  NS1:urlToUse="adorama.com"
  NS1:whereLeetLB="off"
  NS1:leetLevelLB="1"
  NS1:hashAlgorithmLB="md5"
  NS1:passwordLength="8"
  NS1:usernameTB="username"
  NS1:counter=""
  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"
  NS1:prefix=""
  NS1:suffix=""
  NS1:protocolCB="false"
  NS1:subdomainCB="false"
  NS1:domainCB="true"
  NS1:pathCB="false"
  NS1:pattern0="*adorama.com*"
  NS1:patternenabled0="true"
  NS1:patterndesc0=""
  NS1:patterntype0="wildcard"
  NS1:pattern1="www.adoramapix.com*"
  NS1:patternenabled1="true"
  NS1:patterndesc1=""
  NS1:patterntype1="wildcard"
  />

我提到的数字就是$CHROME上面例子中的数字。我是一位老汇编、COBOL、Fortran、Basic 程序员,但我不熟悉脚本或较新的语言。我可能可以在 Basic 程序中完成此操作,但如果可能的话,我想要一个 Linux 解决方案。

答案1

我希望有一些性格——或者至少有一些细绳- 永远不会出现在你的文件中。我假设这对于 来说是正确的|。为了更安全,我会使用||.

运行这个命令:

sed -n -e H -e '/^ *\/> *$/ { s/.*//; X; s/.*NS1:name="\([^"]*\)/\1&/; s/\n/||/gp }'你的文件|
        排序|
        荷兰-ba |
        sed -e 's/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*/\2\ 1/' -e 's/||/\n/g'

注意:这(可能)需要您有 GNU sed。

概述

  • 用于sed将文件转换为适合排序的格式(详情如下)。
  • 对 的输出进行排序sed
  • 应用(添加)行号。使用任何能生成合适数字的命令。我喜欢nl -ba,但cat -n也同样有效,而且可能还有其他选择。
  • 用于sed从行开头去除行号并将其插入到后面CHROME。将数据恢复为原始格式。

详细信息 - 第一个sed命令

sort命令将每一行视为一条记录。因此,我们从输入文件中获取每个(分隔的)记录并将所有行连接起来,形成一长行。我们还将name值复制到行的开头,以避免指定排序键。

  • 使用该-n选项禁止自动打印。仅当我们说 时才会打印行p

  • H在每一行执行。这会将当前行附加到保留空间。从逻辑上讲,这可能更有意义复制将该<行添加到保留空间(使用命令h),然后附加所有后续行。我随意选择了这种方法。

    请注意,因为我们将<行附加到空的保留空间,所以聚合记录在开头有一个额外的换行符。

  • 查找包含 的行/>,可以选择在其前面和/或后面添加空格。当我们找到它时,我们就知道我们在保留空间中有完整的记录。仅在这些行上执行以下命令。

    • s/.*//清除图案空间(即擦除线条/>)。这并不是真正丢弃任何信息;而是丢弃任何信息。该/>行已经附加到保留空间(因为每一个行附加到保留空间)。
    • x交换模式空间和保持空间。这会将聚合(附加/串联)记录从保留空间检索到模式空间中。由于前面的 ( s/.*//) 命令,这会清除保留空间。
    • s/.*NS1:name="\([^"]*\)/\1&/查找名称字段并将其值复制到记录的开头。如果您可以使用带引号字符的名称,则此操作将会失败在里面。
    • s/\n/||/gp将模式空间中的每个换行符替换为||. (这是将记录转换为一行的步骤。)由于p,这将打印记录。

sed当对示例文件运行时,第一个命令的输出是

AAA Carolinas||<RDF:Description RDF:about="rdf:#$CHROME1"|| NS1:name="AAA Carolinas"||  NS1:urlToUse=""||  NS1:whereLeetLB="off"||  NS1:leetLevelLB="1"||  NS1:hashAlgorithmLB="md5"||  NS1:passwordLength="16"||  NS1:usernameTB="user"||  NS1:counter=""||  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV123456789"||  NS1:prefix="6%Fl"||  NS1:suffix="I$5g"||  NS1:protocolCB="false"||  NS1:subdomainCB="true"||  NS1:domainCB="true"||  NS1:pathCB="false"||  />
Adobe Forums||<RDF:Description RDF:about="rdf:#$CHROME2"|| NS1:name="Adobe Forums"||  NS1:urlToUse="adobeforums.com"||  NS1:whereLeetLB="off"||  NS1:leetLevelLB="1"||  NS1:hashAlgorithmLB="md5"||  NS1:passwordLength="12"||  NS1:usernameTB="username"||  NS1:counter=""||  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"||  NS1:prefix=""||  NS1:suffix=""||  NS1:protocolCB="false"||  NS1:subdomainCB="true"||  NS1:domainCB="true"||  NS1:pathCB="false"||  NS1:pattern0="*adobeforums.com*"||  NS1:patternenabled0="true"||  NS1:patterndesc0=""||  NS1:patterntype0="wildcard"||  />
Adorama||<RDF:Description RDF:about="rdf:#$CHROME3"|| NS1:name="Adorama"||  NS1:urlToUse="adorama.com"||  NS1:whereLeetLB="off"||  NS1:leetLevelLB="1"||  NS1:hashAlgorithmLB="md5"||  NS1:passwordLength="8"||  NS1:usernameTB="username"||  NS1:counter=""||  NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"||  NS1:prefix=""||  NS1:suffix=""||  NS1:protocolCB="false"||  NS1:subdomainCB="false"||  NS1:domainCB="true"||  NS1:pathCB="false"||  NS1:pattern0="*adorama.com*"||  NS1:patternenabled0="true"||  NS1:patterndesc0=""||  NS1:patterntype0="wildcard"||  NS1:pattern1="www.adoramapix.com*"||  NS1:patternenabled1="true"||  NS1:patterndesc1=""||  NS1:patterntype1="wildcard"||  />

详细信息 - 第二个sed命令

  • s/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*/\2\1/ 将线分成几部分:

    • 零个或多个空格。
    • 行号(零个或多个数字)。这就成为了\1团体。
    • 行号、值name及其||后面的制表符。
    • 不过记录上升了RDF:about="rdf:#$CHROME。这就成为了\2团体。
    • 旧记录编号(零个或多个数字)。
    • 隐含地,记录的其余部分。

    RDF:about="rdf:#$CHROME然后它用和行号(新记录号)替换前五个部分。由于记录的其余部分不匹配,因此它不受该命令的影响。

  • s/||/\n/g用换行符替换每个||行,恢复(重新创建)文件的原始多行结构。

明显地, …

…要将输出发送到文件,请在命令最后一行的最末尾添加(即在第二行的末尾)。然后您可以移动 ( ) > your_output_filesedmvyour_output_file到你的原始文件。为命令指定--output=(或 -o) 选项是没有任何意义的sort;的输出sort 必须进入应用行号的命令。如果您想捕获中间文件,请这么说。

相关内容