【问题标题】:Messed up regex when trying to make certain parts optional尝试使某些部分可选时弄乱了正则表达式
【发布时间】:2014-05-16 15:17:42
【问题描述】:

我一直在尝试使用正则表达式来解析命令,以度过美好的一天。

我几次接近解决方案,但总是有一点点把事情搞砸了。

我试图保持表达式的通用性,因为我想在不同的命令上使用它,尽管参数的数量是相同的。

我基本上最多有4个捕获组:

  1. Number1(单块,无空格)
  2. Number2(单块,无空格,可选)
  3. 参数1
  4. Param2(可选)

Number1 和 Number2 由“-”分隔(= 可选,没有“-”没有 Number2)
Number1 (+ Number2) 和 Param1 用空格分隔(= 必填)
Param1 & Param2 用空格隔开(= 可选)

所以命令的基本布局是:

[编号1]-[编号2] [参数1] [参数2]

以下是可以预期的示例输入列表:

123456A789C 测试

  • Number1 = 123456A789C
  • Number2 = 未捕获
  • Param1 = 测试
  • Param2 = 未捕获

123456.789C-987654Z321Y 测试

  • Number1 = 123456.789C
  • Number2 = 987654Z321Y
  • Param1 = 测试
  • Param2 = 未捕获

123456.789C 测试1 测试2

  • Number1 = 123456.789C
  • Number2 = 未捕获
  • Param1 = 测试1
  • Param2 = test2

123456.789C-987654Z321Y 测试1 测试2

  • Number1 = 123456.789C
  • Number2 = 987654Z321Y
  • Param1 = 测试1
  • Param2 = test2

我设法为上述示例编写了一个正则表达式,因为它们相当简单。 然而,我突然想到 Param1 和 Param2 可以是句子。 所以我们决定,如果 Param1 或 Param2 包含空格,则应将它们封装在引号(“)之间 然而,我们仍然希望允许输入不带引号的单字数据,因此引号成为可选的。

1-2 "test1" "test2" 也可以输入为 1-2 test1 test2
1-2 "test1 test2" " test2 test3"不能输入为1-2 test1 test2 test3 test4

示例输入:

123456.789C-987654Z321Y "test1 test2" "test3 test4"

  • Number1 = 123456.789C
  • Number2 = 987654Z321Y
  • Param1 = test1 test2 (注意如何不捕获引号)
  • Param2 = test3 test4 (注意如何不捕获引号)

这就是我无法让我的正则表达式正常工作的地方。 一旦我开始将某些部分设为可选,它的行为就不会像我希望的那样。

以下正则表达式是我想出的符合大多数情况的:

(?i)^(?<numbers>(?<number1>[^\s]*?)(?:[-](?<number2>[^\s]*?))?)\s(?<params>("?)(?<param1>[^"]*)\1\s("?)(?<param2>[^"]*)\2)$

但是不接受 1 test, 1-2 test, 1 "test", 1-2 "测试”1“测试测试”1-2“测试测试”

一些正则表达式专家可以在这里帮助我并解释我的表达哪里出错了吗?

这是我用来匹配最完整命令的另一个正则表达式,例如 1-2 "test1 test2" "test3 test4"

(?i)^(?<numbers>(?<number1>.*)-(?<number2>.*))\s(?<params>"(?<param1>[^"]*)"\s"(?<param2>[^"]*)")$

【问题讨论】:

    标签: .net regex


    【解决方案1】:
    (?<N1>[^- ]+)(-(?<N2>[^ ]+))? (?<P1>("[^"]+")|([^ ]+))( (?<P2>("[^"]+")|([^ ]+)))?
    

    【讨论】:

    • 这个表达式直接匹配了我所有的测试用例。该图也很容易解释!
    • 经过一些初步测试后,我不明白为什么当我添加 '^' 和 '$' 以使匹配发生在整个字符串上时,这个表达式将不起作用......另一方面注意,它还匹配参数周围的引号(如果有的话)
    【解决方案2】:

    为了清楚起见,我从示例中删除了所有命名组。

    我想出了这个

    <!-- language: none -->
    ^([a-zA-Z0-9.]+)(-([a-zA-Z0-9.]+))?\s(([a-zA-Z][a-zA-Z0-9]*)|"[a-zA-Z 0-9]+")(\s(([a-zA-Z][a-zA-Z0-9]*)|"[a-zA-Z 0-9]+"))?
    

    (见source

    下面是详细介绍

    • 我们从行首^ 开始(确保您使用的函数可以提供您想要的选项:不区分大小写、全局匹配、多行。我在正则表达式引擎上使用了该选项简化)
    • 然后我们想要捕获一个或两个数字 ([a-zA-Z0-9.]+) 用于强制的第一个数字,(-([a-zA-Z0-9.]+))? 用于可选的第二个数字。
    • 我们添加一个空格\s。请注意,这不能像您一样在 [] 中使用,因为它们会将速记恢复为字面意思的反斜杠或 s。
    • 然后我们要匹配带有或不带有双引号的标识符(([a-zA-Z][a-zA-Z0-9]*)|"[a-zA-Z 0-9]+") 照顾这个。交替的第二部分添加了"
    • 第二个是可选的,但如果存在则以空格开头(\s(([a-zA-Z][a-zA-Z0-9]*)|"[a-zA-Z 0-9]+"))?
    • 我们可以以$结尾

    【讨论】:

    • 您好 M'vy,感谢您的回复,事实证明这很有帮助。在 regexhero 中测试您的表达式后,我注意到它并不匹配所有可能的情况。然而,通过一些小的修改,它就成功了。我不得不把它改成:(?im)^([a-zA-Z0-9.]+)(-([a-zA-Z0-9.]+))?\s([a-zA-Z0-9]*|"[a-zA-Z 0-9]+")(\s([a-zA-Z0-9]*|"[a-zA-Z 0-9]+"))?$自己看:regexhero.net/tester/?id=d6f2f7fb-a5cb-45b6-bf1c-a9b289284366你的解释和表达看起来很明显,我现在觉得很愚蠢-.-
    猜你喜欢
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    相关资源
    最近更新 更多