6

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.

4 Answers 4

3

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().

Sign up to request clarification or add additional context in comments.

Comments

3

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);

Comments

1

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.

2 Comments

Is there maybe some way to use preg_replace to reorder ones that are the wrong way round? I looked at stackoverflow.com/questions/8411407/… and it shows something can be reordered. Just wondered if there was a similar approach.
yes you can but still you will be using 2 regex statements and that defeats the purpose.
0

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]));      
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.