如果我有这样的文件:
abc defghaijkb,mnaobpqa
pbqaaa
qrs - a .. b ...
cde
如何提取以a
开头并以b
开头的所有部分(我选择这些字符来简化示例,它们可能会被一些更复杂的正则表达式替换)?这是一个理想的输出:
ab
aijkb
aob
a .. b
(将每个项目放在一个单独的行)。由于(g)awk中没有非贪婪的匹配(.*?
),我找不到如何解决这个问题(例如使用split
)。
注1:不需要使用多行匹配 - 也就是说,regex1
和regex2
之间不允许使用换行符。
注意2:我不想使用sed
,我想知道是否可以使用awk,bash或其他一些处理输入文件的命令行工具来完成此操作line ... AWK似乎是一个很好的解决方案,但是...如果它只支持非贪婪的.*?
注3:我无法使用grep
,因为在处理大文件时,我总是遇到memory exhausted
错误。
注意4.以下是更复杂的regex1
和regex2
的示例。如果他们可以包含非贪婪.*?
怎么办?例如。 <a>.*?<b>.*?</b>.*?</a>
。
更新。更复杂的例子:
[a]text1[a]text000[b]text2[/b]text11[/a]c defgh[a]text3[b]text33[/b]text333[/a]...[/a],mnaobpqa
...[b]aa[/b]bb[/a],,,
qa - [a][b][/b][/a] aabbcc ...
cde
期望的输出:
[a]text000[b]text2[/b]text11[/a]
[a]text3[b]text33[/b]text333[/a]
[a][b][/b][/a]
答案 0 :(得分:2)
Pure AWK hackery:
awk 'BEGIN{RS="a"}/b/&&NR!=1{sub(/b.*/,"");if($0!~"\n")print"a"$0"b"}'
a
拆分文件并忽略第一段(前a
)。b
,请忽略它。b
并进一步切断。"a"
和"b"
并打印。我不认为你应该永远使用它。使用perl
- 它出现在几乎任何存在awk
的系统上,并使这项任务变得轻而易举:
perl -ne 'print map { "$_\n" } /a.*?b/g;'
这甚至适用于grep
不支持PCRE的系统,因为Perl的定义支持PCRE。 (我不知道内存耗尽的错误 - 正如rici所说,非病态的正则表达式不应该发生。)
编辑以回应OP提出的其他问题:
&#34;有能力的工具&#34;是任何支持非贪婪运算符和每行多个匹配的东西 - 在这种情况下,perl
是无处不在,表达性和速度之间的最佳折衷。
编写的行是一个过滤器 - 您在标准输入中提供输入,您可以在标准输出中输出 - 就像您使用awk
或sed
一样。
标准的regexp语法适用:方括号和斜杠需要转义。
perl -ne 'print map { "$_\n" } /\[a\].*?\[b\].*?\[\/b\].*?\[\/a\]/g;' <infile >outfile
答案 1 :(得分:1)
这可以使用grep
和现代BSD grep(例如Mac OS上的那个)来实现。
grep -E "a.*?b" -o file
.*?
执行非贪婪的匹配。
在只有GNU grep的平台上,可能需要使用-P
而不是-E
;在基线-POSIX平台或SysV派生的Unixen上,这可能根本不起作用(因为POSIX ERE没有指定非贪婪匹配,the POSIX standard for grep
没有定义-o
)。
答案 2 :(得分:1)
搜索本身可以用Awk编写:
$ awk '{
split($0, line, "")
m=""
for(i in line) {
if(line[i] == "a")
m=line[i]
else if(m)
m=m line[i]
if(m && line[i] == "b") {
print m
m=""
}
}
}' file
ab
aijkb
aob
a .. b