PHP, regex and multi-level curly brackets - php

I've got a string which consists of few sentences which are in curly brackets that I want to remove. That would be not that hard to do (as I know now.), but the real trouble is it's multilevel and all I want to strip is the top level brackets and leave everything inside intact. It looks something like this:
{Super duper {extra} text.} {Which I'm really {starting to} hate!} {But I {won't give up} so {easy}!} {Especially when someone is {gonna help me}.}
I want to create an array that would consist of those four entries:
Super duper {extra} text.
Which I'm really {starting to} hate!
But I {won't give up} so {easy}!
Especially when someone is {gonna help me}.
I have tried two ways, one was preg_split which didn't do much good:
$key = preg_split('/([!?.]{1,3}\} \{)/',$key, -1, PREG_SPLIT_DELIM_CAPTURE);
$sentences = array();
for ($i=0, $n=count($key)-1; $i<$n; $i+=2) {
$sentences[] = $key[$i].$key[$i+1]."<br><br>";
}
Another one was using preg_match_all which was quite good until I realized I had those brackets multilevel:
$matches = array();
$key = preg_match_all('/\{[^}]+\}/', $key, $matches);
$key = $matches[0];
Thanks in advance! :)

You can use a recursive expression like this:
/{((?:[^{}]++|(?R))*+)}/
The desired results will be in the first capturing group.
Usage, something like:
preg_match_all('/{((?:[^{}]++|(?R))*+)}/', $str, $matches);
$result = $matches[1];

$x="foo {bar {baz}} whee";
$re="/(^[^{]*){(.*)}([^}]*)$/";
print preg_replace($re, "\\1\\2\\3", $x) . "\n";'
returns:
foo bar {baz} whee

Related

Remove All Text 2 Places After Decimal Place PHP

I'm trying to scrape a products price from a page, however unfortunately it's not in a nice clean div so I'm having to clear all the other junk.
Note: I have looked at several examples however they all assume you only have nice organised numbers in your variable, not raw HTML stuffed on the end.
An example of the string my variable may hold:
$2.87 <span>10% Off Sale</span>
I've played about with substr and sttrpos, read the manual and still can't figure it out on my own.
I want to just cut the string two digits after the first decimal place is found... No doubt it's extremely simple when you know how!
What I want to end up with:
$2.87
An example of the mess I've got myself into trying:
$whatIWant = substr($data, strrpos($data, ".") + 2);
Thanks in advance,
Try this solution:
<?php
$string = "$2.87 <span>10% Off Sale</span>";
$matches = array();
preg_match('/(\$\d+\.\d{2})/', $string, $matches);
var_dump($matches);
Output:
array(2) {
[0]=>
string(5) "$2.87"
[1]=>
string(5) "$2.87"
}
For more info (why result is array etc.) you should check PHP manual on preg_match() function: link
The below should grab the matches for you;
$pattern = '/(\$\d+\.\d{2})/';
$string = '$2.87 <span>10% Off Sale</span>';
$matches = array();
preg_match($pattern, $string, $matches);
Outputs:
Array ( [0] => $2.87 [1] => $2.87 )
There is def better way to do this. For a start, assuming the html structure that you have above will always be the same, you could do something like:
$var = "$85.25 <span>10% Off Sale</span>";
$spl = explode("<", $var);
echo $spl[0];

regular expression word preceded by char

I want to grab a specific string only if a certain word is followed by a = sign.
Also, I want to get all the info after that = sign until a / is reached or the string ends.
Let's take into example:
somestring.bla/test=123/ohboy/item/item=capture
I want to get item=capture but not item alone.
I was thinking about using lookaheads but I'm not sure it this is the way to go. I appreciate any help as I'm trying to grasp more and more about regular expressions.
[^/=]*=[^/]*
will give you all the pairs that match your requirements.
So from your example it should return:
test=123
item=capture
Refiddle Demo
If you want to capture item=capture, it is straightforward:
/item=[^\/]*/
If you want to also extract the value,
/item=([^\/]*)/
If you only want to match the value, then you need to use a look-behind.
/(?<=item=)[^\/]*/
EDIT: too many errors due to insomnia. Also, screw PHP and its failure to disregard separators in a character group as separators.
Here is a function I wrote some time ago. I modified it a little, and added the $keys argument so that you can specify valid keys:
function getKeyValue($string, Array $keys = null) {
$keys = (empty($keys) ? '[\w\d]+' : implode('|', $keys));
$pattern = "/(?<=\/|$)(?P<key>{$keys})\s*=\s*(?P<value>.+?)(?=\/|$)/";
preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);
foreach ($matches as & $match) {
foreach ($match as $key => $value) {
if (is_int($key)) {
unset($match[$key]);
}
}
}
return $matches ?: FALSE;
}
Just trow in the string and valid keys:
$string = 'somestring.bla/test=123/ohboy/item/item=capture';
$keys = array('test', 'item');
$keyValuePairs = getKeyValue($string, $keys);
var_dump($keyValuePairs);

A bit lost with preg_match regular expression

I'm a beginner in regular expression so it didn't take long for me to get totally lost :]
What I need to do:
I've got a string of values 'a:b,a2:b2,a3:b3,a4:b4' where I need to search for a specific pair of values (ie: a2:b2) by the second value of the pair given (b2) and get the first value of the pair as an output (a2).
All characters are allowed (except ',' which seperates each pair of values) and any of the second values (b,b2,b3,b4) is unique (cant be present more than once in the string)
Let me show a better example as the previous may not be clear:
This is a string: 2 minutes:2,5 minutes:5,10 minutes:10,15 minutes:15,never:0
Searched pattern is: 5
I thought, the best way was to use function called preg_match with subpattern feature.
So I tried the following:
$str = '2 minutes:2,5 minutes:5,10 minutes:10,15 minutes:15,20 minutes:20,30 minutes:30, never:0';
$re = '/(?P<name>\w+):5$/';
preg_match($re, $str, $matches);
echo $matches['name'];
Wanted output was '5 minutes' but it didn't work.
I would also like to stick with Perl-Compatible reg. expressions as the code above is included in a PHP script.
Can anyone help me out? I'm getting a little bit desperate now, as Ive spent on this most of the day by now ...
Thanks to all of you guys.
$str = '2 minutes:2,51 seconds:51,5 minutes:5,10 minutes:10,15 minutes:51,never:0';
$search = 5;
preg_match("~([^,\:]+?)\:".preg_quote($search)."(?:,|$)~", $str, $m);
echo '<pre>'; print_r($m); echo '</pre>';
Output:
Array
(
[0] => 5 minutes:5
[1] => 5 minutes
)
$re = '/(?:^|,)(?P<name>[^:]*):5(?:,|$)/';
Besides the problem of your expression having to match $ after 5, which would only work if 5 were the last element, you also want to make sure that after 5 either nothing comes or another pair comes; that before the first element of the pair comes either another element or the beginning of the string, and you want to match more than \w in the first element of the pair.
A preg_match call will be shorter for certain, but I think I wouldn't bother with regular expressions, and instead just use string and array manipulations.
$pairstring = '2 minutes:2,5 minutes:5,10 minutes:10,15 minutes:15,20 minutes:20,30 minutes:30, never:0';
function match_pair($searchval, $pairstring) {
$pairs = explode(",", $str);
foreach ($pairs as $pair) {
$each = explode(":", $pair);
if ($each[1] == $searchval) {
echo $each[0];
}
}
}
// Call as:
match_pair(5, $pairstring);
Almost the same as #Michael's. It doesn't search for an element but constructs an array of the string. You say that values are unique so they are used as keys in my array:
$str = '2 minutes:2,5 minutes:5,10 minutes:10,15 minutes:15,20 minutes:20,30 minutes:30, never:0';
$a = array();
foreach(explode(',', $str) as $elem){
list($key, $val) = explode(':', $elem);
$a[$val] = $key;
}
Then accessing an element is very simple:
echo $a[5];

Preg match question

I'm sure someone already asked this question, but after searching for more than 1 hour on google, I decided to ask my question here.
I want to itterate over an array excisting of different strings/texts.
These texts contain strings with both ##valuetoreplace## and #valuetoreplace#
I want to make to preg_matches:
$pattern = '/^#{1}+(\w+)+#{1}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
// do something with the #values#
}
AND
$pattern = '/^#{2}+(\w+)+#{2}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
//do something with the ##value##
}
This works great.
Now my only problem is as follows:
When i have a string like
$valueToMatch = 'proceding text #value#';
My preg_match cant find my value anymore (as i used a ^ and a $).
Question: how can i find the #value# and the ##value##, without having to worry if these words are in the middle of a (multi-line) value?
*In addition:
What i want is to find patterns and replace the #value# with a db value and a ##value## with a array value.
For example:
$thingsToReplace = 'Hello #firstname# #lastname#,
How nice you joined ##namewebsite##.';
should be
'Hello John Doe,
How nice you joined example.com.'
Try this: /##([^#]+)##/ and /#([^#]+)#/, in that order.
Maybe nice to know for other visitors how i did it:
foreach($personalizeThis as $key => $value)
{
//Replace ##values##
$patternIniData = '/#{2}+(\w+)#{2}/';
$return = 'website'; //testdata
$replacedIniData[$key] = preg_replace($patternIniData, $return, $value);
//Replace #values#
$pattern = '/#{1}+(\w+)#{1}/';
$return = 'ASD'; //testdata
$replacedDbData[$key] = preg_replace($pattern, $return, $replacedIniData[$key]);
}
return $replacedDbData;

Searching within an array of strings

Ok, I'm feeling retarded here,
I have a string like so:
$string = 'function module_testing() {';
or it could be like this:
$string = 'function module_testing()';
or it could be like this:
$string = 'function module_testing($params) {';
or this:
$string = 'function module_testing($params, $another = array())';
and many more ways...
And than I have an array of strings like so:
$string_array = array('module_testing', 'another_function', 'and_another_function');
Now, is there some sort of preg_match that I can do to test if any of the $string_array values are found within the $string string at any given position? So in this situation, there would be a match. Or is there a better way to do this?
I can't use in_array since it's not an exact match, and I'd rather not do a foreach loop on it if I can help it, since it's already in a while loop.
Thanks :)
A foreach loop here is the appropriate solution. Not only is it the most readable but you're looping over three values. The fact that happens within a while loop is a non-issue.
foreach ($string_array as $v) {
if (strpos($string, $v) !== false) {
// found
}
}
You can alternatively use a regular expression:
$search = '\Q' . implode('\E|\Q', $string_array) . '\E';
if (preg_match('!$search!`, $string)) {
// found
}
There are two parts to this. Firstly, there is the | syntax:
a|b|c
which means find a, b or c. The second part is:
\Q...\E
which escapes the contents. This means if your search strings contain any regex special characters (eg () then the regex will still work correctly.
Ultimately though I can't see this being faster than the foreach loop.

Categories