【问题标题】:Matching optional parameters with non-capturing groups in Bash regular expression将可选参数与 Bash 正则表达式中的非捕获组匹配
【发布时间】:2012-02-01 21:09:08
【问题描述】:

我想使用 Bash 中的正则表达式将类似于以下的字符串解析为单独的变量:

Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title";

Category: resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";attributes="occi.core.summary";

“title”之前的第一部分是所有字符串通用的,部分标题和属性是可选的。

我设法提取了所有字符串共有的强制参数,但我遇到了可选参数不一定存在于所有字符串的问题。据我所知,Bash 不支持我将用于此目的的非捕获括号。

这是我迄今为止所取得的成就:

CATEGORY_REGEX='Category:\s*([^;]*);scheme="([^"]*)";class="([^"]*)";'
category_string='Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title";'
[[ $category_string =~ $CATEGORY_REGEX ]]
echo ${BASH_REMATCH[0]}
echo ${BASH_REMATCH[1]}
echo ${BASH_REMATCH[2]}
echo ${BASH_REMATCH[3]}

我想使用的正则表达式(在 Ruby 中对我有用)是:

CATEGORY_REGEX='Category:\s*([^;]*);\s*scheme="([^"]*)";\s*class="([^"]*)";\s*(?:title="([^"]*)";)?\s*(?:rel="([^"]*)";)?\s*(?:location="([^"]*)";)?\s*(?:attributes="([^"]*)";)?\s*(?:actions="([^"]*)";)?'

有没有其他解决方案可以使用命令行工具解析字符串,而不必依赖 perl、python 或 ruby​​?

【问题讨论】:

    标签: regex string bash text-parsing


    【解决方案1】:

    我认为 bash 正则表达式中不存在非捕获组,因此您的选择是使用脚本语言或从所有 (?:...) 组中删除 ?: 并注意您引用的组,例如:

    CATEGORY_REGEX='Category:\s*([^;]*);\s*scheme="([^"]*)";\s*class="([^"]*)";\s*(title="([^"]*)";)?\s*(rel="([^"]*)";)?\s*(location="([^"]*)";)?\s*(attributes="([^"]*)";)?\s*(actions="([^"]*)";)?'
    category_string='Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title";'
    [[ $category_string =~ $CATEGORY_REGEX ]]
    echo "full:       ${BASH_REMATCH[0]}"
    echo "category:   ${BASH_REMATCH[1]}"
    echo "scheme:     ${BASH_REMATCH[2]}"
    echo "class:      ${BASH_REMATCH[3]}"
    echo "title:      ${BASH_REMATCH[5]}"
    echo "rel:        ${BASH_REMATCH[7]}"
    echo "location:   ${BASH_REMATCH[9]}"
    echo "attributes: ${BASH_REMATCH[11]}"
    echo "actions:    ${BASH_REMATCH[13]}"
    

    请注意,从可选参数开始,我们每次都需要跳过一个组,因为从 4 开始的偶数组包含参数名称和值(如果参数存在)。

    【讨论】:

    • 这确实有效。这不是最优雅的解决方案,但只要 bash 中没有非捕获组,每次跳过一个组的解决方法可能是最好的解决方案。有一件事仍然困扰着我:如果任何分号后面有空格,那么正则表达式就会失败,即使它们后面有“\s*”模式来匹配空格。
    • 似乎“\s*”等特殊字符不起作用。用空格替换它确实有效: "\s*" => " *"
    • 尝试使用 [[:space:]]* 代替 \s。
    【解决方案2】:

    您可以在 bash 中使用一点正则表达式来模拟不匹配的组:

                  _2__    _4__   _5__
    [[ "fu@k" =~ ((.+)@|)((.+)/|)(.+) ]];
    echo "${BASH_REMATCH[2]:--} ${BASH_REMATCH[4]:--} ${BASH_REMATCH[5]:--}"
    # Output: fu - k
    

    字符@/ 是我们解析的字符串的一部分。 正则表达式管道| 用于左或右(空)部分匹配。

    出于好奇,${VAR:-<default value>} 是在 $VAR 为空的情况下使用默认值的变量扩展。

    【讨论】:

    • 这对我不起作用。我只是得到三个破折号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 2015-04-13
    相关资源
    最近更新 更多