如何将 CR 分隔的字符串拆分为多行并将 id 附加到每个新行?

如何将 CR 分隔的字符串拆分为多行并将 id 附加到每个新行?

我有一个文件,其中的行由内部回车符分隔,如下所示:

电磁脉冲|123|10\r信息|约翰|史密斯|M|1980/01/12\r地址|125|布里奇路|哥伦布|俄亥俄州
电磁脉冲|456|10\r信息|大卫|皮尔特|M|1980/02/12\r地址|257|布里奇路|哥伦布|俄亥俄州
电磁脉冲|789|10\r信息|珍|麦肯齐|F|1980/03/12\r地址|389|布里奇路|哥伦布|俄亥俄州

请注意,CR 之间的行部分进一步由|字符分隔。

我想在 CR 字符处将每一行分成单独的行。然后每个新的行(即,用换行符替换 CR 形成的行)应以|原始行的 Id(第二个分隔字段)开头。

预期输出:

EMP|123|10
123|INFO|JOHN|SMITH|M|01/12/1980
123|ADDR|125|BRIDGE RD|COLUMBUS|OH
EMP|456|10
456|INFO|DAVID|PIRT|M|02/12/1980
456|ADDR|257|BRIDGE RD|COLUMBUS|OH
EMP|789|10
789|INFO|JENN|MCKENZI|F|03/12/1980
789|ADDR|389|BRIDGE RD|COLUMBUS|OH

Id 是重复的,因此我们可以知道输出中的每组三行属于同一(一个)输入行。

我尝试了下面的命令,但它只用换行符替换了 CR;我不知道如何将 Id 附加到新行

tr '\r' '\n' < test.txt > new.txt

输出:

EMP|123|10
INFO|JOHN|SMITH|M|01/12/1980
ADDR|125|BRIDGE RD|COLUMBUS|OH
EMP|456|10
INFO|DAVID|PIRT|M|02/12/1980
ADDR|257|BRIDGE RD|COLUMBUS|OH
EMP|789|10
INFO|JENN|MCKENZI|F|03/12/1980
ADDR|389|BRIDGE RD|COLUMBUS|OH

我怎样才能做到这一点?

答案1

怎么样

$ awk -F '\r' '{
  print $1; 
  split($1,a,"|"); 
  for(i=2;i<=NF;i++) print a[2] "|" $i;
}' file
EMP|123|10
123|INFO|JOHN|SMITH|M|01/12/1980
123|ADDR|125|BRIDGE RD|COLUMBUS|OH
EMP|456|10
456|INFO|DAVID|PIRT|M|02/12/1980
456|ADDR|257|BRIDGE RD|COLUMBUS|OH
EMP|789|10
789|INFO|JENN|MCKENZI|F|03/12/1980
789|ADDR|389|BRIDGE RD|COLUMBUS|OH

答案2

在 sed 中:

sed ':loop; s/^\([^|]*|\)\([^|]*|\)\([^\r]*\)\r/\1\2\3\n\2/; t loop'

这是一个(某种程度上)简单的替换:匹配由所有字符组成的模式(即,直到并包括)\r缓冲区中的第一个字符。将其分为三个捕获组:

  • 一切都经过(即,直到并包括)|缓冲区中的第一个。这将适用EMP|于文件中的每一行。
  • 之后的所有内容,直到(即,直到并包括)|缓冲区中的下一个(即,第二个)。这将是123|, 456| 或 789| 在您的文件中。
  • 之后的一切,直到(但是不是\r包括)缓冲区中的第一个。

然后将上面的替换为

  • 三个捕获组 ( \1\2\3);即,直到(但不包括)\r缓冲区中第一个的所有内容,
  • 换行符,以及
  • 第二个捕获组 ( \2);即 id 和 |.

然后缓冲区的其余部分(所有内容\r缓冲区中的第一个)保留在原处,因此它位于新创建的行上的重复 id 之后。

那么,如果上面匹配并且s替换成功(t测试如果成功则转到),返回并重试。

对于初学者来说可能不明显的一个方面是,即使我们\n使用 substitute 命令,从而创建一个新行, sed仍然对整个缓冲区进行操作(包括内部/嵌入的换行符)而不仅仅是“新行”(即换行符之后的部分)。所以, sed读第一行,

EMP|123|10\rINFO|JOHN|SMITH|M|01/12/1980\rADDR|125|BRIDGE RD|COLUMBUS|OH

进入缓冲区。该s命令第一次执行后,缓冲包含

EMP|123|10
123|INFO|JOHN|SMITH|M|01/12/1980\rADDR|125|BRIDGE RD|COLUMBUS|OH

所以s命令的下一次迭代匹配

  • \1= EMP|,
  • \2= 123|,并且
  • \3= 10 123|INFO|JOHN|SMITH|M|01/12/1980 (包括在第一次迭代中插入的换行符)。

警告:如果输入行中的\r第二个前面有一个,这可能会造成混乱 。|

相关内容