【问题标题】:awk does not get multiple matches in a line with matchawk 没有在匹配的一行中获得多个匹配项
【发布时间】:2022-11-04 17:16:45
【问题描述】:

AWK 具有 match(s, r [, a]) 函数,根据手册,该函数能够将所有出现的模式记录到数组“a”中:

...如果提供了数组 a,则清除 a,然后用 s 中与 r 中相应的带括号的子表达式匹配的部分填充元素 1 到 n。 a 的第 0 个元素包含 s 与整个正则表达式 r 匹配的部分。下标 a[n, "start"] 和 a[n, "length"] 分别提供每个匹配子串在字符串中的起始索引和长度。

我希望以下行:

echo 123412341234 | awk '{match($0,"1",arr); print arr[0] arr[1] arr[2];)'

打印 111

但实际上“匹配”会忽略除第一个匹配之外的所有其他匹配。

请有人告诉我,用所有出现的“1”填充“arr”的正确语法是什么?

【问题讨论】:

  • (GNU) awk 在数组中存储多个匹配项的能力基于定义多个匹配模式的正则表达式(即括号内的项目);参见GNU awk string functionsmatch() 函数部分;特别要注意讨论的后半部分,其中样本在单个正则表达式中有 2 个带括号的模式:gawk '{ match($0, /(fo+).+(bar*)/, arr),这反过来将填充 arr[] 数组,匹配 f0+bar*
  • 要连续查找多个匹配项,使用match(),您要么必须在正则表达式中考虑它们(例如,正则表达式中的 3x 括号模式以匹配字符串的 3x 副本),要么编写一个执行 @987654330 的循环@ 在行的连续块上

标签: awk


【解决方案1】:

match 只找到第一个匹配项并停在那里。您必须在循环中运行match,否则使用这种方式,我们在任何不是1 的东西上使用拆分输入:

echo '123412341234' | awk -F '[^1]+' '{print $1 $2 $3}'

111

或者在 gnu-awk 中使用split

echo '123412341234' | awk 'split($0, a, /1/, m) {print m[1] m[2] m[3]}'

111

【讨论】:

  • 然后看起来手册具有误导性。有没有办法纠正它?
  • 手册并非完全错误,因为它讨论了比赛的背景。当您的正则表达式只是 /1/ 时,您将得到的就是这些。
  • /1/是什么?有没有办法扩展它?
  • 这是match 函数的第二个参数。您使用了"1",它与/1/ 相同。 awk 中没有 matchAllfindall 等价物
  • 所以很明显match 不是你快速抓取所有匹配项的正确功能。 split 肯定可以做到,即使patsplit 也可以做到。
【解决方案2】:

我将按照以下方式利用 GNU AWK patsplit 函数来完成该任务,让 file.txt 内容成为

123412341234

然后

awk '{patsplit($0,arr,"1");print arr[1] arr[2] arr[3]}' file.txt

给出输出

111

说明:patsplit 是一个函数,它允许您获得与使用 FPAT 变量类似的效果,它确实将第三个参数的所有匹配项放入作为第二个参数提供的数组中(如果不为空则清除它)在作为第一个参数提供的字符串中找到.观察到第一个发现确实在关键1 下,第二个在2 下,第三个在3 下等等(0 下什么都没有)

(在 GNU Awk 5.0.1 中测试)

【讨论】:

    【解决方案3】:

    如果sub 被允许,那么您可以在此处进行替换。尝试关注awk 代码一次。

    awk '{gsub(/[^1]+/,"")} 1'  Input_file
    

    【讨论】:

      猜你喜欢
      • 2014-09-16
      • 2017-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多