【问题标题】:Under bash, how to extract two numbers by parsing a stringbash下,如何通过解析字符串来提取两个数字
【发布时间】:2013-10-24 07:42:02
【问题描述】:

伙计们,

我搜索了很多,但找不到我想要的解决方案。所以我必须在这里发帖。

我需要从一个字符串中提取两个数字,这个字符串可能包含也可能不包含除我要解析的这两个之外的其他数字。

例如,字符串可能看起来像:

newSetupSL5_snolab_Int-300_Exp-10000_3515

snolab_Int-300_Exp-10000_1185

newSetupSL5_snolab_Int-300_Exp-5000_2522

所以,我要提取的是“Int-”和“Exp-”后面的数字,分别对应第一个和第二个字符串中的300和10000,第三个字符串中的300和5000。

此外,我需要使用这两个数字进行进一步分析。也就是说,我希望这两个数字可以分配给两个变量,而不是直接打印出来,用bash脚本,而不是命令行格式。

【问题讨论】:

    标签: string bash numbers extract


    【解决方案1】:

    使用bash正则表达式匹配

    while read line; do
        if [[ $line =~ _Int-([[:digit:]]+)_Exp-([[:digit:]]+) ]]; then
            printf "int=%d; exp=%d\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
        fi
    done <<END
    newSetupSL5_snolab_Int-300_Exp-10000_3515
    snolab_Int-300_Exp-10000_1185
    newSetupSL5_snolab_Int-300_Exp-5000_2522
    END
    
    int=300; exp=10000
    int=300; exp=10000
    int=300; exp=5000
    

    删除 while 循环

    str=newSetupSL5_snolab_Int-300_Exp-10000_3515
    if [[ $line =~ _Int-([[:digit:]]+)_Exp-([[:digit:]]+) ]]; then
        printf "int=%d; exp=%d\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
    fi
    

    【讨论】:

    • 感谢您的 cmets !也许我在我的信息中没有足够清楚地说明。实际上,每次我只需要处理一个字符串,而不是一个文件包含许多字符串。那么,您认为可以将代码从“读取行”更改为另一个可以读取字符串的代码吗?非常感谢!
    【解决方案2】:

    grep 可以通过这个后视表达式实现:

    $ grep -Po '(?<=Int-)\d+|(?<=Exp-)\d+' file
    300
    10000
    300
    10000
    300
    5000
    

    为了看得更清楚,请注意它是如何在Int- 之后获取数字的:

    $ grep -Po '(?<=Int-)\d+' file
    300
    300
    300
    

    然后只需使用| 添加另一个条件。


    更新

    Glenn Jackman's great suggestion 提高输出:

    $ grep -Po '(?<=Int-)\d+|(?<=Exp-)\d+' file | paste - - | while read n1 n2
    > do
    > echo "int=$n1 ext=$n2"
    > done
    int=300 ext=10000
    int=300 ext=10000
    int=300 ext=5000
    

    关于 OP 的评论

    @fedorqui 和 glenn jackman :非常感谢您的代码 - 您的代码 看起来很不错。但是,正如我原来的消息中提到的,我 实际上需要一行代码来处理一个字符串,而不是一个文件。和 此代码行应集成到我的脚本中。你知不知道怎么 用“$string”替换“文件”?非常感谢!

    你可以这样做:

    grep -Po '(?<=Int-)\d+|(?<=Exp-)\d+' <<< "$string"
    

    【讨论】:

    • 并对其进行迭代:grep -oP '(?&lt;=Int-)\d+|(?&lt;=Exp-)\d+' file | paste - - | while read n1 n2; do ...; done
    • 哇,非常感谢。 paste - - 直接进入我的备忘单,非常好!
    • @fedorqui 和 glenn jackman :非常感谢您的代码 - 您的代码看起来非常好。但是,正如我在原始消息中提到的,我实际上需要一行代码来处理一个字符串,而不是一个文件。并且此代码行应集成到我的脚本中。你知道如何用 "$string" 替换 "file" 吗?非常感谢!
    • @user2740039 你可以改为$ grep -Po '...' &lt;&lt;&lt; "$string"
    • @fedorqui 和 glenn jackman :每次只需要解析一个字符串。但是字符串的形状是多种多样的。
    【解决方案3】:

    下,无需外部工具(forks),如sedawk 或其他工具,就可以做到这一点:

    i=0;
    while read string ;do
        ((i++))
        int=${string#*Int-}
        int=(${int//[a-z_-]/ })
        exp=${string#*Exp-}
        exp=(${exp//[a-z_-]/ })
        var=(${string//[a-z_-]/ })
        printf "Line #%2d contain: Int: %6s, Exp: %6s in %2d values: <%s>\n" \
            $i "$int" "$exp" ${#var[@]} "${var[*]}"
      done <<<'
    newSetupSL5_snolab_Int-300_Exp-10000_3515
    
    snolab_Int-300_Exp-10000_1185
    
    newSetupSL5_snolab_Int-300_Exp-5000_2522
    '
    Line # 1 contain: Int:       , Exp:        in  0 values: <>
    Line # 2 contain: Int:    300, Exp:  10000 in  4 values: <5 300 10000 3515>
    Line # 3 contain: Int:       , Exp:        in  0 values: <>
    Line # 4 contain: Int:    300, Exp:  10000 in  3 values: <300 10000 1185>
    Line # 5 contain: Int:       , Exp:        in  0 values: <>
    Line # 6 contain: Int:    300, Exp:   5000 in  4 values: <5 300 5000 2522>
    Line # 7 contain: Int:       , Exp:        in  0 values: <>
    

    或过滤包含 both Exp-Int- 的行:

    i=0
    while read string ;do
        if [ "$string" != "${string#*Int-*Exp-}" ];then
            ((i++))
            int=${string#*Int-}
            int=(${int//[a-z_-]/ })
            exp=${string#*Exp-}
            exp=(${exp//[a-z_-]/ })
            var=(${string//[a-z_-]/ })
            printf "Line #%2d contain: Int: %6s, Exp: %6s in %2d values: <%s>\n" \
                $i "$int" "$exp" ${#var[@]} "${var[*]}"
          fi
      done <<<'
    newSetupSL5_snolab_Int-300_Exp-10000_3515
    
    snolab_Int-300_Exp-10000_1185
    
    newSetupSL5_snolab_Int-300_Exp-5000_2522
    '
    Line # 1 contain: Int:    300, Exp:  10000 in  4 values: <5 300 10000 3515>
    Line # 2 contain: Int:    300, Exp:  10000 in  3 values: <300 10000 1185>
    Line # 3 contain: Int:    300, Exp:   5000 in  4 values: <5 300 5000 2522>
    

    【讨论】:

    • 非常感谢您的代码!虽然我只选择了这四行:“int = ... int = ... exp = ... exp = ...”,但它们很好地满足了我的要求。再次感谢!
    猜你喜欢
    • 2021-12-11
    • 2011-03-03
    • 2020-10-15
    • 2013-02-04
    • 2012-07-07
    • 1970-01-01
    • 2010-10-18
    • 2020-10-04
    相关资源
    最近更新 更多