【问题标题】:Match a string that doesn't contain another string in Bash?在 Bash 中匹配一个不包含另一个字符串的字符串?
【发布时间】:2019-05-27 17:11:01
【问题描述】:

我想匹配一个在开头和结尾包含一些文本但中间不包含不同文本的字符串。例如:以一个单词 (\w+) 开头,以另一个单词结尾,但中间不包含NOT

some_YES_text   // ok
other_COOL_string  // also ok
some_NOT_string   // don't want to match this

通常,我可以通过负前瞻来做到这一点:

\w+_(?!NOT)\w+_\w+

但我正在用 Bash 编写一个不支持它的脚本。达到相同效果的最简单方法是什么?

编辑:我之前并不精确 - 我仍然需要使用正则表达式,而不仅仅是纯文本匹配。

【问题讨论】:

  • 注意:PCRE 正则表达式实际上应该是\w+_(?!NOT_)\w+_\w+。好吧,我现在不确定你是否真的需要在_..._ 之前和之后匹配字母、数字和下划线

标签: regex bash


【解决方案1】:

您可以匹配abc_NOT_def abc_anywordhere_def 并捕获其中一个或一部分,然后在匹配时检查该捕获是否不为空。然后,只需实现您需要的逻辑:

s="other_NOT_string"
rx='^([[:alnum:]_]+_(NOT)_[[:alnum:]_]+|[[:alnum:]_]+_[[:alnum:]_]+_[[:alnum:]_]+)$'
if [[ "$s" =~ $rx ]]; then
 if [ -z ${BASH_REMATCH[2]} ]; then 
   echo "MATCH: ${BASH_REMATCH[0]}"
 else
   echo "No match"
 fi;
else
 echo "No match" 
fi;

详情

  • ^ - 字符串开头
  • ( - 第 1 组开始:
    • [[:alnum:]_]+_ - 1+ 个单词字符(POSIX ERE \w 等效)和一个 _
    • (NOT) - 第 2 组:NOT
    • _[[:alnum:]_]+ - _ 和 1+ 个单词字符
    • | - 或
    • [[:alnum:]_]+_[[:alnum:]_]+_[[:alnum:]_]+ - 1+ 个单词字符,_,1+ 个单词字符,_ 和 1+ 个单词字符
  • ) - 第 1 组结束。
  • $ - 字符串结束

使用[ -z ${BASH_REMATCH[2]} ] 条件,我们检查NOT 是否匹配。如果是,则没有有效的匹配,否则,有一个。

【讨论】:

  • 仅供参考:如果您不想在_..._ 之前和之后允许任何_,请从所有[[:alnum:]_]s 中删除_。如果您不想匹配整个字符串,请删除 ^$。这个想法在这些场景中仍然有效:您匹配并捕获交替的一部分,其中第一个更具体,另一个更通用,并在脚本中应用额外的逻辑来检查匹配是否有效你。
  • 第 1 组(用于替代方案)似乎没有必要。是吗? (无论如何,这个想法可能是最好的方法,谢谢。)
  • @NPS 如果您需要匹配与模式匹配的整个字符串,则第 1 组至关重要,否则,锚将仅应用于不同的替代方案。
  • 好点。但是写两次锚点(对于每个替代项)也可以吗?
  • @NPS 假设您有 5、10 或 15 个备选方案,您很容易错过一两个锚点,并且很难快速找到它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 2021-10-18
  • 1970-01-01
相关资源
最近更新 更多