分别在 POSIX awk 和 Gawk 中,我们如何找到字符串中正则表达式的所有匹配项?
gsub
更具体地说,根据以下两个目标之一查找被内置函数替换的所有匹配项:
找到目标字符串中每个匹配的位置和长度,以及
仅查找作为目标字符串的子字符串的匹配项。
实现第一个目标意味着实现第二个目标。
在 POSIX awk 中,
是否有一个内置函数可以实现这两个目标中的任何一个?
内置函数是否
match
只找到最左边和最长的匹配?match
为了实现第一个目标,重复应用通过查找每个匹配项并从目标字符串中删除匹配项及其前面的前缀而创建的目标字符串的后缀是否是正确的方法?是 https://gist.github.com/mllamazing/a40946fcf8211a503bed正确的实施?在嘎嘎中,
array
调用后是否patsplit(string, array, fieldpat, seps)
按照第二个目标的要求存储匹配项?根据 和之间的分隔符字符串,可以从array
和中找到匹配位置的位置吗?seps
seps[i]
array[i]
array[i+1]
谢谢。
答案1
- 在 POSIX awk 中,
是否有一个内置函数可以实现这两个目标中的任何一个?
不。您可以实现相同的效果,但不能使用单个内置函数。
内置函数是否
match
只找到最左边和最长的匹配?
是的。 POSIX awk
(和 GNU awk
)中的正则表达式总是贪婪的(即最长的匹配总是获胜)。
match
为了实现第一个目标,重复应用通过查找每个匹配项并从目标字符串中删除匹配项及其前面的前缀而创建的目标字符串的后缀是否是正确的方法?
是的,但是如果你想要 100% 兼容gsub()
细节就相当棘手了。
是https://gist.github.com/mllamazing/a40946fcf8211a503bed正确的实施?
大多数情况下,如果您删除通用子线。问题在于细节:如果regex
是空字符串,代码将循环。 Classicawk
不允许空正则表达式,但 IIRCnawk
允许。要解决这个问题,你可以这样做:
function FindAllMatches(str, regex, match_arr) {
ftotal = 0;
ini = RSTART;
leng = RLENGTH;
delete match_arr;
while (str != "" && match(str, regex) > 0) {
match_arr[++ftotal] = substr(str, RSTART, RLENGTH)
str = substr(str, RSTART + (RLENGTH ? RLENGTH : 1))
}
RSTART = ini;
RLENGTH = leng;
}
但这并不是 100% 兼容gsub()
,因为
$ echo 123 | awk '{ gsub("", "-") } 1'
-1-2-3-
而上面的函数只找到 3 个匹配项(即,它错过了最后的匹配项)。
你可以试试这个:
function FindAllMatches(str, regex, match_arr) {
ftotal = 0;
ini = RSTART;
leng = RLENGTH;
delete match_arr;
while (match(str, regex) > 0) {
match_arr[++ftotal] = substr(str, RSTART, RLENGTH)
if (str == "") break
str = substr(str, RSTART + (RLENGTH ? RLENGTH : 1))
}
RSTART = ini;
RLENGTH = leng;
}
这解决了上面的问题,但它打破了其他情况: ifstr = "123"
和regex = "[1-9]*"
函数找到两次出现,123
并且末尾有空字符串,而 whilegsub()
只找到一个,123
。
可能还有其他类似的差异,我现在懒得去寻找。
在嘎嘎中,
array
调用后是否patsplit(string, array, fieldpat, seps)
按照第二个目标的要求存储匹配项?
大多数情况下是的。然而,与正则表达式相关的极端情况可能出乎意料地微妙。可能有一些差异,如上所述。
根据 和之间的分隔符字符串,可以从
array
和中找到匹配位置的位置吗?seps
seps[i]
array[i]
array[i+1]
是的。