Jos*_*hro 4 grep sed regular-expression
我希望 sed 相当于:\n .\xc2\xa0\nI\xc2\xa0 假设,希望对输出进行进一步的处理。\xc2\xa0\n这一步可能只是某些事情的第一部分\n通过添加更长的 sed 表达式将更加详细。grep -Eo 'regex';\xc2\xa0s\xe2\x80\xa6
更清楚地说,我希望能够隔离每个字符串\n匹配\xc2\xa0输入流中给定的正则表达式。\xc2\xa0\n为了概念验证的目的,\n每个这样的字符串应该输出为\ xc2\xa0 没有\xc2\xa0context\n 的单独行(即,\xc2\xa0no\xc2\xa0 周围的文本来自\xc2\xa0input)。\xc2\xa0\n因此\xc2\xa0an\xc2\xa0input 行有多个 (非重叠)匹配\n应导致多个输出行;\n没有匹配的输入行应导致无\xc2\xa0输出。
\n正则表达式: [a-zA-Z]{3}[0-9]{4} \xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\xe2\x80\x83\n(即\xc2\xa0后面跟着三个字母四位数字)
输入:
\nFGH1234 and CAS4057\nMAX2345\nRun Code Online (Sandbox Code Playgroud)\n输出:
\nFGH1234\nCAS4057\nMAX2345\nRun Code Online (Sandbox Code Playgroud)\n
row*_*oat 10
更新以修复零长度正则表达式匹配的行为:
sed 't match;s/REGEX/\n&\n/g;D;:match;/^\n/!P;s/\n//;D' file
Run Code Online (Sandbox Code Playgroud)
全局替换匹配<newline><matched part><newline>. 然后通过创建循环P;s/\n//;D来打印它们t match,依此类推,直到打印完所有匹配的部分。/^\n/!P使用而不是 justP以便只打印非空匹配(就像 GNUgrep -o那样)。
使用的类似方法awk可以是:
regex='REGEX' awk 'BEGIN {FS="\n"}
gsub(ENVIRON["regex"], FS "&" FS) {for (i=2;i<NF;i+=2) if ($i!="") print $i}
' file
Run Code Online (Sandbox Code Playgroud)
原始尝试:请注意,当给定与空字符串(例如.*)匹配的正则表达式时,这些命令的行为会很糟糕 - 空行将在无限循环中打印。
通过一次调用sed:
sed '
t match
s/[[:alpha:]]\{3\}[[:digit:]]\{4\}/\
&\
/;D;:match
P;D' file
Run Code Online (Sandbox Code Playgroud)
使用POSIXsed语法:regex 是基本正则表达式,\在 的替换字符串中使用转义换行符s///,并且使用换行符而不是;在分支标签之后。某些版本sed(例如 GNU sed)可以在一行上接受所有脚本:
sed 't match;s/[[:alpha:]]\{3\}[[:digit:]]\{4\}/\n&\n/;D;:match;P;D' file
Run Code Online (Sandbox Code Playgroud)
替换通过在匹配部分之前和之后添加换行符来隔离第一个匹配项。t match仅在成功替换后才会遵循脚本开头的条件分支。:match是打印匹配部分的地方。D使用以便从模式空间中删除包含匹配的行,并将剩余部分用作下一个循环的输入,从而允许找到更多匹配。
这与rowboat\xe2\x80\x99s 答案非常相似(但独立开发),\n并且可能有稍微更详细的解释。
\n使用 GNU sed:
\nsed -En \'t dummy; : dummy; s/[a-zA-Z]{3}[0-9]{4}/&\\n/; T; s/.*([a-zA-Z]{3}[0-9]{4}\\n)/\\1/; P; D\'\nRun Code Online (Sandbox Code Playgroud)\n解释:
\n-E\xe2\x80\x83\xe2\x80\x83\n使用扩展正则表达式(ERE)。\xc2\xa0\n如果没有这个,我们就不得不说\\{3\\}and\xc2\xa0 \\{4\\}。
\xe2\x80\x82 n\xe2\x80\x83\xe2\x80\x83\nDon\xe2\x80\x99t 自动打印任何内容;只打印我们所说的打印内容。\xc2\xa0\n这个\xc2\xa0是\xc2\xa0理想的,因为,像 一样grep,我们不想打印\n对于不\xe2\x80\x99t包含与正则表达式匹配的字符串的输入行。
t dummy; : dummy\xe2\x80\x83\n跳转到紧随其后的 (\xe2\x80\x9c dummy\xe2\x80\x9d) 标签。\xc2\xa0\n这个\xc2\xa0 是一个\xc2\xa0 条件跳转,因此它可能或可能不会发生。\xc2\xa0\n但是\xe2\x80\x99并不重要,\n因为\xe2\x80\x99在跳转命令和\xc2\xa0the\xc2\xa0标签之间没有任何内容。
这看起来像一个无操作,而且确实是这样,除了它清除 sed\xe2\x80\x99s 内存\n是否存在成功的替代命令。
\ns/[a-zA-Z]{3}[0-9]{4}/&\\n/\xe2\x80\x83\n查找 OP\xe2\x80\x99s 正则表达式。\xc2\xa0\n如果\xc2\xa0找到,则将其替换为自身加上\xc2\xa0换行符(即\xc2\xa0添加\xc2 \xa0换行)。
T\xe2\x80\x83\xe2\x80\x83\n如果上述替代命令失败(没有\xe2\x80\x99找到模式),\n跳转到\xc2\xa0the\xc2\xa0script 和\xc2\的末尾xa0read the \xc2\xa0next line of \xc2\xa0input.\xc2\xa0\n文档说T,
\n\n
T label\n如果没有
\ns///成功替换\n自从读取了最后一个输入行并且自从\xc2\xa0lastt或T命令之后,\n则分支到label;\xe2\x80\x82,如果label省略了\xc2\xa0,则分支到脚本末尾。 \xc2\xa0\n这是一个 GNU 扩展。
因此,\xe2\x80\x99 就是我们使用标签dummy\xe2\x80\x94\n 执行此操作的原因,以便该 T命令\n只查看前一个s命令。
s/.*([a-zA-Z]{3}[0-9]{4}\\n)/\\1/\xe2\x80\x83\n查找 OP\xe2\x80\x99s 正则表达式,前面有任意数量的任意字符 ( .*)\n和\xc2\xa0,后跟 \xc2\xa0 换行符,\n并将它们替换为正则表达式匹配项和换行符\n(即\xc2\xa0删除正则表达式匹配之前的任何文本)。\xc2\xa0\n乍一看\xc2\xa0,这看起来可能会找到\xc2\xa0该行的最后一个匹配项,\因为.*贪婪。\xc2\xa0\n但是它找到了第一个,因为只有第一个匹配\n后面跟着一个换行符(因为第一个s是\xe2\x80\x99t g lobal)。
P\xe2\x80\x83\n (大写P ) \xe2\x80\x83\n通过第一个换行符打印模式缓冲区。\xc2\xa0\n这只是与 \xc2\xa0regex\n 匹配的字符串(就像grep\xc2\xa0-o会输出什么)。
D\xe2\x80\x83\xe2\x80\x83\n通过第一个换行符删除模式缓冲区\n和\xc2\xa0跳转到脚本的开头。
使用 GNU sed 在管道中调用两次可以获得与 grep 相同的输出:
sed -E 's/[a-zA-Z]{3}[0-9]{4}/\n&\n/g' input \
| sed -E '/^[a-zA-Z]{3}[0-9]{4}$/!d'
Run Code Online (Sandbox Code Playgroud)
在概念上:
sed -E 's/REGEX/\n&\n/g' input \
| sed -E '/^REGEX$/!d'
Run Code Online (Sandbox Code Playgroud)
第一个调用将匹配的正则表达式与周围的换行符隔离。
第二个调用deletes与正则表达式不匹配的所有行。
实际上,它只打印与正则表达式完全匹配的行grep -o。
尝试使用一些扩展的正则表达式来匹配,并删除前导或尾随不需要的部分意味着失败。正则表达式引擎将匹配太多(因为任何*)不受限制并且会匹配as much as possible。构建具有环视匹配的 PCRE 可能会解决此问题,但 sed(任何当今的 sed)无法使用 PCRE。
这个解决方案很简单,没有已知的问题(除了如果正则表达式可以匹配“无”它会打印许多空行)。
尝试将这种使用减少到单行 sed 变得(令人惊讶地)相当复杂。其他答案试图通过几个极端情况和复杂的 sed 语法来完成此任务。
我们将继续努力寻找通用解决方案。