如何在使用awk修改其他匹配时保留部分匹配?

时间:2017-08-13 12:45:29

标签: regex awk

如何使用awk修改其他匹配时保留部分匹配?

示例:来自“方法(arg”,我想得到“方法(arg”。

>> echo "method ( arg" | awk '{line = $0; gensub("[a-zA-Z]+ *\( *[a-zA-Z]+", "\1\2\3", "g", line); print line;}'
awk: cmd. line:1: warning: escape sequence `\(' treated as plain `('
awk: cmd. line:1: (FILENAME=- FNR=1) fatal: Unmatched ( or \(: /[a-zA-Z]+ *( *[a-zA-Z]+/

>> echo "method ( arg" | awk '{line = $0; gensub("[a-zA-Z]+ *[(] *[a-zA-Z]+", "\1\2\3", "g", line); print line;}'
method ( arg

修改

记录:

>> echo "method ( arg" | awk '{line = $0; print gensub(/([a-zA-Z]+) *\( *([a-zA-Z]+)/, "\\1(\\2", "g", line)}'
method(arg

>> echo "method ( arg" | awk '{line = $0; print gensub(/([[:alpha:]]+) *\( *([[:alpha:]]+)/, "\\1(\\2", "g", line)}'
method(arg

2 个答案:

答案 0 :(得分:1)

有更简单的方法可以解决此问题,但这里的解决方案类似于awk的初始尝试:

echo "method ( arg" |
  gawk '{line = $0; print gensub("([a-zA-Z]+) *(\\() *([a-zA-Z]+)", "\\1\\2\\3", "g", line)}'

您的原始代码存在许多问题:

  • \(无效,因为您需要双重转义 - 因为反斜杠本身也需要转义。
  • 由于同样的原因,
  • \1\2\3也无法正常工作。
  • gawk返回一个新字符串;它不会修改原始变量。因此,您需要直接打印(就像我一样),或者将结果与新变量相同。
  • 您实际上并未使用任何捕获组 - 因此\1\2\3无法匹配!我在上面添加了这些。由于空白区域位于捕获组之外,因此可以解决原始问题。

这是一个更简单的解决方案,使用sed代替awk

echo "method ( arg" | sed -E "s/([a-zA-Z]+) *(\() *([a-zA-Z]+)/\1\2\3/g"

原则是一样的,但是对于需要逃避(或双重逃逸)的东西的混淆要少得多!

答案 1 :(得分:0)

请参阅我在@TomLord's answer下的评论,了解您的脚本和Toms的问题,但是这里是如何真正做到您尝试使用GNU awk进行第3次arg匹配() + gensub():

$ echo 'here is method ( argi etc' |
gawk 'match($0,/(.*)(\w+\s*\(\s*\w+)(.*)/,a){$0=a[1] gensub(/\s+/,"","g",a[2]) a[3]} 1'
here is method(argi etc

我还将\w用于"字组成字符"正如我所期望的,您匹配的令牌可能包含_,因为它们似乎代表函数/方法和参数名称,因此使用[[:alpha:]][a-zA-Z] isn'足够(\w[[:alpha:]_]的简写)我使用\s这是[[:space:]]的简写,而不是将令牌之间的空格限制为空白字符。 \w\s也是特定的。

如果你没有gawk(你这样做),那么解决方案将采用相同的方法,但代码更多:

$ echo 'here is method ( argi etc' |
awk 'match($0,/[[:alpha:]_]+[[:space:]]*\([[:space:]]*[[:alpha:]_]+/) {
    tgt=substr($0,RSTART,RLENGTH)
    gsub(/[[:space:]]+/,"",tgt)
    $0=substr($0,1,RSTART-1) tgt substr($0,RSTART+RLENGTH)
} 1'
here is method(argi etc

请注意,上述内容适用于目标字符串method ( argi,无论它出现在某个行上的任何位置,并且不需要它作为您的/ Toms在其自己的行上所需的脚本以及空格的删除与目标字符串的标识分离,因此不再依赖于具有3个空格分隔字段的目标字符串来运行,因此如果您必须识别具有20个字段的目标字符串,那么#39 ; d只是更改match()中使用的正则表达式,您不必更改执行空间删除的代码,这与原始脚本不同,其中空间删除依赖于3个反向引用。