从输入中提取感兴趣子字符串的最快方法是什么?如下所示?
MsgTrace(65/26)noop:user=xxx=INBOX:cmd=534
ImapFetchComplete(56/39)user=xxxxxxxxxx
所需的输出(即本例中字符串:
后面的MsgTrace(65/26)
- 终止字符串):
noop
我尝试了以下内容,但没有成功:
egrep -i "[a-zA-Z]+\(.*\)[a-z]+:"
答案 0 :(得分:2)
grep
会在给定输入行找到匹配项时返回整行。
虽然选项-o
仅将输出限制为正则表达式匹配的那一行,但在这种情况下仍然不够,因为您需要该匹配的子字符串。
但是,由于您使用的是Linux,因此可以使用GNU grep
的{{1}}选项(支持PCREs,Perl兼容的正则表达式) ,它允许通过-P
(删除到目前为止匹配的所有内容)和\K
等功能提取子匹配(一个不会对匹配做出贡献的前瞻断言) ):
(?=...)
Ed Morton指出(在已删除的评论中)GNU $ grep -Po "[a-zA-Z]\(.*\)\K[a-z]+(?=:)" <<'EOF'
MsgTrace(65/26)noop:user=xxx=INBOX:cmd=534
ImapFetchComplete(56/39)user=xxxxxxxxxx
EOF
noop # output
的{{1}}页面仍然会调用grep
选项&#34;高度实验&#34;可能&#34;警告未实现的功能&#34;,但该选项已存在多年,并且在实践中我还没有看到警告或性能问题 - YMMV。
在目前的情况下,上述命令甚至优于man
和-P
解决方案 - 请参阅NeronLeVelu's helpful performance comparison。
interesting article Ed指出 可以表面的潜在性能问题,例如sed
(通过PCRE库),Perl本身使用的正则表达式引擎许多其他广泛使用的(和成熟的)正则表达式引擎,例如Python,Ruby和PHP:
awk
的{较长版本}以匹配grep -P
。答案 1 :(得分:2)
你可以试试这个:
$ sed -n 's/[[:alpha:]]*([^)]*)\([[:lower:]]*\):.*/\1/p' file
noop
它可以移植到所有POSIX seds并且不使用PCRE,只使用BRE,因此regexp匹配部分至少应该很快。
答案 2 :(得分:2)
对这样一个样本条目的2469120行文本进行快速而肮脏的测试,将grep -PO
作为获胜者
time sed -n -e 's/^MsgTrace[^)]\{4,\})//;t M' -e 'b' -e ':M' -e 's/:.*//p' YourFile >/dev/null
real 0m7.61s
user 0m7:10s
sys 0m0.13s
time awk -F ':' '/^MsgTrace/{ sub( /.*)/, "", $1); print $1}' YourFile >/dev/null
real 0m17.43s
user 0m16.19s
sys 0m0.17s
time grep -Po "[a-zA-Z]\(.*\)\K[a-z]+(?=:)" YourFile >/dev/null
real 0m6.72s
user 0m6.23s
sys 0m0.11s
time sed -n 's/[[:alpha:]]*([^)]*)\([[:lower:]]*\):.*/\1/p' YourFile >/dev/null
real 0m17.43s
user 0m16.29s
sys 0m0.12s
time grep -Po '(?<=MsgTrace\(65/26\)).*?(?=:)' YourFile >/dev/null
real 0m16.38s
user 0m15.22s
sys 0m0.15s
对于@EdMorton问题(我重做相同的原始sed以在机器加载的相同上下文中具有比较值)。确切的字符串要快很多,我想sed在选择哪个是所有标准中最长的一个之前尝试几个组合,其中.*l
比pool is full
提供更多的可能性
time sed -n -e 's/^MsgTrace([^)]\{3,\})//;T' -e 's/:.*//p' YourFile >/dev/null
real 0m7.28s
user 0m6.60s
sys 0m0.13s
time sed -n -e 's/^[[:alpha:]]*([^)]\{3,\})//;T' -e 's/:.*//p' YourFile >/dev/null
real 0m10.44s
user 0m9.67s
sys 0m0.14s
time sed -n -e 's/^[[:alpha:]]*([^)]*)//;T' -e 's/:.*//p' YourFile >/dev/null
real 0m10.54s
user 0m9.75s
sys 0m0.11s