【问题标题】:Bash Regex Capture GroupsBash 正则表达式捕获组
【发布时间】:2017-09-25 02:45:22
【问题描述】:

我有一个这样格式的字符串:

"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"

如果我用 JS、C# 等编写普通的正则表达式,我会这样做

(?:"(.+?)"|'(.+?)'|(\S+))

并迭代匹配组以获取每个字符串,最好不要使用引号。我最终想将每个值添加到数组中,因此在示例中,我最终会在数组中得到 3 个项目,如下所示:

Mike H<michael.haken@email1.com>
michael.haken@email2.com 
Mike H<hakenmt@email1.com>

我不知道如何使用 grepsed 或 bash 正则表达式复制此功能。我已经尝试了一些类似的东西

echo "$email" | grep -oP "\"\K(.+?)(?=\")|'\K(.+?)(?=')|(\S+)"

这样做的问题是,虽然它有点模仿捕获组的功能,但它并不能真正适用于倍数,所以我得到像这样的捕获

"Mike
H<michael.haken@email1.com>"
 michael.haken@email2.com 

如果我删除向前/向后的逻辑,我至少会得到 3 个字符串,但第一个和最后一个仍然用引号引起来。在这种方法中,我将输出通过管道传输到read,这样我就可以将每个字符串单独添加到数组中,但我对其他选项持开放态度。

编辑:

我认为我的输入示例可能令人困惑,这只是一个可能的输入。真正的输入可以是任意数量的任意顺序的双引号、单引号或不带引号(不带空格)的字符串。我提供的 Javascript/C# 正则表达式是我想要实现的真实行为。

【问题讨论】:

  • 请发布所需的输出。
  • 问题已更新为所需的输出。
  • 按照惯例,不要在 Bash 变量中使用大写字母,而是在引号中引用它们。

标签: regex bash grep pcre


【解决方案1】:

你可以使用 Perl:

$ email='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
$ echo "$email" | perl -lane 'while (/"([^"]+)"|(\S+)/g) {print $1 ? $1 : $2}' 
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>

或者在纯 Bash 中,它有点罗嗦:

re='\"([^\"]+)\"[[:space:]]*|([^[:space:]]+)[[:space:]]*'
while [[ $email =~ $re ]]; do
    echo ${BASH_REMATCH[1]}${BASH_REMATCH[2]}
    i=${#BASH_REMATCH}
    email=${email:i}
done 
# same output

【讨论】:

    【解决方案2】:

    您可以使用sed 来实现,

    $ sed -r 's/"(.*)" (.*)"(.*)"/\1\n\2\n\3/g' <<< "$EMAIL"
    Mike H<michael.haken@email1.com>
    michael.haken@email2.com 
    Mike H<hakenmt@email1.com>
    

    【讨论】:

    • 如果我知道输入格式就可以了;我提供的只是代表一个可能的输入,本质上它是一个输入字符串,它是空格分隔的字符串,可能会或可能不会用双引号或单引号包裹以处理带引号的字符串内的空格。不过感谢您的建议。
    【解决方案3】:

    gawk + bash 解决方案(将每个项目添加到数组中):

    email_str='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
    
    readarray -t email_arr < <(awk -v FPAT="[^\"'[:space:]]+[^\"']+[^\"'[:space:]]+" \
                             '{ for(i=1;i<=NF;i++) print $i }' <<<$email_str)
    

    现在,所有项目都在email_arr

    访问第二项:

    echo "${email_arr[1]}"
    michael.haken@email2.com
    

    访问第三项:

    echo "${email_arr[3]}"
    Mike H<hakenmt@email1.com>
    

    【讨论】:

    • 这确实为我实现了我正在寻找的正则表达式行为和数组结果。
    【解决方案4】:

    你的第一个表情很好;请注意引号(当存在\ 时使用单引号)。最后用 sed 修剪 "

    $ echo $mail | grep -Po '".*?"|\S+' | sed -r 's/"$|^"//g'
    Mike H<michael.haken@email1.com>
    michael.haken@email2.com
    Mike H<hakenmt@email1.com>
    

    【讨论】:

    • 这个答案的问题是它从输入字符串中捕获双引号和单引号作为输出的一部分,但在引号用法上注明。
    • @hakenmt,谢谢你的评论:我的错。我添加了一个额外的步骤来满足要求,但解决方案不是很优雅......
    【解决方案5】:

    使用gawk可以设置多行RS

    awk -v RS='"|" ' 'NF' inputfile
    Mike H<michael.haken@email1.com>
    michael.haken@email2.com
    Mike H<hakenmt@email1.com>
    

    【讨论】:

      【解决方案6】:

      像这样修改你的正则表达式:

      grep -oP '("?\s*)\K.*?(?=")' file
      

      输出:

      Mike H<michael.haken@email1.com>
      michael.haken@email2.com
      Mike H<hakenmt@email1.com>
      

      【讨论】:

      • 该模式假定输入始终按该顺序;输入应该代表一个可能的输入模式,它是一个包含空格分隔的字符串的输入字符串,这些字符串可能会或可能不会用单引号或双引号括起来以处理字符串内的空格。
      【解决方案7】:

      使用 GNU awk 和 FPATdefine fields by content

      $ awk '
      BEGIN { FPAT="([^ ]*)|(\"[^\"]*\")" }  # define a field to be space-separated or in quotes
      {
          for(i=1;i<=NF;i++) {               # iterate every field
              gsub(/^\"|\"$/,"",$i)          # remove leading and trailing quotes
              print $i                       # output
          }
      }' file
      Mike H<michael.haken@email1.com>
      michael.haken@email2.com
      Mike H<hakenmt@email1.com>
      

      【讨论】:

      • 这个版本没有考虑单引号字符串,如果我在最后一个引号字符串后面有一个尾随空格(出于某种原因),它会添加一个空白条目。这也不会将它们添加到数组中,但可以轻松更新以执行此操作。我认为@RomanPerekhrest 的版本更接近。
      【解决方案8】:

      我能够做到这一点,但没有我想要的代码那么简洁:

      arr=()
      while read line; do
        line="${line//\"/}"
        arr+=("${line//\'/}")
      done < <(echo $email | grep -oP "\"(.+?)\"|'(.+?)'|(\S+)")
      

      这给了我一个捕获组的数组,并以任何顺序处理输入,用双引号或单引号括起来,如果没有空格,则根本没有。它还提供了不带引号的数组中的元素。欣赏所有的建议。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-24
        • 2018-03-11
        • 1970-01-01
        • 2019-08-06
        • 1970-01-01
        • 2015-07-24
        相关资源
        最近更新 更多