Jump to content

regex none or many ?


Destramic
Go to solution Solved by requinix,

Recommended Posts

in my regex pattern i have a lot of none or many operators (?) , which has caused a bit of a problem, as a string containing a forward slash will come back with a result.

(?<=/)(([ahis]?)\w+))?(\(([\w-]+(?:\|[\w-]+)*)\))?(\*)?(?![^\[\]]*\])

is it possible to match with a string containing at lease on for the one or many groups? and not just a forward slash?

$pattern = '#(?<=/)(([ahis]?)\w+))?(\(([\w-]+(?:\|[\w-]+)*)\))?(\*)?(?![^\[\]]*\])#';
    
if (preg_match_all($pattern, '/news/:action(add|delete|edit)/:type', $matches))
{
    print_r($matches);
    // wanted match
}

if (preg_match_all($pattern, '/test[/hello[/bye]]', $matches))
{
     print_r($matches);
     // unwanted match
}

i'm not able to find evidence that such thing exists, but it's worth an ask.

 

the reason i bundled all of my routing patterns into one regex pattern is so that i have one simple method to phase all route variables.

 

giving me a nice array to work with:

Array
(
    [0] => Array
        (
            [0] => /
            [1] => /:action(add|delete|edit)
            [2] => /:type
        )

    [1] => Array
        (
            [0] => 
            [1] => :action
            [2] => :type
        )

    [2] => Array
        (
            [0] => 
            [1] => 
            [2] => 
        )

    [3] => Array
        (
            [0] => 
            [1] => action
            [2] => type
        )

    [4] => Array
        (
            [0] => 
            [1] => (add|delete|edit)
            [2] => 
        )

    [5] => Array
        (
            [0] => 
            [1] => add|delete|edit
            [2] => 
        )

    [6] => Array
        (
            [0] => 
            [1] => 
            [2] => 
        )

)
    private function variables()
    {
        $pattern = self::ROUTE_VARIABLES;
        
        $parameters = $this->match($pattern);

        if ($parameters)
        {
            $count       = count($parameters[0]);
            $route_split = explode('/', $this->_route);
            $uri_split   = explode('/', $this->_uri);
            
            for ($i = 0; $i < $count; $i++)
            {
                $match = $parameters[0][$i];
                $type  = $parameters[2][$i];
                $name  = $parameters[3][$i];
                $key   = $this->array_search($match, $route_split);
                
                if (!isset($uri_split[$key]))
                {
                    return false;
                }
                
                $value = $uri_split[$key];
                
                if (!empty($parameters[5][$i]))
                {
                    $values = explode('|', $parameters[5][$i]);

                    if (!in_array($value, $values))
                    {
                        return false;
                    }
                    else if (empty($name))
                    {
                        $this->_route = $this->replace($match, $value, $this->_route);
                        
                        continue;
                    }
                }
                else if (!empty($parameters[6][$i]))
                {
                    if (empty($parameters[1][$i]))
                    {
                        $this->_route = $this->replace($match, '(.*)', $this->_route);
                        
                        continue;
                    }
                    else
                    {
                        $next_key = $key + 1;
                        
                        if (!isset($route_split[$next_key]))
                        {
                            return false;
                        }
                        
                        $next_value = $route_split[$next_key];
                        $values     = array();
                        
                        for ($j = $key; $j < count($uri_split); $j++)
                        {
                            if ($uri_split[$j] === $next_value)
                            {
                                break;
                            }
                        
                            $values[] = $uri_split[$j];
                        }

                        $value = implode('/', $values);
                    }
                }
                
                if ((!empty($type) && !$this->is_type($value, $type)))
                {
                    return false;
                }
                    
                $replace      = '(?P<' . $name . '>'. $value . '+)';
                $this->_route = $this->replace($match, $replace, $this->_route);
            }
        }
        
        return true;
    }

thank you

Link to comment
Share on other sites

sorry i meaning zero or one time ---> ?

 

this returns my match perfectly

$pattern = '#(?<=/)(([ahis]?)\w+))?(\(([\w-]+(?:\|[\w-]+)*)\))?(\*)?(?![^\[\]]*\])#';
    
if (preg_match_all($pattern, '/news/:action(add|delete|edit)/:type', $matches))
{
    print_r($matches);
}

but becuase of the ? zero or one, this subject (/test[/hello[/bye]]) will return matches because of the /

$pattern = '#(?<=/)(([ahis]?)\w+))?(\(([\w-]+(?:\|[\w-]+)*)\))?(\*)?(?![^\[\]]*\])#';

if (preg_match_all($pattern, '/test[/hello[/bye]]', $matches))
{
     print_r($matches);
}

what i'm asking is there a way of making my pattern look for:

/(with at least one of the zero or one groups)

 

or else don't match

 

i just don't want the regex pattern to match on a /

 

hope i made myself a bit more clearer

 

thank you

Link to comment
Share on other sites

  • Solution

There are too many things that are optional in that regex. Either you need to make some stuff required or you should combine some of them with alternation and make the whole set required.

(first?)(second?)(third?) -> (?:first|second|third)
If neither of those then we might have to rebuild the regex from scratch...
Link to comment
Share on other sites

There are too many things that are optional in that regex. Either you need to make some stuff required or you should combine some of them with alternation and make the whole set required.

(first?)(second?)(third?) -> (?:first|second|third)
If neither of those then we might have to rebuild the regex from scratch...

 

 

that is what i need...i come up with:

#(?<=/)([ahis])?(?:(\w+))?\(([\w-]+(?:\|[\w-]+))*\)|((\w+))?\*)|\w+))(?![^\[\]]*\])#

which is a bit spicy...i don't like how i've had to add 

(\w+))

to every options, also a:var(a) will come with a match althoght it shouldn't

 

i think i'm gonna stop over complicating the pattern and just do each pattern individually

 

thank you for your help again on this matter

Link to comment
Share on other sites

i only gone and nailed it :)

#/([ahis])?(\w+))?(?\(([\w-+]+(?:\|[\w-]+)+)*\))|(\*)|(?<=:\w))(?![^\[\]]*\])#

There are too many things that are optional in that regex. Either you need to make some stuff required or you should combine some of them with alternation and make the whole set required.

(first?)(second?)(third?) -> (?:first|second|third)
If neither of those then we might have to rebuild the regex from scratch...

 

 

thanks you for pointing me into the right direction requinix

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.