【问题标题】:Select comma separated values between parentheses选择括号之间的逗号分隔值
【发布时间】:2020-01-15 04:41:28
【问题描述】:

给出以下简化的示例文本;

not me G(select me, and me)
G(select me) G(also me)

使用regex 表达式我想选择G(...) 之间的所有内容作为单独的结果,即使有例如逗号。基于 SO this 上的不同答案是我的第一次尝试;

G\(([^)]+)\)

非常适合第二行,但不适用于第一行。我的second 尝试基于从逗号分隔列表中选择值的其他一些答案;

G\(([^),]+)

Another attempt 基于此SOanother 基于此SO

基本上,我需要帮助...

预期输出:

select me
and me
select me
also me

【问题讨论】:

  • 它不匹配 - 它匹配 G() 之间的全部内容 - 我想要用逗号分隔的值。抱歉,如果问题中不清楚。
  • 请在您的问题中包含预期的输出,以便我们可以帮助您从该输入中获得它。
  • 我很确定给出示例文本select me 和之后的第一句话很清楚。但公平的评论我可以添加它以使其更加明显。
  • 不,您可能希望所有内容都在一行上,或者输出段在与输入中出现的相同的 3 行上,或者所有内容都在一行上,或者您可能想要独特的输出而不是所有输出或其他内容,您可能希望输出逗号分隔或其他内容。最好/必须显示您的预期输出以消除所有歧义。
  • 啊,是的,确实很公平。我添加了预期的结果格式:) 谢谢

标签: regex linux awk grep


【解决方案1】:

这是gnu awk 中的一种方法。这看起来更冗长,但使用了一个相当简单的正则表达式,它不依赖于gnu grep 的实验性 PCRE 正则表达式选项:

s="G(also me1) not me G(select me, and me) G(select me) G(also me)"
awk '{ 
   while ( match($0, /\<G\(([^)]*)\)(.*)/, a) ) {
      gsub(/ *, */, "\n", a[1])
      print a[1]
      $0 = a[2]
   }
}' <<< "$s"

also me1
select me
and me
select me
also me

根据下面 Ismail 的评论,如果我们想让它符合 POSIX,请使用此 awk 命令(因为在 POSIX/BSD awk 中没有字边界或 \&lt;):

awk '{
   while ( match($0, /(^|[[:blank:]])G\([^)]*\)/) ) {
      m=substr($0, RSTART+2, RLENGTH-3)
      sub(/^\(/, "", m)
      gsub(/ *, */, "\n", m)
      print m
      $0=substr($0, RSTART+RLENGTH)
   }
}' <<< "$s"

【讨论】:

  • 这也是一个 GNU 辅助解决方案,POSIX ERE 不支持 \&lt;
  • 我很清楚这一点,并且由于 OP 使用了标签 linux,因此答案并没有声称任何关于 POSIX ERE 的内容。
  • 我的意思是,这不适用于所有 awk。并非所有 awk 都是 GNU awk
  • 要让它在 POSIX/BSD awk 上工作,它会是:awk '{ while ( match($0, /(^|[^_[:alnum:]])G\([^)]*\)/) ) { m=substr($0, RSTART+2, RLENGTH-3); sub(/^\(/, "", m); gsub(/ *, */, "\n", m); print m; $0=substr($0, RSTART+RLENGTH) } }' &lt;&lt;&lt; "$s"
  • 感谢@EdMorton。这非常方便,肯定缩短了gnu-awk 解决方案。我一直忘记gnu-awkmatch 的第三个参数,非常感谢!
【解决方案2】:

使用 GNU grep,您可以使用

(?:\G(?!^),\s*|\bG\()\K[^(),]+(?=[^()]*\))

请参阅regex demo

详情

  • (?:\G(?!^),\s*|\bG\() - 上一场比赛的结束和一个 , 后跟 0+ 个空格字符,或者 G( 前面没有字母、数字或 _ 之前
  • \K - 省略目前匹配的文本
  • [^(),]+ - 除了(), 之外的 1+ 个字符
  • (?=[^()]*\)) - 除了 () 之外,必须有 0+ 个字符,然后在当前位置的右侧紧邻 )

online demo:

rx='(?:\G(?!^),\s*|\bG\()\K[^(),]+(?=[^()]*\))'
example="not me G(select me, and me) G(select me) G(also me)"
grep -oP "$rx" <<< "$example"
# Also works with pcregrep: 
# pcregrep -o  "$rx" <<< "$example"

输出:

select me
and me
select me
also me

【讨论】:

  • @tstev 恐怕我不得不说这对我来说并不复杂。
  • @CinCout 如果没有\K,则无法编写此内容 - 除非您添加更多管道命令来对结果进行后处理。
  • @tstev 是的,regex101.com 是简化编写 PCRE、JS、Python 和 Go 正则表达式的工具。您只需要知道如何稍后在目标环境中使用它们,或移植到您选择的环境。
  • @CinCout 在使用特定标志编译时,某些正则表达式实现是可能的,例如 .NET、PyPi 正则表达式模块或 C++ Boost(但无论如何使用它并不是一个好主意)。甚至 Onigmo 也实现了此功能,但他们决定禁用此功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
  • 2023-03-21
  • 2019-08-23
  • 2020-12-16
相关资源
最近更新 更多