Muhammed Talha Akbar
Muhammed Talha Akbar

Reputation: 313

PHP Regex: How to get optional text if present?

Let's take an example of following string:

$string = "length:max(260):min(20)";

In the above string, :max(260):min(20) is optional. I want to get it if it is present otherwise only length should be returned. I have following regex but it doesn't work:

/(.*?)(?::(.*?))?/se

It doesn't return anything in the array when I use preg_match function.

Remember, there can be something else than above string. Maybe like this:

$string = "number:disallow(negative)";

Is there any problem in my regex or PHP won't return anything? Dumping preg_match returns int 1 which means the string matches the regex.

Fully Dumped:

int 1
array (size=2)
  0 => string '' (length=0)
  1 => string '' (length=0)

Upvotes: 0

Views: 410

Answers (2)

pushpraj
pushpraj

Reputation: 13669

I tried to prepare a regex which can probably solve your issue and also add some value to it

this regex will not only match the optional elements but will also capture in key value pair

Regex

/(?<=:|)(?'prop'\w+)(?:\((?'val'.+?)\))?/g

Test string

length:max(260):min(20)
length
number:disallow(negative)

Result

  • MATCH 1
    • prop [0-6] length


  • MATCH 2
    • prop [7-10] max
    • val [11-14] 260


  • MATCH 3
    • prop [16-19] min
    • val [20-22] 20


  • MATCH 4
    • prop [24-30] length


  • MATCH 5
    • prop [31-37] number


  • MATCH 6
    • prop [38-46] disallow
    • val [47-55] negative

try demo here


EDIT

I think I understand what you meant by duplicate array with different key, it was due to named captures eg. prop & val

here is the revision without named capturing

Regex

/(?<=:|)(\w+)(?:\((.+?)\))?/

Sample code

$str = "length:max(260):min(20)";
$str .= "\nlength";
$str .= "\nnumber:disallow(negative)";

preg_match_all("/(?<=:|)(\w+)(?:\((.+?)\))?/",
    $str,
    $matches);

print_r($matches);

Result

Array
(
    [0] => Array
        (
            [0] => length
            [1] => max(260)
            [2] => min(20)
            [3] => length
            [4] => number
            [5] => disallow(negative)
        )

    [1] => Array
        (
            [0] => length
            [1] => max
            [2] => min
            [3] => length
            [4] => number
            [5] => disallow
        )

    [2] => Array
        (
            [0] => 
            [1] => 260
            [2] => 20
            [3] => 
            [4] => 
            [5] => negative
        )
)

try demo here

Upvotes: 1

revo
revo

Reputation: 48711

You're using single character (.) matching in the case of being lazy, at the very beginning. So it stops at the zero position. If you change your preg_match function to preg_match_all you'll see the captured groups.

Another problem is with your Regular Expression. You're killing the engine. Also e modifier is deprecated many many decades before!!! and yet it was used in preg_replace function only.

Don't use s modifier too! That's not needed.

This works at your case:

/([^:]+)(:.*)?/

Online demo

Upvotes: 3

Related Questions