【问题标题】:backreferencing in awk gensub with conditional branching带有条件分支的 awk gensub 中的反向引用
【发布时间】:2022-01-21 17:01:08
【问题描述】:

我指的是 answer to: GNU awk: accessing captured groups in replacement text 但是? 正则表达式匹配的量词

我想制作if 语句或三元运算符?: 或更优雅的东西,这样如果用\\1 反向引用的正则表达式组返回非空字符串,则一个任意字符串(不排除\\1)被插入,如果它返回空字符串,则插入其他任意字符串。我的示例在捕获组返回非空字符串时有效,但在反向引用为空时不返回预期的分支“B”。如何根据反向引用值进行条件分支?

echo abba | awk '{ print gensub(/a(b*)?a/, "\\1"?"A":"B", "g", $0)}'

【问题讨论】:

  • 这是行不通的,因为"\\1" 的评估将始终为真,非空字符串。
  • edit 你的问题展示了一个最小的可重现示例,其中包含简洁、可测试的样本输入和预期的输出,可以证明你的问题,以便我们为你提供帮助。例如,假设您尝试将XabbaXaaXabaX 转换为XAXBXAX,,请确保在示例输入/输出中包含abbaabbaaabbaabbaabbaaabba 等有趣的案例,以便我们了解您的期望处理的正则表达式的重叠匹配。请参阅 my answer 以了解您可以根据您的要求进行调整的可能示例输入/输出。

标签: if-statement awk conditional-operator backreference


【解决方案1】:

您传递给任何函数的任何参数中的表达式在调用该函数之前进行评估,因此gensub(/a(b*)?a/, "\\1"?"A":"B", "g", $0)str=("\\1"?"A":"B"); gensub(/a(b*)?a/, str, "g", $0) 相同,与gensub(/a(b*)?a/, "A", "g", $0) 相同。

因此,您不能通过单次调用任何函数来完成您显然想做的事情,也不能两次调用gsub(),一次使用ab+a,然后再次使用aa,或类似的调用而不破坏从左到右,最长的顺序,这样的替换函数会将正则表达式与输入进行匹配(如果存在)。

看起来您可能正在尝试执行以下操作,使用 GNU awk for patsplit()

awk '
    n = patsplit($0,f,/ab*a/,s) {
        $0 = s[0]
        for ( i=1; i<=n; i++ ) {
            $0 = $0 (f[i] ~ /ab+a/ ? "A" : "B") s[i]
        }
    }
1'

或使用任何 awk:

awk '
    {
        head = ""
        while ( match($0,/ab*a/) ) {
            str = substr($0,RSTART,RLENGTH)
            head = head substr($0,1,RSTART-1) (str ~ /ab+a/ ? "A" : "B")
            $0 = substr($0,RSTART+RLENGTH)
        }
        $0 = head $0
    }
1'

但没有样本输入/输出,这是一个猜测。 FWIW 给出了这个示例输入文件:

$ cat file
XabbaXaaXabaX
foo
abbaabba
aabbaabba
bar
abbaaabba

上面会输出:

XAXBXAX
foo
AA
BbbBbba
bar
ABbba

【讨论】:

    【解决方案2】:

    您可以在 gensub 中进行赋值,然后使用三元运算符的值,类似这样

    ... | awk '{ v=gensub(/a(b*)?a/, "\\1", "g", $0); print v?"A":"B"}'
    

    【讨论】:

    • 我认为a(b*)?aa(b*)a 相同,但在任何一种情况下都只会打印AB,而不是将记录中与正则表达式匹配的每个字符串替换为@987654326 @ 或 B,同时保留周围的上下文,因为 OP 似乎正在尝试处理 gensub()
    【解决方案3】:

    可能是这样的?:

    $ gawk '{ print gensub(/a(.*)a/, (match($0,/a(b*)?a/)?"A":"B"), "g", $0)}' <<< abba
    A
    
    $ gawk '{ print gensub(/a(.*)a/, (match($0,/a(b*)?a/)?"A":"B"), "g", $0)}' <<< acca
    B
    

    【讨论】:

    • 那个正则表达式太贪心了,考虑像XabbaXaaXabaX这样的输入,即使不是,它也会用匹配第一个的结果替换所有ab*as,而不是单独对待每个.
    • 是的,除了展示我认为 OP 所要求的内容的实现(以及让我在看这部电影时保持清醒......)之外,它没有任何实际用途。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 2020-02-17
    相关资源
    最近更新 更多