【问题标题】:Extract substring using regexp in plain bash在普通bash中使用正则表达式提取子字符串
【发布时间】:2012-11-02 14:52:58
【问题描述】:

我正在尝试使用 bash 从字符串中提取时间,但我很难弄清楚。

我的字符串是这样的:

US/Central - 10:26 PM (CST)

我想提取10:26 部分。

任何人都知道只使用 bash 来执行此操作的方法 - 不使用 sed、awk 等?

就像,在 PHP 中我会使用 - 不是最好的方法,但它可以工作 - 类似:

preg_match( ""(\d{2}\:\d{2}) PM \(CST\)"", "US/Central - 10:26 PM (CST)", $matches );

感谢您的帮助,即使答案使用 sed 或 awk

【问题讨论】:

    标签: regex bash


    【解决方案1】:

    使用纯

    $ cat file.txt
    US/Central - 10:26 PM (CST)
    $ while read a b time x; do [[ $b == - ]] && echo $time; done < file.txt
    

    另一种使用 bash 正则表达式的解决方案:

    $ [[ "US/Central - 10:26 PM (CST)" =~ -[[:space:]]*([0-9]{2}:[0-9]{2}) ]] &&
        echo ${BASH_REMATCH[1]}
    

    使用grep 和环视高级正则表达式的另一种解决方案:

    $ echo "US/Central - 10:26 PM (CST)" | grep -oP "\-\s+\K\d{2}:\d{2}"
    

    另一种使用 sed 的解决方案:

    $ echo "US/Central - 10:26 PM (CST)" |
        sed 's/.*\- *\([0-9]\{2\}:[0-9]\{2\}\).*/\1/'
    

    使用 perl 的另一种解决方案:

    $ echo "US/Central - 10:26 PM (CST)" |
        perl -lne 'print $& if /\-\s+\K\d{2}:\d{2}/'
    

    最后一个使用 awk :

    $ echo "US/Central - 10:26 PM (CST)" |
        awk '{for (i=0; i<=NF; i++){if ($i == "-"){print $(i+1);exit}}}'
    

    【讨论】:

    • 酷!我有没有机会在模式中也使用连字符“-”?因为该 grep 返回一些匹配项,而我只对具有连字符、空格和时间的匹配项感兴趣.....
    • 我可能已经得到了 perl 解决方案,但这是一个很好的加分项。谢谢!
    • 感谢您让我知道 \K “技巧”。 grep 加上 perl 语法真的很强大。
    • 我喜欢sed 版本,但想警告其他人sed 不一定采用+ 修饰符。一种解决方法是使用{1, } 修饰符来匹配一个或多个。
    【解决方案2】:
        echo "US/Central - 10:26 PM (CST)" | sed -n "s/^.*-\s*\(\S*\).*$/\1/p"
    
    -n      suppress printing
    s       substitute
    ^.*     anything at the beginning
    -       up until the dash
    \s*     any space characters (any whitespace character)
    \(      start capture group
    \S*     any non-space characters
    \)      end capture group
    .*$     anything at the end
    \1      substitute 1st capture group for everything on line
    p       print it
    

    【讨论】:

    • 我觉得这让我成为了一个即时的 sed 大师。我可以调整的一个好选择比我不理解的九个要好。
    • 感谢您的详细解释,有助于避免将来出现“我如何正则表达式 XXXX”的帖子。
    • 您能解释一下为什么您先用-n 禁止打印,然后再用/p 请求打印吗?省略-n 标志和省略/p 指令不是一样吗?谢谢。
    • 很好的答案!感谢您的帮助:-)
    • @VictorZamanian from here: "默认情况下,sed 打印每一行。如果它进行替换,则打印新文本而不是旧文本。如果您使用 sed 的可选参数, “sed -n”,默认情况下不会打印任何新行。...当使用“-n”选项时,“p”标志将导致打印修改的行。”
    【解决方案3】:

    Quick 'n dirty、无正则表达式、低鲁棒性的斩波技术

    string="US/Central - 10:26 PM (CST)"
    etime="${string% [AP]M*}"
    etime="${etime#* - }"
    

    【讨论】:

    • 这太恶心了,我很惭愧我自己没有想到。 +1 | read zone dash time apm zone 也可以
    • 非常干净,避免调用外部程序。
    • 嗨,如果它包含对进一步文档的引用或围绕该技术的一些名称的引用,那么这将是有用的 10 倍,以便人们可以进行更多研究。对于感兴趣的,这是 bash 字符串操作,您可以在此处找到更多详细信息:tldp.org/LDP/abs/html/string-manipulation.html
    【解决方案4】:

    如果你的字符串是

    foo="US/Central - 10:26 PM (CST)"
    

    然后

    echo "${foo}" | cut -d ' ' -f3
    

    会做的。

    【讨论】:

    • cut -c14-18 当然只有在字符位置不变的情况下。如果时区是固定的,这不应该发生。
    • 向先生询问正则表达式而不是剪切
    【解决方案5】:

    foo="美国/中部 - 晚上 10:26 (CST)"

    回声 ${foo} |日期 +%H:%M

    【讨论】:

    • 您好 Jimbro,欢迎来到 StackOverflow!不幸的是,这不是问题的解决方案。请注意,OP 希望从字符串中提取日期,您的解决方案返回当前日期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2013-07-06
    • 2016-07-05
    • 2013-06-25
    • 1970-01-01
    相关资源
    最近更新 更多