Parsing command arguments in PHP

后端 未结 11 728
萌比男神i
萌比男神i 2020-12-11 01:19

Is there a native \"PHP way\" to parse command arguments from a string? For example, given the following string:

foo \"bar \\\"baz         


        
11条回答
  •  自闭症患者
    2020-12-11 01:47

    Regexes are quite powerful: (?s)(?. So what does this expression mean ?

    • (?s) : set the s modifier to match newlines with a dot .
    • (? : negative lookbehind, check if there is no backslash preceding the next token
    • ("|') : match a single or double quote and put it in group 1
    • (?:[^\\]|\\.)*? : match everything not \, or match \ with the immediately following (escaped) character
    • \1 : match what is matched in the first group
    • | : or
    • \S+ : match anything except whitespace one or more times.

    The idea is to capture a quote and group it to remember if it's a single or a double one. The negative lookbehinds are there to make sure we don't match escaped quotes. \1 is used to match the second pair of quotes. Finally we use an alternation to match anything that's not a whitespace. This solution is handy and is almost applicable for any language/flavor that supports lookbehinds and backreferences. Of course, this solution expects that the quotes are closed. The results are found in group 0.

    Let's implement it in PHP:

    $string = <<

    If you wonder why I used 4 backslashes. Then take a look at my previous answer.

    Output

    Array
    (
        [0] => foo
        [1] => "bar \"baz\""
        [2] => '\'quux\''
        [3] => 'foo"bar'
        [4] => "baz'boz"
        [5] => hello
        [6] => "regex
    
    world\""
        [7] => "escaped escape\\"
    )
    

                                           Online regex demo                                 Online php demo


    Removing the quotes

    Quite simple using named groups and a simple loop:

    preg_match_all('#(?(?:[^\\\\]|\\\\.)*?)\1|(?\S+)#s', $string, $matches, PREG_SET_ORDER);
    
    $results = array();
    foreach($matches as $array){
       if(!empty($array['escaped'])){
          $results[] = $array['escaped'];
       }else{
          $results[] = $array['unescaped'];
       }
    }
    print_r($results);
    

    Online php demo

提交回复
热议问题