使用 sed 仅获取捕获组中的字母数字字符

Only get alphanumeric characters in capture group using sed

输入:

x.y={aaa b .c}

请注意,{}中的内容只是示例,实际上可以是任何值。

问题:我只想保留 {}.

中的字母数字字符

所以它会来:

x.y={aaabbc}

试用 0

$ echo 'x.y={aaa b .c}' | sed 's/[^[:alnum:]]\+//g'
xyaaabc

这很好,但我只想修改 {} 内的部分。所以我认为这可能需要捕获组,因此我继续尝试了这些:

试验 1

$ echo 'x.y={aaa b .c}' | sed -E 's/x.y=\{(.*)\}/x.y={}/'
x.y={aaa b .c}

这里我已经正确捕获了我想要修改的内容 (aaa b .c),但是我需要一种方法来以某种方式在 s/[^[:alnum:]]\+//g 上仅在 </code></strong>.</p> <p>相反,我尝试仅捕获 <em>所有字母数字字符(至 <code>),如下所示:

试验 2

$ echo 'x.y={aaa b .c}' | sed -E 's/x.y=\{([[:alnum:]]+)\}/x.y={}/'
x.y={aaa b .c}

当然,它不起作用,因为我只是 期待 alnum,然后立即 } 文字。我没有告诉它忽略非校友的。即,这部分:

s/x.y=\{([[:alnum:]]+)\}/x.y={}/
      ^^^^^^^^^^^^^^^^^^   

它完全匹配:一个左大括号、一些 alnum 和一个右大括号——这不是我想要的。我希望它 匹配所有内容,但只捕获 alnum 的 .


input/output的例子:

x.y={aaa b .c} blah
blah
x.y={1 2 3 def} blah
blah

x.y={aaabc} blah
blah
x.y={123def} blah
blah

在最终放弃并发布问题之前,我在网上进行了搜索,但没有发现任何有用的信息,因为我没有看到任何人遇到与我类似的问题。感谢您的帮助,因为我希望更好地理解 regex/sed 中的变量,谢谢!

使用您展示的示例,请尝试在 awk 中进行以下操作。在 GNU awk.

中编写和测试
awk '
match([=10=],/\{[^}]*}/){
  val=substr([=10=],RSTART,RLENGTH)
  gsub(/[^{}a-zA-Z]/,"",val)
  [=10=]=substr([=10=],1,RSTART-1) val substr([=10=],RSTART+RLENGTH)
}
1
' Input_file

说明: 为以上添加详细说明。

awk '                                      ##Starting awk program from here.
match([=11=],/\{[^}]*}/){                      ##using match function of awk to match from { to first occurrence of }
  val=substr([=11=],RSTART,RLENGTH)            ##Creating val which has sub string of matched regex in it.
  gsub(/[^{}a-zA-Z]/,"",val)               ##Globally substituting everything apart from { } and alphabets in val.
  [=11=]=substr([=11=],1,RSTART-1) val substr([=11=],RSTART+RLENGTH) ##saving everything before match val and everything after match here.
}
1                                          ##Printing line if it doesn't meet `match` condition mentioned above.
'  Input_file                              ##Mentioning Input_file name here. 


通用解决方案: 如果 { 和 } 多次出现,请尝试遵循 awk 代码。

awk '
{
  line=""
  while(match([=12=],/\{[^}]*}/)){
    val=substr([=12=],RSTART,RLENGTH)
    gsub(/[^{}a-zA-Z]/,"",val)
    line=(line?line:"") (substr([=12=],1,RSTART-1) val)
    [=12=]=substr([=12=],RSTART+RLENGTH)
  }
  if(RSTART+RLENGTH!=length([=12=])){
    [=12=]=line [=12=]
  }
  else{
    [=12=]=line
  }
}
1
'  Input_file

这是另一个 gnu-awk 解决方案,使用 FPAT:

s='x.y={aaa b .c}'
awk -v OFS= -v FPAT='{[^}]+}|[^{}]+' '
{
   for (i=1; i<=NF; ++i)
      if ($i ~ /^{/) $i = "{" gensub(/[^[:alnum:]]+/, "", "g", $i) "}"
} 1' <<< "$s"

x.y={aaabc}

使用 sed(在 GNU sed 上测试,语法可能因其他实现而异):

$ sed -E ':a s/(\{[[:alnum:]]*)[^[:alnum:]]+([^}]*})//; ta' ip.txt
x.y={aaabc} blah
blah
x.y={123def} blah
blah
  • :a将该位置标记为标签a(只要替换成功就使用ta跳转)
  • (\{[[:alnum:]]*) 匹配 { 后跟零个或多个字母字符
  • [^[:alnum:]]+ 匹配一个或多个 non-alnum 个字符
  • ([^}]*}) 匹配到下一个 } 字符


如果perl没问题:

$ perl -pe 's/\{\K[^}]+(?=\})/$&=~s|[^a-z\d]+||gir/e' ip.txt
x.y={aaabc} blah
blah
x.y={123def} blah
blah
  • \{\K[^}]+(?=\}) 匹配 {} 的序列(假设 } 不能出现在两者之间)
    • \{\K(?=\}) 用于避免大括号成为匹配部分的一部分
  • e 标志允许您在替换部分使用 Perl 代码,在这种情况下是另一个替换命令
  • $&=~s|[^a-z\d]+||gir这里,$&指的是整个匹配部分,gi标志用于global/case-insensitive,r标志用于return 这个替换的值而不是修改 $&
    • [^a-z\d]+匹配non-alphanumeric个字符(假设是ASCII,也可以用[^[:alnum:]]+
    • 如果您还想保留下划线,请使用 \W+

对于这两种方案,您可以根据需要添加x\.y=前缀以缩小匹配范围。