Reputation: 63
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
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
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
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
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