如何在字符串中查找与正则表达式的所有匹配项

Tim*_*Tim 5 awk text-processing regular-expression gawk

分别在 POSIX awk 和 Gawk 中,我们如何在字符串中找到与正则表达式的所有匹配项?

更具体地说,gsub根据以下两个目标之一,找到被内置函数替换的所有匹配项:

  • 找到目标字符串中每个匹配项的位置和长度,以及

  • 仅将匹配项作为目标字符串的子字符串查找。

实现第一个目标意味着实现第二个目标。

  1. 在 POSIX awk 中,

    是否有内置函数可以实现这两个目标中的任何一个?

    match内置函数是否只找到最左边和最长的匹配项?

    为了实现第一个目标,match通过查找每个匹配项并从目标字符串中删除匹配项及其前面的前缀来重复应用到目标字符串的后缀是否是正确的方法?被 https://gist.github.com/mllamazing/a40946fcf8211a503bed正确实施?

  2. 在 Gawk 中,

    没有array 一个电话后,patsplit(string, array, fieldpat, seps) 存储的匹配,而在第二个目标需要?是否可以从arrayand 中找到匹配位置的位置seps,基于它seps[i]array[i] 和之间的分隔符字符串array[i+1]

谢谢。

Sat*_*ura 4

  1. 在 POSIX awk 中,
    是否有一个内置函数可以实现这两个目标中的任何一个?

不。您可以实现相同的效果,但不能使用单个内置函数。

内置函数是否match只找到最左边和最长的匹配?

是的。POSIX awk(和 GNU awk)中的正则表达式总是贪婪的(即最长的匹配总是获胜)。

为了实现第一个目标,重复应用match通过查找每个匹配项并从目标字符串中删除匹配项及其前面的前缀而创建的目标字符串的后缀是否是正确的方法?

是的,但是如果你想要 100% 兼容gsub()细节就相当棘手了。

https://gist.github.com/mllamazing/a40946fcf8211a503bed是正确的实现吗?

大多数情况下,如果删除gsub 行。问题在于细节:如果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;
}
Run Code Online (Sandbox Code Playgroud)

但这并不是 100% 兼容gsub(),因为

$ echo 123 | awk '{ gsub("", "-") } 1'
-1-2-3-
Run Code Online (Sandbox Code Playgroud)

而上面的函数只找到 3 个匹配项(即,它错过了最后的匹配项)。

你可以试试这个:

$ echo 123 | awk '{ gsub("", "-") } 1'
-1-2-3-
Run Code Online (Sandbox Code Playgroud)

这解决了上面的问题,但它打破了其他情况: ifstr = "123"regex = "[1-9]*"函数找到两次出现,123并且末尾有空字符串,而 whilegsub()只找到一个,123

可能还有其他类似的差异,我现在懒得去寻找。

  1. 在嘎嘎中,

    array 调用后是否patsplit(string, array, fieldpat, seps) 按照第二个目标的要求存储匹配项?

大多数情况下是的。然而,与正则表达式相关的极端情况可能出乎意料地微妙。如上所述,可能存在一些差异。

根据 和之间的分隔符字符串,可以从array和中找到匹配位置的位置吗?sepsseps[i]array[i]array[i+1]

是的。