【问题标题】:Regex pattern for quoted numbers and commas引用数字和逗号的正则表达式模式
【发布时间】:2018-08-22 13:06:28
【问题描述】:

我正在尝试找到正确的正则表达式来搜索文件以查找用逗号分隔的双引号。例如,我正在尝试查找 "27,422,734",然后在文本编辑器中将其替换以将逗号更正为每 4 个数字,因此最终结果将是 "2742,2734"

我尝试了一些我在 SO 上找到的示例,但没有一个可以像

那样帮助我解决这种情况
"[^"]+"

'\d+'

虽然上面确实找到了匹配项,但我不知道如何处理逗号以及如何替换它。

感谢您的帮助!

【问题讨论】:

  • 你在 bash/shell 中吗?你用什么工具来替换文字?
  • 哪种语言?

标签: regex bash unix awk sed


【解决方案1】:

我找到了一个更短的解决方案(适用于 gnu-sed):

colonmv () {
  echo $@ | sed 's/,//g' | sed -r ':a;s/\B[0-9]{4}\>/,&/;ta'
}

但请注意,第一个 sed 命令会吃掉每个逗号,而不仅仅是数字之间,因此请改进它或过滤您的输入。

第二个命令使用 :a 技巧。

读取 4 位数字,后跟一个非数字 (>) 替换为相同的加逗号,当发生替换时,从 ta 跳回到 :a 并重复。

现在,让我们看看野外的colonmv:

colonmv '"A 3-grouped, pretty long number: 5,127,422,734 and an ungrouped one 5678905567789065778"'
"A 3-grouped pretty long number: 51,2742,2734 and an ungrouped one 567,8905,5677,8906,5778"

【讨论】:

  • 感谢您的帮助!我终于明白了:)
【解决方案2】:

可能有更好的方法,但我建议采用以下方法:

输入:

$ cat to_transform.txt
abc "27,422,734" def"27,422,734" def
ltu "123,734" abc "345,678,123,734" vtu
xtz "345,678,123,734" vtu "345,678,123,734"
u "1" a
"123"
iu"abc"a "123,734"

CMD:

$ paste -d' ' <(grep -oP '(?<=")(:?\d+,\d+)+(?=")' to_transform.txt) <(grep -oP '(?<=")(:?\d+,\d+)+(?=")' to_transform.txt | sed -e 's/,//g;:loop s/\([0-9]\{4\}\)\($\|,\)/\2,\1/g; s/,,/,/g; /\([0-9]\{5\}\)/b loop') | awk '{cmd="sed -i 0,/"$1"/s/" $1 "/" $2 "/ to_transform.txt"; system(cmd)}'

输出:

$ cat to_transform.txt
abc "2742,2734" def"2742,2734" def
ltu "12,3734" abc "3456,7812,3734" vtu
xtz "3456,7812,3734" vtu "3456,7812,3734"
u "1" a
"123"
iu"abc"a "12,3734"

代码详情和解释:

  • &lt;(grep -oP '(?&lt;=")(:?\d+,\d+)+(?=")' to_transform.txt) 将从输入文件中提取每个要处理的数字,这里使用的正则表达式使用lookbehind/lookahead 来强制使用引号包围的条件,(:?\d+,\d+)+ 用于提取像27,422,734 这样的数字。
  • sed 命令将从 grep 命令获取输出然后执行以下操作:

SED 详细信息:

s/,//g #remove all , in the number
:loop  #create a label to loop
s/\([0-9]\{4\}\)\($\|,\)/\2,\1/g #add a coma after every chain of 4 characters starting by the end of the string/or from the latest coma added
s/,,/,/g #remove duplicate comas added by the previous step if any
/\([0-9]\{5\}\)/b loop #if there are at least 5 digits present successively in the string loop and continue the processing.

paste操作后的临时输出

27,422,734 2742,2734
27,422,734 2742,2734
123,734 12,3734
345,678,123,734 3456,7812,3734
345,678,123,734 3456,7812,3734
345,678,123,734 3456,7812,3734
123,734 12,3734

最后但同样重要的是,awk 命令将读取此文件并运行一些 sed 命令以将第一列的每个元素替换为第二个命令中的相应值:awk '{cmd="sed -i 0,/"$1"/s/" $1 "/" $2 "/ to_transform.txt"; system(cmd)}'

【讨论】:

    【解决方案3】:

    前提条件:您的输入符合“[0-9,]*”并且是“#,###”格式正确的数字。

    #!/bin/bash
    colonmv () {
         echo $1 | sed -r 's/,([0-9]{3})+/\1/g;' | \
         rev | sed -r 's/[^0-9]?([0-9]{4})/\1,/g;s/,"$/"/;s/.*/"&/' | rev
    }
    
    colonmv '"734"'
    colonmv '"2,734"'
    colonmv '"22,734"'
    colonmv '"422,734"'
    colonmv '"7,422,734"'
    colonmv '"27,422,734"'
    colonmv '"127,422,734"'
    colonmv '"5,127,422,734"'
    

    测试:

    colonmv.sh  
    
    "734""
    "2734"
    "2,2734"
    "42,2734"
    "742,2734"
    "2742,2734"
    "1,2742,2734"
    "51,2742,2734"
    

    【讨论】:

    • @Allan:这很讽刺吗? :) 我不得不承认,我根本不熟悉贪婪的非贪婪前缀。可能是他们很新?迟早,我必须更多地了解它们。叹。 :)
    • 不不不讽刺,看我的回答太长了!就性能而言,我认为你的也不错! (我还必须最后在sed 代码中循环,我多次调用sed 并让awk 处理一个临时文件,所以......
    • @Allan:找到一个更短的。
    • "" 中的"734"" 错字吗?
    • 你看到了!不,试过了,这是命令的神器。我的新解决方案不受此错误的影响。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多