I want to implode a string with multiple delimiters. I've already eplode it with this PHP function:
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
$text = "here is a sample: this text, and this will be exploded. this also | this one too :)";
$exploded = multiexplode(array(",",".","|",":"),$text);
The output of this is:
Array (
[0] => here is a sample
[1] => this text
[2] => and this will be exploded
[3] => this also
[4] => this one too
[5] => )
)
Can I implode this array with the following multiple delimiters: , . | : ?
Edit:
For define the rules I think this is the best option:
$test = array(':', ',', '.', '|', ':');
$i = 0;
foreach ($exploded as $value) {
$exploded[$i] .= $test[$i];
$i++;
}
$test2 = implode($exploded);
The output of $test2 is:
here is a sample: this text, and this will be exploded. this also | this one too :)
I only now need to know how to define the $test array (maybe with preg_match()?) so that it matched these values , . | : and set the variables in a order where it occurs in the string into an array. Is this possible?
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
$string = "here is a sample: this text, and this will be exploded. this also | this one too :)";
echo "Input:".PHP_EOL.$string;
$needle = array(",",".","|",":");
$split = multiexplode($needle, $string);
$chars = implode($needle);
$found = array();
while (false !== $search = strpbrk($string, $chars)) {
$found[] = $search[0];
$string = substr($search, 1);
}
echo PHP_EOL.PHP_EOL."Found needle:".PHP_EOL.PHP_EOL;
print_r($found);
$i = 0;
foreach ($split as $value) {
$split[$i] .= $found[$i];
$i++;
}
$output = implode($split);
echo PHP_EOL."Output:".PHP_EOL.$output;
The output of this is:
Input:
here is a sample: this text, and this will be exploded. this also | this one too :)
Found needle:
Array
(
[0] => :
[1] => ,
[2] => .
[3] => |
[4] => :
)
Output:
here is a sample: this text, and this will be exploded. this also | this one too :)
You can see it working here.
For more information what's the function of strpbrk in this script, see here.
It's my first contribution to Stack Overflow, hope it helps.
Related
This question already has answers here:
PHP: explode but ignore escaped delimiter
(4 answers)
Closed 3 years ago.
The text is
a,b,c,d\,e,f,g
and I want to split these into an array based on delimiter , and ignore the escaped , like \,e
["a","b","c", "d,e", "f", "g"]
I've tried using explode like
explode(',', $data);
but it doesn't recognize the escaped \ in the text.
How to split the text and ignore the escaped delimiter?
You can use preg_split to split based on un-escaped commas (using a negative look-behind on the comma to check it is not preceded by a \), although you would need to post-process to remove the backslashes:
$string = 'a,b,c,d\,e,f,g';
$array = preg_split('/(?<!\\\\),/', $string);
$array = array_map(function ($v) { return str_replace('\\', '', $v); }, $array);
print_r($array);
Output:
Array ( [0] => a [1] => b [2] => c [3] => d,e [4] => f [5] => g )
You can use regular expression for this, and they are quite good, but they are also quite hard to understand. Why not something more simplistic like:
$input = "a,b,c,d\,e,f,g,h\,i\,j,k,l,m";
$output = [];
$buffer = "";
foreach (explode(",", $input) as $part) {
if (substr($part, -1) == "\\") $buffer .= $part;
else {
$output[] = $buffer . $part;
$buffer = "";
}
}
print_r($output);
This doesn't remove the backslashes, but it is now easy to add or remove that. This is the same algorithm that removes them:
foreach (explode(",", $input) as $part) {
if (substr($part, -1) == "\\") $buffer .= substr($part, 0, -1) . ',';
else {
$output[] = $buffer . $part;
$buffer = "";
}
}
I am aware that this is not a popular opinion, but changing something you can actually easy understand is a lot more fun than struggling to understand dense regular expressions. It's, of course, all quite subjective.
Wihout regular expression
$ignore = '\\';
$arr = explode(',','a,b,c,d\,e,f,g');
array_walk($arr, function(&$v, $k) use ($ignore,&$arr){
if(strpos($v, $ignore)){
$v = str_replace($ignore, ',', $v).$arr[$k+1];
unset($arr[$k+1]);
}
return $v;
});
try this
$string = 'a,b,c,d\,e,f,g';
$str = str_replace("\,", '\\', $string);
$array = explode(',', $str);
print_r(str_replace('\\',',',$array));
result
Array
(
[0] => a
[1] => b
[2] => c
[3] => d,e
[4] => f
[5] => g
)
i hope someone can help.
I have a string as following
$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';
Now what i am trying is to create an array out of each key, value pair but badly failing with regex for preg_match_all()
Currently my attempts aren't giving desired results, creating key => value pairs works as long as there are no brackets, but i have absolutely no idea how to achieve a multidimensional array if key contains key/value pairs inside brackets in example.
Array (
[0] => Array
(
[0] => latitude=46.6781471,
[1] => longitude=13.9709534,
[2] => options=[units=si,
[3] => lang=de,
)
[1] => Array
(
[0] => latitude
[1] => longitude
[2] => options=[units
[3] => lang
)
.. and so on
Where in the end i would like to achieve results as following.
Array (
[latitude] => 46.6781471
[longitude] => 13.9709534
[options] => Array
(
[units] => auto
[exclude] => hourly,minutely
)
)
I would appreciate any help or example how i can achieve this from a given string.
Regular expression isn't the right tool to deal with recursive matches. You can write a parser instead of a regex (or use JSON, query string, XML or any other commonly used format):
function parseOptionsString($string) {
$length = strlen($string);
$key = null;
$contextStack = array();
$options = array();
$specialTokens = array('[', ']', '=', ',');
$buffer = '';
$currentOptions = $options;
for ($i = 0; $i < $length; $i++) {
$currentChar = $string[$i];
if (!in_array($currentChar, $specialTokens)) {
$buffer .= $currentChar;
continue;
}
if ($currentChar == '[') {
array_push($contextStack, [$key, $currentOptions]);
$currentOptions[$key] = array();
$currentOptions = $currentOptions[$key];
$key = '';
$buffer = '';
continue;
}
if ($currentChar == ']') {
if (!empty($buffer)) {
if (!empty($key)) {
$currentOptions[$key] = $buffer;
} else {
$currentOptions[] = $buffer;
}
}
$contextInfo = array_pop($contextStack);
$previousContext = $contextInfo[1];
$thisKey = $contextInfo[0];
$previousContext[$thisKey] = $currentOptions;
$currentOptions = $previousContext;
$buffer = '';
$key = '';
continue;
}
if ($currentChar == '=') {
$key = $buffer;
$buffer = '';
continue;
}
if ($currentChar == ',') {
if (!empty($key)) {
$currentOptions[$key] = $buffer;
} else if (!empty($buffer)) {
$currentOptions[] = $buffer;
}
$buffer = '';
$key = '';
continue;
}
}
if (!empty($key)) {
$currentOptions[$key] = $buffer;
}
return $currentOptions;
}
this gives the following output:
print_r(parseOptionsString($string));
Array
(
[latitude] => 46.6781471
[longitude] => 13.9709534
[options] => Array
(
[units] => auto
[lang] => de
[exclude] => Array
(
[0] => hourly
[1] => minutely
)
)
)
Note also that you want a special syntax for arrays with only comma separated values (exclude=[hourly,minutely] becomes exclude => hourly,minutely and not exclude => array(hourly, minutely)). I think this is an inconsistency in your format and I wrote the parser with the "correct" version in mind.
If you don't want parser you can also try this code. It converts your string to JSON and decode to array. But as others said, I think you should try the approach with JSON. If you're sending this string by XmlHttpRequest in JavaScript it will not be hard to create proper JSON code to send.
$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';
$string = preg_replace('/([^=,\[\]\s]+)/', '"$1"', $string);
$string = '{' . $string . '}';
$string = str_replace('=', ':', $string);
$string = str_replace('[', '{', $string);
$string = str_replace(']', '}', $string);
$string = preg_replace('/({[^:}]*})/', '|$1|', $string);
$string = str_replace('|{', '[', $string);
$string = str_replace('}|', ']', $string);
$result = json_decode($string, true);
print_r($result);
I have a text file which I must read, and use the data from.
3
sam 99912222
tom 11122222
harry 12299933
sam
edward
harry
How can I create an array of these strings in the following form?
array(
"name" => "number"
...
)
I tried this:
$handle = fopen("file.txt", "r");
fscanf($handle, "%d %d", $name, $number);
What then? No matter what I try, it only works for the first line.
sam 99912222
Added codes to have both types of output - ignoring and including the lines that don't have name-value pairs. Check them out below
This code goes through each line and gets only the ones that have both name and value (something[space]something)):
//$lines = ... each line of the file in an array
$vals = array();
foreach($lines as $v){
$tmp = explode(' ', $v);
if(count($tmp) > 1){
$vals[trim($tmp[0])] = trim($tmp[1]); // trim to prevent garbage
}
}
print_r($vals);
It will output this:
Array
(
[sam] => 99912222
[tom] => 11122222
[harry] => 12299933
)
See the code in action here.
If you need the values even if they didn't come in pairs, do it like this:
//$lines = ... each line of the file
$vals = array();
foreach($lines as $v){
$tmp = explode(' ', $v);
$name = '';
$number = '';
$tmp[0] = trim($tmp[0]);
if(count($tmp) > 1){
$name = $tmp[0];
$number = trim($tmp[1]);
}else{
if(is_numeric($tmp[0])){
$number = $tmp[0];
}else{
$name = $tmp[0];
}
}
$vals[] = array(
'name' => $name,
'number' => $number
);
}
print_r($vals);
And the output:
Array
(
[0] => Array
(
[name] =>
[number] => 3
)
[1] => Array
(
[name] => sam
[number] => 99912222
)
[2] => Array
(
[name] => tom
[number] => 11122222
)
[3] => Array
(
[name] => harry
[number] => 12299933
)
[4] => Array
(
[name] => sam
[number] =>
)
[5] => Array
(
[name] => edward
[number] =>
)
[6] => Array
(
[name] => harry
[number] =>
)
See the code in action here.
Data in file are inconsistent, best of is to use regex to identify what data you've got from each line.
$lines = file('file.txt'); // this will open file and split them into lines
$items = array();
foreach($lines as $line){
$name = null;
$number = null;
$nameFound = preg_match("|([A-Za-z]+)|", $line, $matches);
if($nameFound){
$name = $matches[0];
}
$numberFound = preg_match("|([0-9]+)|", $line, $matches);
if($numberFound){
$number = $matches[0];
}
$items[] = array('name' => $name, 'number' => $number);
}
Then in items you should find parsed data from file.
To make it just extract full format data just change lines with regex into one line like this:
$lines = file('file.txt'); // this will open file and split them into lines
$items = array();
foreach($lines as $line){
$userFound = preg_match("/([A-Za-z]+) ([0-9]+)/", $line, $matches);
if($userFound){
$items[$matches[1]] = $matches[2];
}
}
With the Algorithm below, you can simply parse each individual line of the Text-File Contents into an array with the 1st Word or Digit(s) on each line as the Key and the 2nd Word as the Value. When the 2nd word or group of words do not exist, a NULL is assigned to that Key. For re-usability, this algorithm has been encapsulated into a Function. Here you go:
<?php
function parseTxtFile($txtFile){
$arrTxtContent = [];
if(!file_exists($txtFile)){ return null;}
$strFWriteTxtData = file_get_contents($txtFile);
if(empty($strFWriteTxtData)){return null;}
$arrFWriteInfo = explode("\n", $strFWriteTxtData);
foreach($arrFWriteInfo as $iKey=>$lineData){
$arrWriteData = explode(", ", $lineData);
foreach($arrWriteData as $intKey=>$strKeyInfo){
preg_match("#(^[a-z0-9_A-Z]*)(\s)(.*$)#i", $strKeyInfo, $matches);
preg_match("#(^[a-z0-9_A-Z]*)(\s*)?$#i", $strKeyInfo, $matches2);
if($matches) {
list(, $key, $null, $val) = $matches;
if (!array_key_exists($key, $arrTxtContent)) {
$arrTxtContent[$key] = $val;
}else{
$iKey = $intKey + 1;
$key = $key . "_{$iKey}";
$arrTxtContent[$key] = $val;
}
}else if($matches2) {
list(, $key, $null) = $matches2;
if (!array_key_exists($key, $arrTxtContent)) {
$arrTxtContent[$key] = null;
}else{
$key = preg_match("#_\d+#", $key, $match)? $key . $match[0] : "{$key}_1";
$arrTxtContent[$key] = null;
}
}
}
}
return $arrTxtContent;
}
var_dump(parseTxtFile(__DIR__ . "/data.txt"));
Just call the function parseTxtFile($txtFile) passing it the path to your text File and it will return an Array that looks something like below:
array (size=7)
3 => null
'sam' => string '99912222' (length=8)
'tom' => string '11122222' (length=8)
'harry' => string '12299933' (length=8)
'sam_1' => null
'edward' => null
'harry_1' => null
Hope this could help a bit....
Cheers & Good-Luck ;-)
$str = "This is a string";
$words = explode(" ", $str);
Works fine, but spaces still go into array:
$words === array ('This', 'is', 'a', '', '', '', 'string');//true
I would prefer to have words only with no spaces and keep the information about the number of spaces separate.
$words === array ('This', 'is', 'a', 'string');//true
$spaces === array(1,1,4);//true
Just added: (1, 1, 4) means one space after the first word, one space after the second word and 4 spaces after the third word.
Is there any way to do it fast?
Thank you.
For splitting the String into an array, you should use preg_split:
$string = 'This is a string';
$data = preg_split('/\s+/', $string);
Your second part (counting spaces):
$string = 'This is a string';
preg_match_all('/\s+/', $string, $matches);
$result = array_map('strlen', $matches[0]);// [1, 1, 4]
Here is one way, splitting the string and running a regex once, then parsing the results to see which segments were captured as the split (and therefore only whitespace), or which ones are words:
$temp = preg_split('/(\s+)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$spaces = array();
$words = array_reduce( $temp, function( &$result, $item) use ( &$spaces) {
if( strlen( trim( $item)) === 0) {
$spaces[] = strlen( $item);
} else {
$result[] = $item;
}
return $result;
}, array());
You can see from this demo that $words is:
Array
(
[0] => This
[1] => is
[2] => a
[3] => string
)
And $spaces is:
Array
(
[0] => 1
[1] => 1
[2] => 4
)
You can use preg_split() for the first array:
$str = 'This is a string';
$words = preg_split('#\s+#', $str);
And preg_match_all() for the $spaces array:
preg_match_all('#\s+#', $str, $m);
$spaces = array_map('strlen', $m[0]);
Another way to do it would be using foreach loop.
$str = "This is a string";
$words = explode(" ", $str);
$spaces=array();
$others=array();
foreach($words as $word)
{
if($word==' ')
{
array_push($spaces,$word);
}
else
{
array_push($others,$word);
}
}
Here are the results of performance tests:
$str = "This is a string";
var_dump(time());
for ($i=1;$i<100000;$i++){
//Alma Do Mundo - the winner
$rgData = preg_split('/\s+/', $str);
preg_match_all('/\s+/', $str, $rgMatches);
$rgResult = array_map('strlen', $rgMatches[0]);// [1,1,4]
}
print_r($rgData); print_r( $rgResult);
var_dump(time());
for ($i=1;$i<100000;$i++){
//nickb
$temp = preg_split('/(\s+)/', $str, -1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$spaces = array();
$words = array_reduce( $temp, function( &$result, $item) use ( &$spaces) {
if( strlen( trim( $item)) === 0) {
$spaces[] = strlen( $item);
} else {
$result[] = $item;
}
return $result;
}, array());
}
print_r( $words); print_r( $spaces);
var_dump(time());
int(1378392870)
Array
(
[0] => This
[1] => is
[2] => a
[3] => string
)
Array
(
[0] => 1
[1] => 1
[2] => 4
)
int(1378392871)
Array
(
[0] => This
[1] => is
[2] => a
[3] => string
)
Array
(
[0] => 1
[1] => 1
[2] => 4
)
int(1378392873)
$financialYear = 2015-2016;
$test = explode('-',$financialYear);
echo $test[0]; // 2015
echo $test[1]; // 2016
Splitting with regex has been demonstrated well by earlier answers, but I think this is a perfect case for calling ctype_space() to determine which result array should receive the encountered value.
Code: (Demo)
$string = "This is a string";
$words = [];
$spaces = [];
foreach (preg_split('~( +)~', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $s) {
if (ctype_space($s)) {
$spaces[] = strlen($s);
} else {
$words[] = $s;
}
}
var_export([
'words' => $words,
'spaces' => $spaces
]);
Output:
array (
'words' =>
array (
0 => 'This',
1 => 'is',
2 => 'a',
3 => 'string',
),
'spaces' =>
array (
0 => 1,
1 => 1,
2 => 4,
),
)
If you want to replace the piped constants used by preg_split() you can just use 3 (Demo). This represents PREG_SPLIT_NO_EMPTY which is 1 plus PREG_SPLIT_DELIM_CAPTURE which is 2. Be aware that with this reduction in code width, you also lose code readability.
preg_split('~( +)~', $string, -1, 3)
What about this? Does someone care to profile this?
$str = str_replace(["\t", "\r", "\r", "\0", "\v"], ' ', $str); // \v -> vertical space, see trim()
$words = explode(' ', $str);
$words = array_filter($words); // there would be lots elements from lots of spaces so skip them.
This question already has answers here:
How to split a string by multiple delimiters in PHP?
(4 answers)
Closed 12 months ago.
Can we do multiple explode() in PHP?
For example, to do this:
foreach(explode(" ",$sms['sms_text']) as $no)
foreach(explode("&",$sms['sms_text']) as $no)
foreach(explode(",",$sms['sms_text']) as $no)
All in one explode like this:
foreach(explode('','&',',',$sms['sms_text']) as $no)
What's the best way to do this? What I want is to split the string on multiple delimiters in one line.
If you're looking to split the string with multiple delimiters, perhaps preg_split would be appropriate.
$parts = preg_split( '/(\s|&|,)/', 'This and&this and,this' );
print_r( $parts );
Which results in:
Array (
[0] => This
[1] => and
[2] => this
[3] => and
[4] => this
)
Here is a great solution I found at PHP.net:
<?php
//$delimiters must be an array.
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
$text = "here is a sample: this text, and this will be exploded. this also | this one too :)";
$exploded = multiexplode(array(",",".","|",":"),$text);
print_r($exploded);
//And output will be like this:
// Array
// (
// [0] => here is a sample
// [1] => this text
// [2] => and this will be exploded
// [3] => this also
// [4] => this one too
// [5] => )
// )
?>
you can use this
function multipleExplode($delimiters = array(), $string = ''){
$mainDelim=$delimiters[count($delimiters)-1]; // dernier
array_pop($delimiters);
foreach($delimiters as $delimiter){
$string= str_replace($delimiter, $mainDelim, $string);
}
$result= explode($mainDelim, $string);
return $result;
}
You could use preg_split() function to stplit a string using a regular expression, like so:
$text = preg_split('/( |,|&)/', $text);
I'd go with strtok(), eg
$delimiter = ' &,';
$token = strtok($sms['sms_text'], $delimiter);
while ($token !== false) {
echo $token . "\n";
$token = strtok($delimiter);
}