使用 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=
前缀以缩小匹配范围。
输入:
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=
前缀以缩小匹配范围。