Reputation: 4615
I have a string like that:
$string = "Half Board, 10% Off & 100 Euro Star - Save £535";
The percentage can be anywhere in the string.
This is what I have, but I don't like the fact that it has a preg_replace AND a loop operation, which are heavy. I'd like a ReGex expression that would do it in one operation.
$string = "Half Board, 10% Off & 100 Euro Star - Save £535";
$string_array = explode(" ", $string);
$pattern = '/[^0-9,.]*/'; // non-digits
foreach($string_array as $pc) {
if(stristr($pc, '%')) {
$percent = preg_replace($pattern, '', $pc);
break;
}
}
echo $percent;
exit;
Upvotes: 2
Views: 3881
Reputation: 76413
Update:
From the code you added to your question, I get the impression your percentages might look like 12.3%
or even .50%
. In which case, the regex you're looking for is this:
if (preg_match_all('/(\d+|\d+[.,]\d{1,2})(?=\s*%)/','some .50% and 5% text with 12.5% random percentages and 123 digits',$matches))
{
print_r($matches);
}
Which returns:
Array
(
[0] => Array
(
[0] => .50
[1] => 5
[2] => 12.5
)
[1] => Array
(
[0] => .50
[1] => 5
[2] => 12.5
)
)
the expression explained:
(\d+|\d*[.,]\d{1,2})
: is an OR -> either match digits \d+
, or \d*
zero or more digits, followed by a decimal separator ([.,]
) and 1 or 2 digits (\d{1,2}
)(?=\s*%)
: only if the afore mentioned group is followed by zero or more spaces and a % signUsing a regular expression, with a positive lookahead, you can get exactly what you want:
if (preg_match_all('/\d+(?=%)/', 'Save 20% if you buy 5 iPhone charches (excluding 9% tax)', $matches))
{
print_r($matches[0]);
}
gives you:
array (
0 => '20',
1 => '9'
)
Which is, I believe, what you are looking for
The regex works like this:
\d+
matches at least 1 digit (as many as possible)(?=%)
: provided they are followed by a %
signBecause of the lookahead, the 5
isn't matched in the example I gave, because it's followed by a space, not a %
sign.
If your string might be malformed (have any number of spaces between the digit and the %
sign) a lookahead can deal with that, too. As ridgerunner pointed out to me, only lookbehinds need to be of fixed size, so:
preg_match_all('/\d+(?=\s*%)/', $txt, $matches)
The lookahead works like this
\s*
: matches zero or more whitespace chars%
: and percent signHence, both 123 %
and 123%
fit the pattern, and will match.
A good place to read up on regex's is regular-expressions.info
If "complex" regex's (ie with lookaround assertions) aren't your cup of tea (yet, though I strongly suggest learning to use them), you could resort to splitting the string:
$parts = array_map('trim', explode('%', $string));
$percentages = array();
foreach($parts as $part)
{
if (preg_match('/\d+$/', $part, $match))
{//if is required, because the last element of $parts might not end with a number
$percentages[] = $match[0];
}
}
Here, I simply use the %
as delimiter, to create an array, and trim each string section (to avoid trailing whitespace), and then procede to check each substring, and match any number that is on the end of that substring:
'get 15% discount'
['get 15', 'discount']
/\d+$/, 'get 15' = [15]
But that's just an awful lot of work, using a lookahead is just way easier.
Upvotes: 4
Reputation: 785481
This should work:
$str = "Save 20% on iPhone chargers...";
if (preg_match_all('/\d+(?=%)/', $str, $match))
print_r($match[0]);
Upvotes: 0
Reputation: 11984
$str = "Half Board, 10% Off & 100 Euro Star - Save £535";
preg_match("|\d+|", $str, $arr);
print_r($arr);
Upvotes: 1
Reputation: 28753
Try with split
like
$str_arr = split(' ',$str);
$my_str = split('%',$str_arr[1]);
echo $my_str[0];
Upvotes: 0