用于捕获命令标志和值的正则表达式

时间:2016-03-12 20:31:35

标签: regex

我正在尝试使用正则表达式来捕获命令标志和值。例如,给定字符串:

helloworld --name=stretch --message="Hi there everyone"

它应该捕获namestretch,然后messageHi there everyone

所以我几乎得到了我需要的东西:

\--([a-zA-Z]+)=[\"\']*([^\"\s\'\\]*(?:\\.[^\\\'\"]*)*)\g

但是我对这个空间有问题...如果我把它拿出来,它只适用于引用的值,并且在它中它只适用于不带引号的字符串Lol ......

这是regex101: https://regex101.com/r/eE1zP6/2

4 个答案:

答案 0 :(得分:3)

如果它合适,您可以捕获不同组中的引用和不引用的消息:

--(\w+)=(?:[\"\']([^\"\'\\]*(?:\\.[^\\\'\"]*)*)[\"\']|(\w+))

然后在您的代码中,您可以检查它是引用的(第2组)还是不引用的(第3组)。

答案 1 :(得分:2)

不要使用引号,而是采用更优越的方法:使用条件正则表达式。
基本形式如下:

(?(1)foo|bar)
# Meaning: if group1 is set, use foo, otherwise bar as subpattern

根据您的要求,这归结为:

--(?P<key>\w+)=(")?(?P<value>(?(2)[^"]+|[^\s]+))

PHP代码和解释中,这看起来更漂亮:

<?php
$string = 'helloworld --name=stretch --message="Hi there everyone"';
$regex = '~
            --(?P<key>\w+)=         # look for two dashes, capture every word character into the group "key"
            (")?                    # look for double quotes and make the group (2) optional
            (?P<value>              # save the following to the group "value"
                (?(2)[^"]+|[^\s]+)  # if (2) is set, capture everything BUT a double quote
                                    # else capture everything but a space (not allowed without quotes)
            )
            ~x';                    # verbose modifier
preg_match_all($regex, $string, $matches, PREG_SET_ORDER);
foreach ($matches as $match)
    echo "Key: {$match['key']}, Value: {$match['value']}\n";
/* output:
Key: name, Value: stretch
Key: message, Value: Hi there everyone
*/    
?>

ideone.com 上查看此演示。

您甚至可以更进一步,允许单引号作为分隔符,并在您的值中包含转义引号,如下所示:

--(?P<key>\w+)= 
(['"])?                   # allow single or double quotes
(?P<value>       
    (?(2).+?(?<!\\)(?=\2) # if (2) is set, match everything lazily afterwards
                          # and make sure that what follows is the formerly captured quote
                          # make also sure that what precedes, is not a backslash (thus allowing escaped quotes)
    |[^\s]+)
)

看到这个 demo on regex101.com (被@SebastianProske劫持,对不起伙伴:)。

答案 2 :(得分:1)

我的方法如下:

--([a-zA-Z]+)=([^"'\s]+|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')

开始很简单:--([a-zA-Z]+)=匹配双-后跟字母和=,捕获组中的字母。 然后我们有3个替代方案,没有引号,[^"'\s]+匹配所有不是引号或空格的内容(如果允许在值内,则可以删除引号。"(?:[^"\\]|\\.)*"正在寻找双引号后跟任何数量的非双引号或\后跟任何内容,直到\.未使用双引号。'(?:[^'\\]|\\.)*'对单引号执行相同的操作。 (在我看来是正确的)混合引号,如我的例子的最后一行所示。

https://regex101.com/r/gE1hG6/2

答案 3 :(得分:0)

如果不使用IF条件匹配,您可以尝试:

--(\w+)=(?:('|")(.*?)(?<!\\)\2|(\S+))

DEMO HERE