如何使用 sed 匹配由两个以上边界定义的多行范围?
How to Match Using sed a Multi-Line Range Defined by More Than Two Bounds?
我该如何...
...使用 sed
不仅可以匹配标准的 2 边界范围,还可以匹配以 "multi-range" 为特征的范围 - 某些特定的多个 (>2
) 子匹配订单...
...WHILE 包含成对的内部匹配(例如 (
/ )
)可能与一对多范围的边界模式重叠?
工作简单范围匹配
假设我有一个模式,其内容在给定格式中类似于以下内容:
someVar: SomeObj.someFunct
("name1", "name2",
SomeConst)
在上述大多数情况下,无论某些常量 SomeObj.someFunct
的格式如何,我都可以使用范围模式进行捕获:
cat $file | sed -ne '/^[ \t]*[a-zA-Z0-9_\: ]*SomeObj.someFunct/,/)/ {p}'
双范围边界是:
/^[ \t]*[a-zA-Z0-9_\: ]*SomeObj.someFunct/
和
/)/
所以基本上它是在寻找开始位,然后是结束括号。
失败案例
但是如果在 )
之间有东西,这偶尔会失败。一个简单的例子可能是:
someVar: SomeObj.someFunct
(thisTimeImCallingTheFunction(), "name2",
SomeConst)
如果 SomeObj.someFunct 在下一行,它也会失败,即:
someVar:
SomeObj.someFunct("name1", "name2",
SomeConst)
乘法有界范围?
我的想法是,我想要一个 "multi-range",或者等价于:
/^[ \t]*[a-zA-Z0-9_\: ]*/
和
/SomeObj.someFunct/
和
/(/
|和(可选)
|
|一些任意数量的中介 (
和 )
)
和
/)/
...因此范围必须至少检查 4 个边界,最后两个检查可选的中间值以防止内部 (
/ )
对。
我得到了什么
不幸的是,即使考虑到可选的内部匹配,这个天真的版本也没有....
cat $file | sed -ne '/^[ \t]*[a-zA-Z0-9_\: ]*/,/SomeObj.someFunct/,/(/,/)/ {p}'
无效。
似乎模式 /check1/,/check2/,/check3/,/check4/
无效,必须采用一些更复杂的策略。
问题总结
- 检查由两个末端模式和内部模式以某种特定顺序定义的连续范围(但不一定在同一行)
- 每遇到一个
(
,在范围 )
. 的最终匹配之前跳过一个 )
Note/Disclaimer
我搜索了以前类似的问题,认为有人问过,但只找到了问题 asking about multiple ranges with standard dual bounds,而不是 "multi range" 在由两个以上的边界匹配定义的单个连续范围的意义上.
奖金问题:
一旦有了这样的多界匹配,我该如何多捕获以下模式:
someVar
之前的空格。
- 三个参数(包括interiror
(
/ )
in the complex case.
您的第一个嵌套函数调用失败案例无法在正确的 "regular" 表达式中处理。一些扩展,如 Perl 的 REs 可以处理查找任意嵌套事物的匹配对,但实际上您此时需要一个实际的解析器。
这可能适合您 (GNU sed):
sed -rn '/^\s*\w+:/!b;:a;N;/\)\s*$/!ba;/^\s*\w+:\s*SomeObj\.someFunct\s*\(/p;//d;D' file
这匹配第一个变量,然后附加更多行,直到 )
后跟可能的白色 space 和行尾。然后检查模式 space 以查看是否满足所有其他匹配项,如果满足则打印模式 space。否则删除第一行并重复该过程。
N.B。如前所述,正则表达式不能在所有情况下都用于匹配括号,这应该留给解析器处理。
sed 用于 s/old/new,仅此而已。如果您要用它做任何其他事情,那么您使用的结构在 1980 年代发明 awk 时就已经过时了。使用 GNU awk 进行多字符 RS 和第三个参数匹配():
$ cat tst.awk
BEGIN { RS="^$" }
match([=10=],/([[:blank:]]*\w*:\s*SomeObj\.someFunct\s*\()(.*)/,a) {
str = a[1]
while ( match(a[2],/([^\)]*\))(.*)/,a) ) {
str = str a[1]
if ( !index(a[1],"(") ) {
break
}
}
print str
}
$ awk -f tst.awk file
someVar: SomeObj.someFunct
(thisTimeImCallingTheFunction(), "name2",
SomeConst)
上面找到一个与您的起始正则表达式匹配的字符串,然后将以 )
结尾的字符串附加到该字符串,直到它到达一个以 )
结尾且不包含 [=13= 的字符串].
我该如何...
...使用 sed
不仅可以匹配标准的 2 边界范围,还可以匹配以 "multi-range" 为特征的范围 - 某些特定的多个 (>2
) 子匹配订单...
...WHILE 包含成对的内部匹配(例如 (
/ )
)可能与一对多范围的边界模式重叠?
工作简单范围匹配
假设我有一个模式,其内容在给定格式中类似于以下内容:
someVar: SomeObj.someFunct
("name1", "name2",
SomeConst)
在上述大多数情况下,无论某些常量 SomeObj.someFunct
的格式如何,我都可以使用范围模式进行捕获:
cat $file | sed -ne '/^[ \t]*[a-zA-Z0-9_\: ]*SomeObj.someFunct/,/)/ {p}'
双范围边界是:
/^[ \t]*[a-zA-Z0-9_\: ]*SomeObj.someFunct/
和
/)/
所以基本上它是在寻找开始位,然后是结束括号。
失败案例
但是如果在 )
之间有东西,这偶尔会失败。一个简单的例子可能是:
someVar: SomeObj.someFunct
(thisTimeImCallingTheFunction(), "name2",
SomeConst)
如果 SomeObj.someFunct 在下一行,它也会失败,即:
someVar:
SomeObj.someFunct("name1", "name2",
SomeConst)
乘法有界范围?
我的想法是,我想要一个 "multi-range",或者等价于:
/^[ \t]*[a-zA-Z0-9_\: ]*/
和
/SomeObj.someFunct/
和
/(/
|和(可选)
|
|一些任意数量的中介 (
和 )
)
和
/)/
...因此范围必须至少检查 4 个边界,最后两个检查可选的中间值以防止内部 (
/ )
对。
我得到了什么
不幸的是,即使考虑到可选的内部匹配,这个天真的版本也没有....
cat $file | sed -ne '/^[ \t]*[a-zA-Z0-9_\: ]*/,/SomeObj.someFunct/,/(/,/)/ {p}'
无效。
似乎模式 /check1/,/check2/,/check3/,/check4/
无效,必须采用一些更复杂的策略。
问题总结
- 检查由两个末端模式和内部模式以某种特定顺序定义的连续范围(但不一定在同一行)
- 每遇到一个
(
,在范围)
. 的最终匹配之前跳过一个
)
Note/Disclaimer
我搜索了以前类似的问题,认为有人问过,但只找到了问题 asking about multiple ranges with standard dual bounds,而不是 "multi range" 在由两个以上的边界匹配定义的单个连续范围的意义上.
奖金问题:
一旦有了这样的多界匹配,我该如何多捕获以下模式:
someVar
之前的空格。- 三个参数(包括interiror
(
/)
in the complex case.
您的第一个嵌套函数调用失败案例无法在正确的 "regular" 表达式中处理。一些扩展,如 Perl 的 REs 可以处理查找任意嵌套事物的匹配对,但实际上您此时需要一个实际的解析器。
这可能适合您 (GNU sed):
sed -rn '/^\s*\w+:/!b;:a;N;/\)\s*$/!ba;/^\s*\w+:\s*SomeObj\.someFunct\s*\(/p;//d;D' file
这匹配第一个变量,然后附加更多行,直到 )
后跟可能的白色 space 和行尾。然后检查模式 space 以查看是否满足所有其他匹配项,如果满足则打印模式 space。否则删除第一行并重复该过程。
N.B。如前所述,正则表达式不能在所有情况下都用于匹配括号,这应该留给解析器处理。
sed 用于 s/old/new,仅此而已。如果您要用它做任何其他事情,那么您使用的结构在 1980 年代发明 awk 时就已经过时了。使用 GNU awk 进行多字符 RS 和第三个参数匹配():
$ cat tst.awk
BEGIN { RS="^$" }
match([=10=],/([[:blank:]]*\w*:\s*SomeObj\.someFunct\s*\()(.*)/,a) {
str = a[1]
while ( match(a[2],/([^\)]*\))(.*)/,a) ) {
str = str a[1]
if ( !index(a[1],"(") ) {
break
}
}
print str
}
$ awk -f tst.awk file
someVar: SomeObj.someFunct
(thisTimeImCallingTheFunction(), "name2",
SomeConst)
上面找到一个与您的起始正则表达式匹配的字符串,然后将以 )
结尾的字符串附加到该字符串,直到它到达一个以 )
结尾且不包含 [=13= 的字符串].