正则表达式单词可以是可选的,但只有与字符匹配时才可以

时间:2016-09-19 16:37:39

标签: regex bash shell command-line grep

以下模式:来自http://regexr.com/(v[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2})(-[0-9]{1,2})?((-schema)?(-dev)?)((-schema)?(-dev)?)旨在用于grep的shell脚本,并且与以下字符串匹配(工作示例):

  • Hello I am a text and this is my v1.12.33-32 version
  • Hello I am a text and this is my v1.12.33-dev version
  • Hello I am a text and this is my v1.12.33-dev-schema version
  • Hello I am a text and this is my v1.12.33-schema version
  • Hello I am a text and this is my v1.12.33-3-schema version

等等

所以我将单词schemadev设为可选。可以以任意顺序省略或使用它们。我不是这样的:

  • Hello I am a text and this is my v1.12.33-foo versionHello I am a text and this is my v1.12.33-asfs version

匹配。

我希望选项更加受限制。目前,正则表达式仍然匹配......实际匹配的东西。

例如:

Hello I am a text and this is my v1.123.33

会产生空字符串,而这是:

`你好我是一个文本,这是我的v1.12.33-bla“

仍会导致v.1.12.33

这是因为我制作的分组吗?那么至少完全匹配的组将被用于返回的匹配字符串?

4 个答案:

答案 0 :(得分:1)

由于正则表达式是开放式的,因此您需要使用$指定匹配结束的位置,因此您不要让正则表达式引擎静默忽略尾随垃圾。

在可选集中只有两个标签,我只想列举4种可能性:

(v[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2})(-[0-9]{1,2})?(-schema|-dev|-dev-schema|-schema-dev)?$

答案 1 :(得分:1)

问题似乎是潜伏在所有的可选表达 边缘(结束)。

你可以通过几种方式解决这个问题,但是因为你需要,所以没有一种方法可以解决这个问题 更多规则来控制匹配的内容 它不像你可以说不允许-后记,引擎将为 回溯到其中一个范围数字{1,2}以进行匹配。

现在似乎工作的是传递空白端边缘 或匹配 dev / schema 项目。

(v[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2})(-[0-9]{1,2})?(?:(?!\S)|(-(schema|dev)(?:-(schema|dev))?))

扩展

 (                             # (1 start)
      v [0-9]{1,2} 
      \. [0-9]{1,2} 
      \. [0-9]{1,2} 
 )                             # (1 end)
 ( - [0-9]{1,2} )?             # (2)
 (?:
      (?! \S )                      # Whitespace boundary
   |                              # or, 
      (                             # (3 start)
           -
           ( schema | dev )              # (4)
           (?:
                -
                ( schema | dev )              # (5)
           )?
      )                             # (3 end)
 )

编辑

如果要避免两次匹配相同的架构| dev 字,只需添加
在上面的捕获组5之前,对组4的否定断言。

(v[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2})(-[0-9]{1,2})?(?:(?!\S)|(-(schema|dev)(?:-(?!\4)(schema|dev))?))

扩展

 (                             # (1 start)
      v [0-9]{1,2} 
      \. [0-9]{1,2} 
      \. [0-9]{1,2} 
 )                             # (1 end)
 ( - [0-9]{1,2} )?             # (2)
 (?:
      (?! \S )                      # Whitespace boundary
   |                              # or,
      (                             # (3 start)
           -
           ( schema | dev )              # (4)
           (?:
                -
                (?! \4 )                      # Not same word twice
                ( schema | dev )              # (5)
           )?
      )                             # (3 end)
 )

答案 2 :(得分:1)

我的版本:

\b

其中

  • 第一个(?: ... )是一个单词边界(你可能想让它更严格);
  • \s|$表达式为redirect output;
  • schema可以是空格字符,也可以是行尾

其余的只是为了简单而重构。

表达式只允许在{"结束" devorder by

答案 3 :(得分:1)

要仅匹配 版本字符串,禁止使用额外的尾随标记,但允许尾随不匹配的文本,则需要支持前瞻的正则表达式语言。标准grep / egrep正则表达式不支持预测。

您有两种选择:

  1. 因为你似乎依赖于GNU grep,你可以使用Perl正则表达式,例如
  2. v[0-9]{1,2}(\.[0-9]{1,2}){2}(-[0-9]{1,2})?((-schema(-dev)?)?|(-dev(-schema)?)?)?(?!\S)
    

    最后的否定前瞻允许匹配出现在行的末尾,但也要求如果它不结束行,那么匹配后的下一个字符必须是空格(它本身不包括在内)匹配)。

    1. 你可以放弃通过-o完全隔离目标文本,而是允许模式匹配尾随上下文:
    2. v[0-9]{1,2}(\.[0-9]{1,2}){2}(-[0-9]{1,2})?((-schema(-dev)?)?|(-dev(-schema)?)?)?(\s.*)?$
      

      在这种情况下,您可以通过剥离以空格开头的任何尾部来在第二步中隔离目标文本。

      请注意,这些都不会引起之前匹配的文字。您可以像处理尾随部分一样处理该部分。