【问题标题】:Trying to replace a pattern with another one试图用另一种模式替换一种模式
【发布时间】:2015-01-11 23:54:00
【问题描述】:

这是我在这个网站上的第一个问题。(很高兴我发现了这个社区)

我正在尝试替换文件中的特定模式(多行),看起来像这样:

Bla bla bla bla |SMTH AWESOME INSIDE >>> LOL| bla bla bla | let's do it again >>> AWESOME |

变成这样的格式

Bla bla bla bla ( LOL | SMTH AWESOME INSIDE ) bla bla bla ( AWESOME | let's do it again )

我尝试通过使用逐字解析行的代码以及如果找到“|”来做到这一点字符开始创建一个包含第一个单词的字符串,然后,在找到 >>> 字符后,它开始创建第二个字符串,直到找到“|”最后一个字符,但它不起作用。

之后我也尝试过使用 AWK(但由于我是 linux 新手,所以我也失败了。

awk -F 'BEGIN { FS=OFS="|" } { sub(/.*<<</,"", $2); }1' $1 }'    

然后使用 sed 解析输出(从两个字符串中删除 ) 和 ( 字符。但它不起作用。

感谢您的阅读。

【问题讨论】:

  • 不要使用“模式”这个词,因为它非常模棱两可。您在搜索正则表达式或字符串或其他内容吗?如果您不想要(),请不要将它们添加到第一位。发布几行示例输入(包括您认为难以正确处理的案例)和预期输出。

标签: linux bash awk


【解决方案1】:

看起来这只是每行中的一个简单替换,所以您只需要 sed:

$ sed 's/| *\([^|]*\) >>> \([^|]*\) *|/( \2 | \1 )/g' file
Bla bla bla bla ( LOL | SMTH AWESOME INSIDE ) bla bla bla ( AWESOME  | let's do it again )

您可以在 GNU awk 中使用 gensub() 或其他 awk 中使用 match() 和 substr() 来执行相同的操作。

【讨论】:

    【解决方案2】:

    sed 中使用扩展的正则表达式:

    sed -r 's/\|([^|]+)[[:space:]]*>>>[[:space:]]*([^|]+)\|/( \2 | \1 )/g' File
    

    逻辑:

    我们寻找以| 开头的模式,后跟一系列非| 字符,然后是&gt;&gt;&gt;,再后跟一系列非| 字符。查看使用() 完成的分组。然后我们根据需要替换这些模式。 ( \2 | \1 ) 是替换模式,其中 \1 和 \2 分别是第一组和第二组。

    sed 中使用基本的正则表达式:

    sed 's/|\([^|]*\)[[:space:]]*>>>[[:space:]]*\([^|]*\)|/( \2 | \1 )/g' File
    

    【讨论】:

    • 尝试使用此方法,它适用于文件中除最后一行之外的所有行(如果它是文件中的唯一行,则为第一行)。如何修改它以在所有情况下工作?例如,在这种情况下它不起作用Pastebin
    • 嗨,我看不到你的输入文件内容(只有输出)...你能告诉我它不工作的那一行吗?我会查
    • 它不适用于只包含需要替换的字符串的行,在其他情况下它可以完美地工作。(例如,如果我的最后一行只包含“| SMTH AWESOME INSIDE >>> LOL| bla bla bla |" 它不会转换它。(但如果在此之前还有其他行,它会转换它,不管它们的格式)
    • Pastebin ,适用于第 1,2 行,但不适用于第 3 行。
    • @AlwaysGoingToAsk 您现在正在剥洋葱,因为您没有像我在原始评论中发布的那样粘贴多行示例输入,因此我们正在尝试生成适用于您发布的一行的解决方案并且无法猜测您的输入可能采取的其他形式(如果有的话)。
    【解决方案3】:

    Perl 的正则表达式具有 awk 所没有的“非贪婪”匹配特性:

    perl -pe '
        s/ \|       # the first delimiter
           (.*?)    # capture up to ...
           >>>      # the middle delimiter
           (.*?)    # capture up to ...
           \|       # the last delimiter
        /($2 | $1)/gx
    ' file
    
    Bla bla bla bla ( LOL | SMTH AWESOME INSIDE ) bla bla bla ( AWESOME  |  let's do it again )
    

    【讨论】:

      【解决方案4】:

      让我们试试:

      awk 'NR%2{ printf("%s", $0) } NR%2==0{ printf("( %s %s",$NF,RS); gsub(/>>>.*$/,")"); printf("%s",$0) }' RS='|' file
      Bla bla bla bla ( LOL | SMTH AWESOME INSIDE ) bla bla bla ( AWESOME | let's do it again )
      

      RS| 定义为记录分隔符。因此,当输入记录号 (NR) 不是 2 的模块时(NR%2 返回 1)然后打印该记录本身。如果 NR 是 2 的模块(NR%2==0 表示如果记录是 2 的模块),则打印一个左括号,然后打印最后一个字段并打印记录分隔符 (printf("( %s %s",$NF,RS)),然后替换 &gt;&gt;&gt;.*$带右括号并打印其余记录 (gsub(/&gt;&gt;&gt;.*$/,")"); printf("%s",$0))

      【讨论】:

      • 永远不要使用printf $0,因为如果输入包含 printf 格式字符,例如%s。总是做printf "%s", $0。各个字段也是如此。
      • @EdMorton 啊,我永远不会忘记这一点。已解决,谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-12
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 2016-06-01
      • 1970-01-01
      相关资源
      最近更新 更多