Rowan Parker
Rowan Parker

Reputation: 63

A PHP Regex Query

I've only just been trying to teach myself how to use regular expressions so sorry if this seems trivial to some.

I'm making a little crib script. It uses a standard deck of playing cards and I'm using CDHS (clubs, diamonds, hearts, spades) for suits and A2..9TJQK (ace, 2...9, 10, jack, queen, king) for the ranks.

I have variable $hand which is an even-length string of cards. For example, S2HA3D would be the 2 of spades, ace of hearts and 3 of diamonds respectively. Note the suit and rank can be either way round.

I'm using:

preg_match_all("/[2-9ATJQK][CDHS]|[CDHS][2-9ATJQK]/i", $hand, $result);

to find all the cards but this returns suits and ranks in the order found.

My question is how can I make the result give the rank first for each card, regardless of the order given. I hope I've worded this clearly.

Upvotes: 6

Views: 168

Answers (4)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89557

A way is to use named captures with the J modifier that allows to use same names.

$pattern = '~(?J)(?<rk>[2-9ATJQK])?(?<su>[CDHS])(?(1)|(?<rk>[2-9ATJQK]))~i';

preg_match_all($pattern, $hand, $matches, PREG_SET_ORDER);

foreach($matches as $match) {
    $result .= $match['rk'] . $match['su'];
}
echo $result;

Or more simple with a preg_replace:

$result = preg_replace('~([2-9ATJQK])?([SCHD])(?(1)|([2-9ATJQK]))~i', '$2$1$3', $hand);

Upvotes: 3

RandomSeed
RandomSeed

Reputation: 29769

I don't think you can do that with preg_match only.

This function is meant to match strings, not manipulate them. You can, however, do a preg_replace in a second pass:

preg_match_all("/[2-9ATJQK][CDHS]|[CDHS][2-9ATJQK]/i", $hand, $rawResult);
$normalisedResult = preg_replace('/([CDHS])([2-9ATJQK])/i', "$2$1", $rawResult[0]);

In case you wonder, $1 and $2 are backreferences to the groups identified by the parenthesis in the first argument of preg_replace().

Upvotes: 3

Lorenzo P
Lorenzo P

Reputation: 1540

I would use a regex to match all the pairs and then have some logic to resque the grade as first. Here is what I mean (untested)

$grades = array(2,3,4,5,6,7,8,9,'A','T','J','Q','K');

preg_match_all('/((C|D|H|S)[2-9ATJQK]{1})|([2-9ATJQK]{1}(C|D|H|S))/i', $subject, $result, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($result[0]); $i++) {

    if (in_array($result[0][$i][0], $grades)) {
        echo ($result[0][$i]);
    }
    else {
        echo (strrev($result[0][$i]));      
    }

}

Upvotes: 0

Desolator
Desolator

Reputation: 22759

Edit: I didn't get your question properly at first. here is what you need to do, you need to make 2 regex calls something like:

/([CDHS])([A2-9TJQK])/i

then:

/([A2-9TJQK])([CDHS])/i

try to make a variable which can hold the 1st group value and the 2nd group value. then to get the correct rank you need to switch them with the second pattern...

correct me if I'm wrong but you can't do this with one regex.

Upvotes: 1

Related Questions