Regular Expressions Insight

Any questions involving matching text strings to patterns - the pattern is called a "regular expression."

Moderator: General Moderators

Post Reply
JeFFb68CAM
Forum Newbie
Posts: 15
Joined: Tue Apr 03, 2007 11:17 pm

Regular Expressions Insight

Post by JeFFb68CAM »

Hey there,

I'm working on an open source chat software, and it's time I rewrite my commands; I've got this idea I'd like to get accomplished but I'm having a hard time getting it done.

I want my commands do look something like this: (any of you that have linux experience should get what I'm trying to accomplish)

/example -custom="Custom User" -time=65 This is an example message

now, a more real world example would be:

/ban -time=15 Bad_User Stop Flooding

As you can see, I am going for the linux cmd line goal, this is easy but I am struggling with trying to get the values inside the quotes. This is the code I have so far.

Code: Select all

$cmd = "-duration=55 -perm=yes -rofl=5 -nice=\"this is a tesT\" JeFFb68CAM test message";

preg_match_all("/-(.*?)=(\w+|\".*\")/", $cmd, $matches);
echo "<pre>";
print_r($matches);
This gives me this:

Code: Select all

Array
(
    [0] => Array
        (
            [0] => -duration=55
            [1] => -perm=yes
            [2] => -rofl=5
            [3] => -nice="this is a tesT"
        )

    [1] => Array
        (
            [0] => duration
            [1] => perm
            [2] => rofl
            [3] => nice
        )

    [2] => Array
        (
            [0] => 55
            [1] => yes
            [2] => 5
            [3] => "this is a tesT"
        )

)
As you can see everything works except for that it leaves the quotes in tact - I need to get read of the quotes, I could str_replace them off, but that's kind of tacky and thought there might be a more simple way with a regex change that I'm missing.

Any help is appreciated, thanks;
Jeff
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Code: Select all

<?php

$p = '#-([^\s=]+)(?:'.'(?:=|\s+)(?:"(.*?(?<!\\\\)(?:\\\\\\\\)*)"|\'(.*?(?<!\\\\)(?:\\\\\\\\)*)\'|(\w+)))?#';

$cmd = '-duration=55 -perm=yes -rofl=5 -nice="this is\\" a \\\\\\"tesT" JeFFb68CAM test message';

preg_match_all($p, $cmd, $matches);

var_export($matches);

?>
outputs

Code: Select all

array (
  0 =>
  array (
    0 => '-duration=55',
    1 => '-perm=yes',
    2 => '-rofl=5',
    3 => '-nice="this is\\" a \\\\\\"tesT"',
  ),
  1 =>
  array (
    0 => 'duration',
    1 => 'perm',
    2 => 'rofl',
    3 => 'nice',
  ),
  2 =>
  array (
    0 => '',
    1 => '',
    2 => '',
    3 => 'this is\\" a \\\\\\"tesT',
  ),
  3 =>
  array (
    0 => '',
    1 => '',
    2 => '',
    3 => '',
  ),
  4 =>
  array (
    0 => '55',
    1 => 'yes',
    2 => '5',
    3 => '',
  ),
)
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

Well, to me this looks a bit overcomplicated. ;)

JeFFb68CAM, lets try this

Code: Select all

$re = '/-(\w+)=(?:(\w+)|"(.*?)")/';
This captures the parameter in [2] or [3], leaving the other group empty, so that you can blindly take both

Code: Select all

$param_value = @$mathes[2] . @$matches[3];
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

The version I posted allows for toggle level parameters (no specifier) and allows the quoted string to have escapes so it captures the entire string correctly.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

Most programming languages have a tool with the name getopt(s), which is dedicated to getting arguments.. And i've seen a couple of php implementations too...
JeFFb68CAM
Forum Newbie
Posts: 15
Joined: Tue Apr 03, 2007 11:17 pm

Post by JeFFb68CAM »

timvw wrote:Most programming languages have a tool with the name getopt(s), which is dedicated to getting arguments.. And i've seen a couple of php implementations too...
Yeah I've seen some of these but they don't support the "quote" feature either, and that's mainly the functionality that I need.

Thanks for the help stereo and frog, I'll give those a try. Feyd unfortunately yours exports results into 3 different arrays which is not exactly what I'm going for, as I want to keep the functionality of this as easy as possible so people can extend on it further.
JeFFb68CAM
Forum Newbie
Posts: 15
Joined: Tue Apr 03, 2007 11:17 pm

Post by JeFFb68CAM »

I wrote my own function to do what I wanted to do, I'm posting it here for anyone else to use as reference or for critique from you guys.

Code: Select all

$cmd = "-create -topic=\"This is the new topic of the room\" -max_members=10 Support Room";

$params  = array(
    'options' => array(
        'max_members' => 50,
        'topic' => '',
        'create' => false,
    ),
    'room_name' => ''
);

function parseArgs($cmd, &$params)
{
    $cmd = explode(" ", preg_replace('/\s\s+/', ' ', trim($cmd)));
    $keys = array_keys($params);
    for($x=0;$x<count($params);$x++) {
        if($keys[$x] == 'options') {
            $options =& $params['options'];
            while($cmd[0]{0} == '-') {
                $command = array_shift($cmd);
                $option = substr($command, 1);
                if(stristr($option, '=')) {
                    $option = explode('=', $option);
                    $param = $option[0];
                    $value = $option[1];
                    if(!isset($options[$param])) {
                        continue;
                    }
                    if(empty($option[1])) {
                        $options[$param] = false;
                        continue;
                    }
                    if($value{0} == '"') {
                        $value = substr($value, 1);
                        while(substr($cmd[0], -1, 1) != '"') {
                            $value .= " " . array_shift($cmd);
                        }
                        $value .= " " . substr(array_shift($cmd), 0, -1);
                    }
                    $options[$param] = is_numeric($value) ? intval($value) : $value;
                } else {
                    if(!isset($options[$option])) {
                        continue;
                    }
                    $options[$option] = true;
                }
            }
        } else {
            if(isset($cmd[0])) {
                $params[$keys[$x]] = isset($keys[$x+1]) ? array_shift($cmd) : implode(" ", $cmd);
            }
        }
    }
    return true;
}

parseArgs($cmd, $params);

echo "<pre>";
print_r($params);

die();
Which outputs:

Code: Select all

Array
(
    [options] => Array
        (
            [max_members] => 10
            [topic] => This is the new topic of the room
            [create] => 1
        )

    [room_name] => Support Room
)
Basically this does exactly what I wanted and works with any combination or order of the commands.

Thanks for your guys' help anyway,
Jeff
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

What you wanted is just not possible for regular expressions to build. You can integrate the arrays after the fact however as the entries in the last three elements are mutually exclusive.
JeFFb68CAM
Forum Newbie
Posts: 15
Joined: Tue Apr 03, 2007 11:17 pm

Post by JeFFb68CAM »

feyd wrote:What you wanted is just not possible for regular expressions to build. You can integrate the arrays after the fact however as the entries in the last three elements are mutually exclusive.
Yeah I figured that after thinking about how they work and how each ( ) is it's own result. That's why I just settled for a function instead.
Post Reply