统一包含相同模式的行

时间:2015-03-05 10:26:03

标签: regex sed

我有一个具有这种结构的数据库:

word1#element1.1#element1.2#element1.3#...
word2#element2.1#element2.2#element2.3#...
...
...

每当开头的单词相同时,我想统一2行或更多行的元素 例如:

...
word8#element8.1#element8.2#element8.3#...
word9#element9.1#element9.2#element9.3#...
...

现在,让我们假设word8 = word9,这就是结果:

...
word8#element8.1#element8.2#element8.3#...#element9.1#element9.2#element9.3#...
...

我尝试使用sed命令:

  • 我在N
  • 时匹配2行
  • 记住第一行的第一个单词:^\([^#]*\)(所有元素都用'#'表示)
  • 记住第一行的所有其他元素:\([^\n]*\)
  • 检查第二行(\n之后)是否出现相同的字词:\1
  • 如果是这样,我只需取出换行符char和第二行的第一个单词:\1#\2

这是完整的代码:

sed 'N;s/^\([^#]*\)#\([^\n]*\)\n\1/\1#\2/' database

我想了解为什么它不起作用以及如何解决这个问题。

非常感谢你。

5 个答案:

答案 0 :(得分:3)

这可能适合你(GNU sed):

sed 'N;s/^\(\([^#]*#\).*\)\n\2/\1#/;P;D' file

始终读取2行,如果这两行开头的单词匹配,则删除换行符和第二行的匹配部分(恢复#)。

答案 1 :(得分:1)

sed '#n
H
$ { x
:cycle
  s/\(\n\)\([^#]*#\)\([^[:cntrl:]]*\)\1\2/\1\2\3#/g
  t cycle
  s/.//
  p
  }' YourFile

假设单词已排序

  • 将整个文件加载到缓冲区中(如果文件很大,则可以调整代码以仅在缓冲区中使用几行)
  • 最后,将缓冲区内容加载到工作缓冲区
  • 删除前一行以相同单词开头的任何行的新行和第一个单词(并添加#作为seprator)
  • 如果发生,请再次重试
  • 如果没有,请删除第一个字符(由于加载过程而导致的新行)
  • 打印

答案 2 :(得分:1)

您可以尝试使用。它逐行读取输入文件,分成第一个#字符,并使用hash arrays将第一个单词保存为键,并将该行的其余部分附加为值。在END块,它按第一个单词排序并加入行:

perl -lne '
    ($key, $line) = split /#/, $_, 2;
    push @{$hash{$key}}, $line;
    END { 
        for $k ( sort keys %hash ) { 
            printf qq|%s#%s\n|, $k, join q|#|, @{$hash{$k}};
        }   
    }   
' infile

答案 3 :(得分:1)

使用文字替换:

perl -p0E 'while( s/(^|\n)(.+?#)(.*)\n\2(.*)/$1$2$3 $4/ ){}' yourfile

或缩进:

perl -p0E 'while(           # while we can 
      s/(^|\n)                # substitute \n
        (.+?\#)    (.*)  \n     #    id  elems1
         \2        (.*)         #    id  elems2
       /$1$2$3 $4/x             # \n id  elems1 elems2
    ){}'

谢谢:@birei

答案 4 :(得分:1)

$ cat file
word1#element1.1#element1.2#element1.3
word2#element2.1#element2.2#element2.3
word8#element8.1#element8.2#element8.3
word8#element9.1#element9.2#element9.3
word9#element9.1#element9.2#element9.3

$ awk 'BEGIN{FS=OFS="#"}
    NR>1 && $1!=prev { print "" }
    $1==prev { sub(/^[^#]+/,"") }
    { printf "%s",$0; prev=$1 }
    END { print "" }
' file
word1#element1.1#element1.2#element1.3
word2#element2.1#element2.2#element2.3
word8#element8.1#element8.2#element8.3#element9.1#element9.2#element9.3
word9#element9.1#element9.2#element9.3