统一包含相同模式的行
Unify lines that contains same patterns
我有一个具有这种结构的数据库:
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
:
- 我一次匹配 2 行
N
- 记住第一行的第一个单词:
^\([^#]*\)
(除'#'外的所有元素)
- 记住第一行的所有其他元素:
\([^\n]*\)
- 检查第二行(
\n
之后)是否出现相同的单词:</code></li>
<li>如果是这样我就把换行符和第二行的第一个字去掉:<code>#
这是完整的代码:
sed 'N;s/^\([^#]*\)#\([^\n]*\)\n/#/' database
我想了解为什么它不起作用以及如何解决该问题。
非常感谢您。
sed '#n
H
$ { x
:cycle
s/\(\n\)\([^#]*#\)\([^[:cntrl:]]*\)/#/g
t cycle
s/.//
p
}' YourFile
假设单词已排序
- 将整个文件加载到缓冲区(如果文件太大而只能使用缓冲区中的几行,则可以调整代码)
- 最后,将保持缓冲区内容加载到工作缓冲区
- 删除新行和前一行以相同单词开头的任何行的第一个单词(并添加
#
作为分隔符)
- 如果发生,重试一次
- 如果不是,删除第一个字符(由于加载过程而换行)
- 打印
你可以试试perl。它逐行读取输入文件,拆分第一个 #
字符并使用 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
使用文本替换:
perl -p0E 'while( s/(^|\n)(.+?#)(.*)\n(.*)/ / ){}' yourfile
或缩进:
perl -p0E 'while( # while we can
s/(^|\n) # substitute \n
(.+?\#) (.*) \n # id elems1
(.*) # id elems2
/ /x # \n id elems1 elems2
){}'
感谢:@birei
这可能适合您 (GNU sed):
sed 'N;s/^\(\([^#]*#\).*\)\n/#/;P;D' file
始终读取 2 行,如果这两行开头的单词匹配,则删除换行符和第二行的匹配部分(恢复 #
)。
$ 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 && !=prev { print "" }
==prev { sub(/^[^#]+/,"") }
{ printf "%s",[=11=]; prev= }
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
我有一个具有这种结构的数据库:
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
:
- 我一次匹配 2 行
N
- 记住第一行的第一个单词:
^\([^#]*\)
(除'#'外的所有元素) - 记住第一行的所有其他元素:
\([^\n]*\)
- 检查第二行(
\n
之后)是否出现相同的单词:</code></li> <li>如果是这样我就把换行符和第二行的第一个字去掉:<code>#
这是完整的代码:
sed 'N;s/^\([^#]*\)#\([^\n]*\)\n/#/' database
我想了解为什么它不起作用以及如何解决该问题。
非常感谢您。
sed '#n
H
$ { x
:cycle
s/\(\n\)\([^#]*#\)\([^[:cntrl:]]*\)/#/g
t cycle
s/.//
p
}' YourFile
假设单词已排序
- 将整个文件加载到缓冲区(如果文件太大而只能使用缓冲区中的几行,则可以调整代码)
- 最后,将保持缓冲区内容加载到工作缓冲区
- 删除新行和前一行以相同单词开头的任何行的第一个单词(并添加
#
作为分隔符) - 如果发生,重试一次
- 如果不是,删除第一个字符(由于加载过程而换行)
- 打印
你可以试试perl。它逐行读取输入文件,拆分第一个 #
字符并使用 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
使用文本替换:
perl -p0E 'while( s/(^|\n)(.+?#)(.*)\n(.*)/ / ){}' yourfile
或缩进:
perl -p0E 'while( # while we can
s/(^|\n) # substitute \n
(.+?\#) (.*) \n # id elems1
(.*) # id elems2
/ /x # \n id elems1 elems2
){}'
感谢:@birei
这可能适合您 (GNU sed):
sed 'N;s/^\(\([^#]*#\).*\)\n/#/;P;D' file
始终读取 2 行,如果这两行开头的单词匹配,则删除换行符和第二行的匹配部分(恢复 #
)。
$ 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 && !=prev { print "" }
==prev { sub(/^[^#]+/,"") }
{ printf "%s",[=11=]; prev= }
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