我正在尝试使用正则表达式来解析命令行开关的键值对。这是我到目前为止所得到的:
(?<=(^-{1,2}| -{1,2}|^/| /))(?<name>[\w]+)[ :"]*(?<value>[\w.?=&+ :/|\\]*)(?=[ "]|$)
似乎正好解析一切......几乎。如果值中有连字符,则会在匹配时出现问题。我如何调整它以适用于下面的所有测试示例?
测试示例(全部有效):
-s -i:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
-o:"C:\temp\db\" -s -r -host:localhost --d theDB
-s -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB -Scripts\" -h:localhost -d:theDB
-s -d http://www.theproject.com -h:localhost -d:theDB
-i:"C:\Users\Fozzie\Workspace\TheProject\TheProject_Stack_1_5\db\DB Scripts\" --h:localhost -d:theDB
-h:localhost -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack_1_5\db\DB Scripts\" -d:theDB
--d theDB -o:"C:\temp\db\" -host=local-host -r
当值部分类似于
时,正则表达式失败"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\"
或"local-host"
由于其中的连字符。它被视为新开关的开始。
PS:我不想使用像getops这样的固定选项库。我有兴趣让正则表达式正确。
感谢。
更新:抱歉缺少详细信息:这是一个.NET正则表达式。
答案 0 :(得分:3)
这个建议的.NET解决方案只是'建议';我不做.NET而且无法在我的任何机器上测试它(是否有针对.NET的正则表达式测试网站?)。我已经采用了Perl解决方案,删除了您不担心的<mark>
和<pad>
部分以及评论,并假设.NET没有将其全部压平为一行t有一个易读性选项,类似于Perl的x
选项。您仍然可以找到与Perl正则表达式的5个部分相对应的5组括号。我假设(?:...)
是一个非捕获组。
(?:-{1,2}|/)(?<name>\w+)(?:[=:]?|\s+)(?<value>[^-\s"][^"]*?|"[^"]*")?(?=\s+[-/]|$)
我还假设.NET提供了一些类似于Perl的g
修饰符的机制,它允许您在上一次传递中停止的第二个(或后续)传递中扫描字符串。或者你可以以某种方式确定比赛结束的位置并从那里恢复扫描。
这和我设法使用Perl正则表达式一样好(在Mac OS X 10.7.5上使用Perl 5.16.0进行测试)。
#!/usr/bin/env perl
use strict;
use warnings;
# Original regex split into 5 sections:
# C1 (?<=(^-{1,2}|\ -{1,2}|^/|\ /))
# C2 (?<name>[\w]+)
# C3 [ :"]*
# C4 (?<value>[\w.?=&+ :/|\\]*)
# C5 (?=[ "]|$)
my $rx = qr%(?<mark> -{1,2}|/ ) (?# Was C1)
(?<name> \w+ ) (?# Was C2)
(?<pad> (?: [=:]?|\s+ )) (?# Was C3)
(?<value> (?: [^-\s"][^"]*? | "[^"]*" ))? (?# Was C4)
(?=\s+[-/]|$) (?# Was C5)
%x;
while (my $line = <DATA>)
{
chomp $line;
print "\nLine: $line\n";
while ($line =~ m/$rx/g)
{
my($mark, $name, $pad, $value) = ($1, $2, $3, $4 // "");
print "Found: mark $mark name <<$name>> pad <<$pad>> value <<$value>>\n";
}
}
__DATA__
-s -i:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
-o:"C:\temp\db\" -s -r -host:localhost --d theDB
-s -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB -Scripts\" -h:localhost -d:theDB
-s -d http://www.theproject.com -h:localhost -d:theDB
-i:"C:\Users\Fozzie\Workspace\TheProject\TheProject_Stack_1_5\db\DB Scripts\" --h:localhost -d:theDB
-h:localhost -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack_1_5\db\DB Scripts\" -d:theDB
--d theDB -o:"C:\temp\db\" -host=local-host -r
-s -i:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
/d theDB /o:"C:\temp\db\" /host=local-host /r
/d theDB /o:"C:\temp\db\" /host=local-host /r /t
-s:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
大部分脚本不是很有趣。外部while循环一次读取一行文件的数据部分(标记__DATA__
之后的材料),打印它以进行验证,然后在行上重复运行正则表达式以查找组件(标记,名称,填充和值),打印出来。大部分数据都是问题中提供的(谢谢!)。与最初提供的数据相比,数据的最后三行是额外的。
所有的兴奋都在正则表达式中。我使用了Perl的/x
修饰符来允许正则表达式中的空格以便于阅读。这意味着除非前面有反斜杠或用方括号括起来(并且此样本中没有明显的空白区域),否则空格不重要。我已经使用(?<name> ...)
符号来识别原始中的碎片,尽管名称可以省略,因为它们未被使用。 (?# Was Cn)
部分是纯粹的评论。
--?
将是另一种更短的写作方式。(?: ...)
是非捕获分组操作符。-s
选项没有值)。它包括:一个以短划线,双引号或空格开头的字符串,后跟非贪婪的非引号字符串;或双引号,一串非引号和另一个双引号。输出结果为:
Line: -s -i:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
Found: mark - name <<s>> pad << >> value <<>>
Found: mark - name <<i>> pad <<:>> value <<C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\>>
Found: mark - name <<h>> pad <<:>> value <<local:host>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: -o:"C:\temp\db\" -s -r -host:localhost --d theDB
Found: mark - name <<o>> pad <<:>> value <<"C:\temp\db\">>
Found: mark - name <<s>> pad <<>> value <<>>
Found: mark - name <<r>> pad <<>> value <<>>
Found: mark - name <<host>> pad <<:>> value <<localhost>>
Found: mark -- name <<d>> pad << >> value <<theDB>>
Line: -s -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB -Scripts\" -h:localhost -d:theDB
Found: mark - name <<s>> pad << >> value <<>>
Found: mark - name <<i>> pad <<:>> value <<"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB -Scripts\">>
Found: mark - name <<h>> pad <<:>> value <<localhost>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: -s -d http://www.theproject.com -h:localhost -d:theDB
Found: mark - name <<s>> pad << >> value <<>>
Found: mark - name <<d>> pad << >> value <<http://www.theproject.com>>
Found: mark - name <<h>> pad <<:>> value <<localhost>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject_Stack_1_5\db\DB Scripts\" --h:localhost -d:theDB
Found: mark - name <<i>> pad <<:>> value <<"C:\Users\Fozzie\Workspace\TheProject\TheProject_Stack_1_5\db\DB Scripts\">>
Found: mark -- name <<h>> pad <<:>> value <<localhost>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: -h:localhost -i:"C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack_1_5\db\DB Scripts\" -d:theDB
Found: mark - name <<h>> pad <<:>> value <<localhost>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: --d theDB -o:"C:\temp\db\" -host=local-host -r
Found: mark -- name <<d>> pad << >> value <<theDB>>
Found: mark - name <<o>> pad <<:>> value <<"C:\temp\db\">>
Found: mark - name <<host>> pad <<=>> value <<local-host>>
Found: mark - name <<r>> pad <<>> value <<>>
Line: -s -i:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
Found: mark - name <<s>> pad <<>> value <<>>
Found: mark - name <<i>> pad <<:>> value <<C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\>>
Found: mark - name <<h>> pad <<:>> value <<local:host>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
Line: /d theDB /o:"C:\temp\db\" /host=local-host /r
Found: mark / name <<d>> pad << >> value <<theDB >>
Found: mark / name <<o>> pad <<:>> value <<"C:\temp\db\">>
Found: mark / name <<host>> pad <<=>> value <<local-host >>
Found: mark / name <<r>> pad <<>> value <<>>
Line: /d theDB /o:"C:\temp\db\" /host=local-host /r /t
Found: mark / name <<d>> pad << >> value <<theDB>>
Found: mark / name <<o>> pad <<:>> value <<"C:\temp\db\">>
Found: mark / name <<host>> pad <<=>> value <<local-host>>
Found: mark / name <<r>> pad <<>> value <<>>
Found: mark / name <<t>> pad <<>> value <<>>
Line: -s:C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\ -h:local:host -d:theDB
Found: mark - name <<s>> pad <<:>> value <<C:\Users\Fozzie\Workspace\TheProject\TheProject-Stack-1_5\db\DB Scripts\>>
Found: mark - name <<h>> pad <<:>> value <<local:host>>
Found: mark - name <<d>> pad <<:>> value <<theDB>>
答案 1 :(得分:0)
编辑:更改了解决方案,现在它可以匹配FILEPATHS,如D:\ huheue \ hello \ my name.pdf
这是我得到的正则表达式,效果非常好。
(--?[a-zA-Z]+)[:\s=]?([A-Z]:(?:\\[\w\s-]+)+\\?(?=\s-)|\"[^\"]*\"|[^-][^\s]*)?
我希望这是你需要的,你会有这样的输出:
MATCH 1
1. [0-2] `-s`
MATCH 2
1. [3-5] `-i`
2. [6-70] `C:\Users\Fozzie\Workspace\TheProject\TheProaject-Stack-1_5\db\DB Scripts`
MATCH 3
1. [80-82] `-h`
2. [83-93] `local:host`
ETC