matthewdaniel
matthewdaniel

Reputation: 1476

Re-order regular expression matches

Is there a way to get the match patterns to change order? For example if you have a string with letters-digits and using preg_match_all(), and you want the resulting match array to have the digits before the letters. Is there a way to specify this in the regular expression itself?

So "aaa-111" would result in matches with

array(0 => '111', 1 => 'aaa');

Upvotes: 2

Views: 408

Answers (5)

gen_Eric
gen_Eric

Reputation: 227280

The order of groups in a regex is dependent on their positions in the regex and the string. Changing the order would make it very confusing.

What you can do is use "named groups".

/(?P<letters>\w*)-(?P<digits>\d*)/

The array will still be in the same order, but, you can use $matches['digits'] to easily get just the digits.

DEMO: http://ideone.com/3tRJLZ

Upvotes: 3

Willem Mulder
Willem Mulder

Reputation: 13994

Yes you can. You can use lookaheads that don't push the 'cursor' and so you could first match the last part, and then the first part. It works with (?=regex)

This works:

(?=\w+\-(\d+))(\w+)\-\d+

but will also give the full match at index 0. Like ["aaa-111", "111", "aaa"] is that a problem?

Upvotes: 2

Jordan Mack
Jordan Mack

Reputation: 8743

I don't believe there is. Regex isn't designed to sort. You could setup two different regular expressions to check for each pattern though. This code will echo the two string in num/alpha order as you requested:

<?php
header('Content-Type: text/plain');

$string1 = 'aaa-123';
$string2 = '123-aaa';

echo 'String 1: '.$string1."\n";
echo 'String 2: '.$string2."\n";

$pattern1 = '/([\d]+)-([a-z]+)/i';
$pattern2 = '/([a-z]+)-([\d]+)/i';

echo 'Result 1: ';
if(preg_match($pattern1, $string1, $matches))
{
    echo $matches[1].' '.$matches[2]."\n";
}
if(preg_match($pattern2, $string1, $matches))
{
    echo $matches[2].' '.$matches[1]."\n";
}

echo 'Result 2: ';
if(preg_match($pattern1, $string2, $matches))
{
    echo $matches[1].' '.$matches[2]."\n";
}
if(preg_match($pattern2, $string2, $matches))
{
    echo $matches[2].' '.$matches[1]."\n";
}
?>

The resulting output is:

String 1: aaa-123
String 2: 123-aaa
Result 1: 123 aaa
Result 2: 123 aaa

Upvotes: 0

Jonathan Amend
Jonathan Amend

Reputation: 12815

Perhaps named capture groups will help. Example:

preg_match('/(?<alphapart>[a-z]+)-(?<numpart>[0-9]+)/', 'aaa-111', $matches);

$matches:

array('alphapart' => 'asd', 'numpart' => '111')

This way you can refer to the matches by a name instead of whatever order index they were matched in.

Edit: Just for accuracy, I want to note that $matches will actually include the matches by index as well, so the actual $matches will be: array(5) { [0]=> string(7) "aaa-111" ["alphapart"]=> string(3) "aaa" [1]=> string(3) "aaa" ["numpart"]=> string(3) "111" [2]=> string(3) "111" }

Upvotes: 5

Madara&#39;s Ghost
Madara&#39;s Ghost

Reputation: 175017

If you want the digits to be there first, you need to sort the array yourself.

array_sort() will... sort it out for you.

Upvotes: -1

Related Questions