How to explode only on the last occurring delimiter? - php

$split_point = ' - ';
$string = 'this is my - string - and more';
How can I make a split using the second instance of $split_point and not the first one. Can I specify somehow a right to left search?
Basically how do I explode from right to left. I want to pick up only the last instance of " - ".
Result I need:
$item[0]='this is my - string';
$item[1]='and more';
and not:
$item[0]='this is my';
$item[1]='string - and more';

You may use strrev to reverse the string, and then reverse the results back:
$split_point = ' - ';
$string = 'this is my - string - and more';
$result = array_map('strrev', explode($split_point, strrev($string)));
Not sure if this is the best solution though.

How about this:
$parts = explode($split_point, $string);
$last = array_pop($parts);
$item = array(implode($split_point, $parts), $last);
Not going to win any golf awards, but it shows intent and works well, I think.

Here is another way of doing it:
$split_point = ' - ';
$string = 'this is my - string - and more';
$stringpos = strrpos($string, $split_point, -1);
$finalstr = substr($string,0,$stringpos);

If I understand correctly, you want the example case to give you ('this is my - string', 'and more')?
Built-in split/explode seems to be forwards-only - you'll probably have to implement it yourself with strrpos. (right-left search)
$idx = strrpos($string, $split_point);
$parts = array(substr($string, 0, $idx), substr($string, $idx+strlen($split_point)))

Why not split on ' - ', but then join the first two array entries that you get back together?

I've stumbled uppon the same, and fixed it like so:
$split_point = ' - ';
$string = 'this is my - string - and more';
$reverse_explode = array_reverse(explode($split_point, $string));

I liked Moff's answer, but I improved it by limiting the number of elements to 2 and re-reversing the array:
$split_point = ' - ';
$string = 'this is my - string - and more';
$result = array_reverse(array_map('strrev', explode($split_point, strrev($string),2)));
Then $result will be :
Array ( [0] => this is my - string [1] => and more )

this is my - string - and more
Use common explode function to get all strings
Get sizeof array and fetch last item
Pop last item using array_pop function.
Implode remaining string with same delimeter(if u want other delimeter can use).
Code
$arrSpits=explode("", "this is my - string - and more");
$arrSize=count($arrSpits);
echo "Last string".$arrSpits[arrSize-1];//Output: and more
array_pop(arrSpits); //now pop the last element from array
$firstString=implode("-", arrSpits);
echo "First String".firstString; //Output: this is my - string

I am underwhelmed by all of the over-engineered answers which are calling many functions and/or iterating over data multiple times. All of those string and array reversing functions make the technique very hard to comprehend.
Regex is powerfully elegant in this case. This is exactly how I would do it in a professional application:
Code: (Demo)
$string = 'this is my - string - and more';
var_export(preg_split('~.*\K - ~', $string));
Output:
array (
0 => 'this is my - string',
1 => 'and more',
)
By greedily matching characters (.*), then restarting the fullstring match (\K), then matching the last occurring delimiting substring (" - "), you are assured to only separate the final substring from the string.

Assuming you only want the first occurrence of $split_point to be ignored, this should work for you:
# retrieve first $split_point position
$first = strpos($string, $split_point);
# retrieve second $split_point positon
$second = strpos($string, $split_point, $first+strlen($split_point));
# extract from the second $split_point onwards (with $split_point)
$substr = substr($string, $second);
# explode $substr, first element should be empty
$array = explode($split_point, $substr);
# set first element as beginning of string to the second $split_point
$array[0] = substr_replace($string, '', strpos($string, $substr));
This will allow you to split on every occurrence of $split_point after (and including) the second occurrence of $split_point.

Just an idea:
function explode_reversed($delim,$s){
$result = array();
$w = "";
$l = 0;
for ($i = strlen($s)-1; $i>=0; $i-- ):
if ( $s[$i] == "$delim" ):
$l++;
$w = "";
else:
$w = $s[$i].$w;
endif;
$result[$l] = $w;
endfor;
return $result;
}
$arr = explode_reversed(" ","Hello! My name is John.");
print_r($arr);
Result:
Array
(
[0] => John.
[1] => is
[2] => name
[3] => My
[4] => Hello!
)
But this is much slower then explode. A test made:
$start_time = microtime(true);
for ($i=0; $i<1000;$i++)
$arr = explode_reversed(" ","Hello! My name is John.");
$time_elapsed_secs = microtime(true) - $start_time;
echo "time: $time_elapsed_secs s<br>";
Takes 0.0625 - 0.078125s
But
for ($i=0; $i<1000;$i++)
$arr = explode(" ","Hello! My name is John.");
Takes just 0.015625s
The fastest solution seems to be:
array_reverse(explode($your_delimiter, $your_string));
In a loop of 1000 times this is the best time I can get 0.03125s.

Not sure why no one posted a working function with $limit support though here it is for those who know that they'll be using this frequently:
<?php
function explode_right($boundary, $string, $limit)
{
return array_reverse(array_map('strrev', explode(strrev($boundary), strrev($string), $limit)));
}
$string = 'apple1orange1banana1cupuacu1cherimoya1mangosteen1durian';
echo $string.'<br /><pre>'.print_r(explode_right(1, $string, 3),1).'</pre>';
?>

$split_point = ' - ';
$string = 'this is my - string - and more';
$result = end(explode($split_point, $string));
This is working fine

Related

php string manipulation issues

I have the following string...
$string = "True is True (5-7 years)";
what I want is to get - TiT(5-7 years)
I have tried the following code but no luck...
$string = "True is True (5-7 years)";
$explodedString = explode(" ",$string);
for($i = 0; $i < 4; $i++){
$tempString = substr($explodedString[$i], 0, 1);
$finalString .= $tempString;
}
In short, I need the first three words of its initials and the remaining in bracket is as it is like this.... TiT(5-7 years). how?
This a good case for using regular expressions:
$str = 'True is True (5-7 years)';
preg_match_all('~\([^()]*\)|\b\w~', $str, $matches);
echo implode("", $matches[0]); // TiT(5-7 years)
Regex breakdown:
\([^()]*\) Match anything inside parentheses including themselves
| Or
\b\w Match first word character from a word
Your loop is going one element too far. If you want the first letter of the first 3 words, it should be $i < 3.
Then you should use array_slice() and implode() to concatenate the rest of the array.
for ($i = 0; $i < 3; $i++) {
$finalString .= $explodedString[$i][0];
}
$finalString .= implode(' ', array_slice($explodedString, 3));
DEMO
$string = "True is True (5-7 years)";
$new_string = preg_replace('/^([a-z])[a-z]+ ([a-z])[a-z]+ ([a-z])[a-z]+ (\(.+\))$/i', '$1$2$3$4', $string);
First of all.
Create an empty variable. That will be your final result
$result="";
Then youse foreach to loop your explode string.
At every part chech the first character.
If it's not ( add the first char onto the result variable.
else add the whole array element onto the result variable
foreach(explodedString as $t){
If($t[0] !="("){$result.=$t[0];} else{$result.=$t;}
}
At the end of the loop you will get what you wanted
echo $result;

PHP Regex for a specific numeric value inside a comma-delimited integer number string

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.

How do I echo a different statement when different checkboxes are selected with php? [duplicate]

I have searched everywhere but can't find a solution that works for me.
I have the following:
$bedroom_array = array($studio, $one_bed, $two_bed, $three_bed, $four_bed);
For this example lets say:
$studio = '1';
$one_bed = '3';
$two_bed = '3';
I then use the implode function to put a comma in between all the values:
$bedroom_list = implode(", ", array_filter($bedroom_array));
echo $bedroom_list;
This then outputs:
1, 2, 3
What I want to do is find the last comma in the string and replace it with an &, so it would read:
1, 2 & 3
The string will not always be this long, it can be shorter or longer, e.g. 1, 2, 3, 4 and so on. I have looked into using substr but am not sure if this will work for what I need?
Pop off the last element, implode the rest together then stick the last one back on.
$bedroom_array = array('studio', 'one_bed', 'two_bed', 'three_bed', 'four_bed');
$last = array_pop($bedroom_array);
$string = count($bedroom_array) ? implode(", ", $bedroom_array) . " & " . $last : $last;
Convert & to the entity & if necessary.
if you have comma separated list of words you may use:
$keyword = "hello, sadasd, sdfgdsfg,sadfsdafsfd, ssdf, sdgdfg";
$keyword = preg_replace('/,([^,]*)$/', ' & \1', $keyword);
echo $keyword;
it will output:
hello, sadasd, sdfgdsfg,sadfsdafsfd, ssdf & sdgdfg
A one-liner alternative, that will work for any size array ($b = $bedroom_array):
echo count($b) <= 1 ? reset($b) : join(', ', array_slice($b, 0, -1)) . " & " . end($b);
strrpos finds the last occurrance of a specified string.
$str = '1, 2, 3';
$index = strrpos( $str, ',' );
if( $index !== FALSE )
$str[ $index ] = '&';
function fancy_implode($arr){
array_push($arr, implode(' and ', array_splice($arr, -2)));
return implode(', ', $arr);
}
I find this easier to read/understand and use
Does not modify the original array
Does not use regular expressions as those may fail if strings in the array contain commas, there could be a valid reason for that, something like this: array('Shirts (S, M, L)', 'Pants (72 x 37, 72 x 39)');
Delimiters don't have to be of the same length as with some of the other solutions
$bedroom_list = implode(", ", array_filter($bedroom_array));
$vars = $bedroom_list;
$last = strrchr($vars,",");
$last_ = str_replace(",","&",$last);
echo str_replace("$last","$last_",$vars);
<?php
$string = "3, 4, 5";
echo $string = preg_replace('/,( \d)$/', ' &\1', $string);
?>
Here's another way to do the replacement with a regular expression using a positive lookahead which doesn't require a backreference:
$bedroom_list = preg_replace('/,(?=[^,]*$)/',' &', implode(', ', $bedroom_array));

Separate each word into a Array

I have a file with contents like :
Apple 100
banana 200
Cat 300
I want to search for a particular string in the file and get the next word. Eg: I search for cat, I get 300. I have looked up this solution: How to Find Next String After the Needle Using Strpos(), but that didn't help and I didn't get the expected output. I would be glad if you can suggest any method without using regex.
I'm not sure this is the best approach, but with the data you've provided, it'll work.
Get the contents of the file with fopen()
Separate the values into array elements with explode()
Iterate over your array and check each element's index as odd or even. Copy to new array.
Not perfect, but on the right track.
<?php
$filename = 'data.txt'; // Let's assume this is the file you mentioned
$handle = fopen($filename, 'r');
$contents = fread($handle, filesize($filename));
$clean = trim(preg_replace('/\s+/', ' ', $contents));
$flat_elems = explode(' ', $clean);
$ii = count($flat_elems);
for ($i = 0; $i < $ii; $i++) {
if ($i%2<1) $multi[$flat_elems[$i]] = $flat_elems[$i+1];
}
print_r($multi);
This outputs a multidimensional array like this:
Array
(
[Apple] => 100
[banana] => 200
[Cat] => 300
)
Try this, it doesn't use regex, but it will be inefficient if the string you're searching is longer:
function get_next_word($string, $preceding_word)
{
// Turns the string into an array by splitting on spaces
$words_as_array = explode(' ', $string);
// Search the array of words for the word before the word we want to return
if (($position = array_search($preceding_word, $words_as_array)) !== FALSE)
return $words_as_array[$position + 1]; // Returns the next word
else
return false; // Could not find word
}
$find = 'Apple';
preg_match_all('/' . $find . '\s(\d+)/', $content, $matches);
print_r($matches);
You might benefit from using named regex subpatterns to capture the information you're looking for.
For example you, finding a number the word that is its former (1 <= value <= 9999)
/*String to search*/
$str = "cat 300";
/*String to find*/
$find = "cat";
/*Search for value*/
preg_match("/^$find+\s*+(?P<value>[0-9]{1,4})$/", $str, $r);
/*Print results*/
print_r($r);
In cases where a match is found the results array will contain the number you're looking for indexed as 'value'.
This approach can be combined with
file_get_contents($file);

Get the current + the next word in a string

this is what I try to get:
My longest text to test When I search for e.g. My I should get My longest
I tried it with this function to get first the complete length of the input and then I search for the ' ' to cut it.
$length = strripos($text, $input) + strlen($input)+2;
$stringpos = strripos($text, ' ', $length);
$newstring = substr($text, 0, strpos($text, ' ', $length));
But this only works first time and then it cuts after the current input, means
My lon is My longest and not My longest text.
How I must change this to get the right result, always getting the next word. Maybe I need a break, but I cannot find the right solution.
UPDATE
Here is my workaround till I find a better solution. As I said working with array functions does not work, since part words should work. So I extended my previous idea a bit. Basic idea is to differ between first time and the next. I improved the code a bit.
function get_title($input, $text) {
$length = strripos($text, $input) + strlen($input);
$stringpos = stripos($text, ' ', $length);
// Find next ' '
$stringpos2 = stripos($text, ' ', $stringpos+1);
if (!$stringpos) {
$newstring = $text;
} else if ($stringpos2) {
$newstring = substr($text, 0, $stringpos2);
} }
Not pretty, but hey it seems to work ^^. Anyway maybe someone of you have a better solution.
You can try using explode
$string = explode(" ", "My longest text to test");
$key = array_search("My", $string);
echo $string[$key] , " " , $string[$key + 1] ;
You can take i to the next level using case insensitive with preg_match_all
$string = "My longest text to test in my school that is very close to mY village" ;
var_dump(__search("My",$string));
Output
array
0 => string 'My longest' (length=10)
1 => string 'my school' (length=9)
2 => string 'mY village' (length=10)
Function used
function __search($search,$string)
{
$result = array();
preg_match_all('/' . preg_quote($search) . '\s+\w+/i', $string, $result);
return $result[0];
}
There are simpler ways to do that. String functions are useful if you don't want to look for something specific, but cut out a pre-defined length of something. Else use a regular expression:
preg_match('/My\s+\w+/', $string, $result);
print $result[0];
Here the My looks for the literal first word. And \s+ for some spaces. While \w+ matches word characters.
This adds some new syntax to learn. But less brittle than workarounds and lengthier string function code to accomplish the same.
An easy method would be to split it on whitespace and grab the current array index plus the next one:
// Word to search for:
$findme = "text";
// Using preg_split() to split on any amount of whitespace
// lowercasing the words, to make the search case-insensitive
$words = preg_split('/\s+/', "My longest text to test");
// Find the word in the array with array_search()
// calling strtolower() with array_map() to search case-insensitively
$idx = array_search(strtolower($findme), array_map('strtolower', $words));
if ($idx !== FALSE) {
// If found, print the word and the following word from the array
// as long as the following one exists.
echo $words[$idx];
if (isset($words[$idx + 1])) {
echo " " . $words[$idx + 1];
}
}
// Prints:
// "text to"

Categories