【问题标题】:Regex: keep same pattern found multiple times in same line and replace line by appending single pattern in front正则表达式:保持在同一行中多次找到相同的模式,并通过在前面附加单个模式来替换行
【发布时间】:2019-09-01 07:06:59
【问题描述】:

是否可以使用 notepad++(或者可能来自 linux bash shell)从找到的模式创建多行,与找到的模式一样多次,并在新创建的行中附加单个找到的模式?

多模式是val=[0-9]+ 单一模式是id=[a-zA-Z0-9]+

例子:

输入行:

id=af2477,val=333,val=777
id=af3456,val=222,val=444,val=678
id=af3327,val=3234,val=123,val=701

输出线:

id=af2477,val=333
id=af2477,val=777
id=af3456,val=222
id=af3456,val=444
id=af3456,val=678
id=af3327,val=3234
id=af3327,val=123
id=af3327,val=701

我尝试了 2 个子组,但它不起作用。它只会替换第二组一次:

找到什么:(id=[a-zA-Z0-9]+,)(val=[0-9]+,)* 替换:\n\1,\2

更新:TotoWiktor Stribiżew 的两个答案似乎都能胜任。还没有测试它们。我仍然想看看如何使用 Notepad++(即使需要多个步骤)

【问题讨论】:

  • 你是对的。更新的问题。
  • 它看起来更像 Notepad++ 中的 hack,有两个正则表达式步骤解决方案。 awk 看起来是更好的选择。

标签: regex notepad++


【解决方案1】:

由于您还考虑为此使用 Linux 工具,awk 解决方案看起来更可行:

awk 'BEGIN{FS=OFS=","} /^id=[a-zA-Z0-9]+(,val=[0-9]+)*$/{
    for(i=2; i<=NF; i++) {
        print $1,$i
    }; next;
}{print $0}' file > outfile

请参阅online demo

在这里,任何与^id=[a-zA-Z0-9]+(,val=[0-9]+)*$ 匹配的行(即与您需要扩展的行的格式匹配)都将按照您需要的方式与for(i=2; i&lt;=NF; i++) {print $1,$i}; next; 进行拆分。否则,该行将按原样写入 (print $0)。

BEGIN{FS=OFS=","} 部分将输入和输出字段分隔符设置为逗号。

【讨论】:

  • 仅供参考:上面也可以写成1行:awk 'BEGIN{FS=OFS=","} /^id=[a-zA-Z0-9]+(,val=[0-9]+)*$/{for(i=2; i&lt;=NF; i++) { print $1,$i }; next; }{ print $0 }' file &gt; outfile
【解决方案2】:

这个 perl 单行代码完成了这项工作(在 STDOUT 上输出):

perl -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file
id=af2477,val=333
id=af2477,val=777
id=af3456,val=222
id=af3456,val=444
id=af3456,val=678
id=af3327,val=3234
id=af3327,val=123
id=af3327,val=701

说明:

($id,$vals)=/(id=\w+),(.+)$/;       # explode id and values for each line in input file
say "$id,$_" for split/,/,$vals     # print id and each value

您可以将输出重定向到另一个文件:

perl -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file > outputfile

或者就地改变:

perl -i -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file

【讨论】:

    【解决方案3】:

    使用一个正则表达式来做到这一点是可能的,但非常复杂,您将不得不使用(?R) 和条件语句。


    通过多个步骤将非常简单。例如,您可以使用最长行中可能拥有的 val 的最大数量来查找和替换,例如,想象 4 将是 val 的最大数量,那么我们将有四个 (,val=[^\r\n,]*)在我们的初始表达式中:

    ^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
    

    并用四行替换它,

    $1$2\n$1$3\n$1$4\n$1$5
     ---- ---- ---- ----
    

    Demo for Step 1

    对于任何额外的步骤,我们可以简单地删除一个val,并从初始表达式和替换的末尾删除一行。例如,我们的表达式看起来像

    ^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
    

    在第二步中,我们将其替换为:

    $1$2\n$1$3\n$1$4
    ----  ----  ----
    

    Demo for Step 2

    在第三步也是最后一步,我们的表达式有两个 val,

    ^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
    

    我们的替换将有两行:

    $1$2\n$1$3
    ----  ----
    

    Demo for Step 3


    对于问题中的示例,只需要两个步骤,第二个和第三个表达式可能就可以正常工作。

    【讨论】:

      猜你喜欢
      • 2021-07-23
      • 2012-09-22
      • 2018-01-19
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      相关资源
      最近更新 更多