I have string like this
$str="absdbsasd k=12312 sdasd l=89879 m=ken asddq casdasd"
and the output should be like this
the question is how to process the string on variable $str to get output which is like this
k=12312
l=89879
m=ken asddq casdasd
I have tried to implement parse_str after I replace the space character (' ') into '&', but the output still got the wrong answer
k=12312
l=89879
m=ken
Could anybody help me..
Assuming the logic is that identifiers are word chars ending with a = and values ends when the next identifier comes, but if the value starts with numbers then only the first word of numbers needed for the value, i would go about it like this:
$str="absdbsasd k=12312 sdasd l=89879 m=ken asddq casdasd";
$parts = preg_split('/(\w+=)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
$result = array();
$prev_was_an_identifier = false;
$last_identifier = null;
foreach ($parts as $part) {
if ($prev_was_an_identifier) {
if (preg_match('/^\d+/', $part)) {
$result[$last_identifier] = preg_replace('/^(\d+).*/', '$1', $part);
} else {
$result[$last_identifier] = $part;
}
$prev_was_an_identifier = false;
} elseif (preg_match('/=$/', $part)) {
$prev_was_an_identifier = true;
$last_identifier = mb_substr($part, 0, -1);
}
}
outputs:
array (
'k' => '12312',
'l' => '89879',
'm' => 'ken asddq casdasd',
)
Well, first you need to define the structure of the string something like this:
$str = "$first_value k=$secound_value l=$third_value m=$forth_value";
If the structure is as I have written, then It's pretty impossible to get what you need, since there are no sepperators or any other types of way to determine where one value ends and another value begins.
Look at this example:
$str="absdbsasd k=12312 sdasd l=s l=8987 l=s 9 m=ken asddq casdasd"
There is no way to teel where the real l= starts.
If you would add some seperators like ' ( and make sure they don't appear in the values, the you can get something like this:
$str="'absdbsasd' k='12312 sdasd l=s' l='8987 l=s 9' m='ken asddq casdasd'"
And then you can do a preg_match or preg_split check and get your desired values.
Or, suggested, just make an array in the 1st place.
Related
I've spent my last 4 hours figuring out how to ... I got to ask for your help now.
I'm trying to extract from a text multiple substring match my starting_words_array and ending_words_array.
$str = "Do you see that ? Indeed, I can see that, as well as this." ;
$starting_words_array = array('do','I');
$ending_words_array = array('?',',');
expected output : array ([0] => 'Do you see that ?' [1] => 'I can see that,')
I manage to write a first function that can find the first substring matching one of both arrays items. But i'm not able to find how to loop it in order to get all the substring matching my requirement.
function SearchString($str, $starting_words_array, $ending_words_array ) {
forEach($starting_words_array as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($ending_words_array as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
Do you guys have any idea about how to achieve such thing ?
I use preg_match for my solution. However, the start and end strings must be escaped with preg_quote. Without that, the solution will be wrong.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr[] = $match[0];
}
}
return $resArr;
}
The result is what the questioner expects.
If the expressions can occur more than once, preg_match_all must also be used. The regex must be modify.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*?".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr = array_merge($resArr,$match[0]);
}
}
return $resArr;
}
The resut for the second variant:
array (
0 => "Do you see that ?",
1 => "Indeed,",
2 => "I can see that,",
)
I would definitely use regex and preg_match_all(). I won't give you a full working code example here but I will outline the necessary steps.
First, build a regex from your start-end-pairs like that:
$parts = array_map(
function($start, $end) {
return $start . '.+' . $end;
},
$starting_words_array,
$ending_words_array
);
$regex = '/' . join('|', $parts) . '/i';
The /i part means case insensitive search. Some characters like the ? have a special purpose in regex, so you need to extend above function in order to escape it properly.
You can test your final regex here
Then use preg_match_all() to extract your substrings:
preg_match_all($regex, $str, $matches); // $matches is passed by reference, no need to declare it first
print_r($matches);
The exact structure of your $matches array will be slightly different from what you asked for but you will be able to extract your desired data from it
Benni answer is best way to go - but let just point out the problem in your code if you want to fix those:
strpos is not case sensitive and find also part of words so you need to changes your $starting_words_array = array('do','I'); to $starting_words_array = array('Do','I ');
When finding a substring you use return which exit the function so you want find any other substring. In order to fix that you can define $res = []; at the beginning of the function and replace return substr($str,$pos,... with $res[] = substr($str,$pos,... and at the end return the $res var.
You can see example in 3v4l - in that example you get the output you wanted
I need help finding something in a variable that isn't always the same, and then put it in another variable.
I know that what I'm looking for has 5 slashes, it starts with steam://joingame/730/ and after the last slash there are 17 numbers.
Edit: It doesn't end with a slash, thats why I need to count 17 numbers after the fifth slash
Assuming what you're looking for looks something like this:
steam://joingame/730/11111111111111/
Then you could use explode() as a simple solution:
$gameId = explode('/', 'steam://joingame/730/11111111111111/');
var_dump($gameId[4]);
or you could use a regex as a more complex solution:
preg_match('|joingame/730/([0-9]+)|', 'steam://joingame/730/11111111111111/', $match);
var_dump($match[1]);
This splits the string into an array then return the last element as the game_id. It doesn't matter how many slashes. It will always return the last one.
$str = 'steam://joingame/730';
$arr = explode("/", $str) ;
$game_id = end($arr);
Following on from what DragonSpirit said
I modified there code so the string can look like
steam://joingame/730/11111111111111
or
steam://joingame/730/11111111111111/
$str = 'steam://joingame/730/11111111111111/';
$rstr = strrev( $str ); // reverses the string so it is now like /1111111111...
if($rstr[0] == "/") // checks if now first (was last ) character is a /
{
$nstr = substr($str, 0, -1); // if so it removes the /
}
else
{
$nstr = $str; // else it dont
}
$arr = explode("/", $nstr) ;
$game_id = end($arr);
Thanks for the help, I've found a solution for the problem. I'm going to post an uncommented version of the code on pastebin, becuase I couldn't get the code saple thing working here.
code
I am trying to get the integer on the left and right for an input from the $str variable using REGEX. But I keep getting the commas back along with the integer. I only want integers not the commas. I have also tried replacing the wildcard . with \d but still no resolution.
$str = "1,2,3,4,5,6";
function pagination()
{
global $str;
// Using number 4 as an input from the string
preg_match('/(.{2})(4)(.{2})/', $str, $matches);
echo $matches[0]."\n".$matches[1]."\n".$matches[1]."\n".$matches[1]."\n";
}
pagination();
How about using a CSV parser?
$str = "1,2,3,4,5,6";
$line = str_getcsv($str);
$target = 4;
foreach($line as $key => $value) {
if($value == $target) {
echo $line[($key-1)] . '<--low high-->' . $line[($key+1)];
}
}
Output:
3<--low high-->5
or a regex could be
$str = "1,2,3,4,5,6";
preg_match('/(\d+),4,(\d+)/', $str, $matches);
echo $matches[1]."<--low high->".$matches[2];
Output:
3<--low high->5
The only flaw with these approaches is if the number is the start or end of range. Would that ever be the case?
I believe you're looking for Regex Non Capture Group
Here's what I did:
$regStr = "1,2,3,4,5,6";
$regex = "/(\d)(?:,)(4)(?:,)(\d)/";
preg_match($regex, $regStr, $results);
print_r($results);
Gives me the results:
Array ( [0] => 3,4,5 [1] => 3 [2] => 4 [3] => 5 )
Hope this helps!
Given your function name I am going to assume you need this for pagination.
The following solution might be easier:
$str = "1,2,3,4,5,6,7,8,9,10";
$str_parts = explode(',', $str);
// reset and end return the first and last element of an array respectively
$start = reset($str_parts);
$end = end($str_parts);
This prevents your regex from having to deal with your numbers getting into the double digits.
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];
Let's say you have a string that looks like this:
token1 token2 tok3
And you want to get all of the tokens (specifically the strings between the spaces), AND ALSO their position (offset) and length).
So I would want a result that looks something like this:
array(
array(
'value'=>'token1'
'offset'=>0
'length'=>6
),
array(
'value'=>'token2'
'offset'=>7
'length'=>6
),
array(
'value'=>'tok3'
'offset'=>14
'length'=>4
),
)
I know that this can be done by simply looping through the characters of the string and I can simpy write a function to do this.
I am wondering, does PHP have anything built-in that will do this efficiently or at least help with part of this?
I am looking for suggestions and appreciate any help given. Thanks
You can use preg_match_all with the PREG_OFFSET_CAPTURE flag:
$str = 'token1 token2 tok3';
preg_match_all('/\S+/', $str, $matches, PREG_OFFSET_CAPTURE);
var_dump($matches);
Then you just need to replace the items in $matches[0] like this:
function update($match) {
return array( 'value' => $value[0], 'offset' => $value[1], 'length' => strlen($value[0]));
}
array_map('update', $matches[0]);
var_dump($matches[0]);
There's a simpler way, in most respects. You'll have a more basic result, but with much less work put in.
Assuming you have tokena tokenb tokenc stored in $data
$tokens = explode(' ', $data);
Now you have an array of tokens separated by spaces. They will be in order, so $tokens[0] = tokena, $tokens[1] = tokenb, etc. You can very easily get the length of any given item by doing strlen($tokens[$index]); If you need to know how many tokens you were passed, use $token_count = count($tokens);
Not as sophisticated, but next to no work to get it.
You could use explode(), which will give you an array of tokens from the string, and strlen() to count the number of characters in the string. As far as I know, I don't think there is a PHP function to tell you where an element is in an array.
To get around the last problem, you could use a counter variable that loops through the explod()ed array (foreach() for for()) and gives each sub-array in the new data it's position.
Someone please correct my if I'm wrong.
James
I like the first answer the most - to use PREG_OFFSET_CAPTURE. In case anyone else is interested, I ended up writing something that does this as well, although I am going to accept the first answer.
Thank you everybody for helping!
function get_words($string) {
$string_chars = str_split($string);
$words = array();
$curr_offset = 0;
foreach($reduced_string_chars as $offset=>$char) {
if ($char == ' ') {
if ($length) $words[] = array('offset'=>$curr_offset,'length'=>$length,'value'=>implode($value_array));
$curr_offset = $offset;
$length = 0;
$value_array = array();
}
else {
$length++;
$value_array[] = $char;
}
}
return $words;
}