Parse string of alternating letters and numbers (no delimiters) to associative array - php

I need to parse a string of alternating letters and number and populate an array where the letters are the keys and the numbers are the values.
Example:
p10s2z1234
Output
Array(
'p' => 10,
's' => 2,
'z' => 1234
)

Use regex to get desired values and then combine arrays to get associative array. For example:
$str = 'p10s2z1234';
preg_match_all('/([a-z]+)(\d+)/', $str, $matches); //handles only lower case chars. feel free to extend regex
print_r(array_combine($matches[1], $matches[2]));

Scenario 1: You want to parse the string which has single letters to be keys, will produce three pairs of values, and you want the digits to be cast as integers. Then the best, most direct approach is sscanf() with array destructuring -- a single function call does it all. (Demo)
$str = 'p10s2z1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = sscanf($str, '%1s%d%1s%d%1s%d');
var_export($result);
Output:
array (
'p' => 10,
's' => 2,
'z' => 1234,
)
Scenario 2: You want the same parsing and output as scenario 1, but the substrings to be keys have variable/unknown length. (Demo)
$str = 'pie10sky2zebra1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = sscanf($str, '%[^0-9]%d%[^0-9]%d%[^0-9]%d');
var_export($result);
Scenario 3: You want to parse the string with regex and don't care that the values are "string" data-typed. (Demo)
$str = 'pie10sky2zebra1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = preg_split('/(\d+)/', $str, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
var_export($result);
Scenario 4: If you don't know how many pairs will be generated by the input string, use array_combine(). (Demo)
$str = 'pie10sky2zebra1234extra999';
var_export(
preg_match_all('/(\D+)(\d+)/', $str, $m)
? array_combine($m[1], $m[2])
: []
);

Related

Uppercase array keys and Lowercase array values (input from parse_str)

It feels like that problem has already been solved but my search did not find a "good" solution. I have a time critical app and need to convert a typical string into an assoc array:
"appliCAation=webCALL&Arg1=ABC&arG2=xyZ&someMore=Dec-1950"
I know I can use parse_str() for that but I would like to "normalize" the user input so that all keys are always uppercase and all values are always lowercase (and vice versa, if possible done by parameter and NOT widen the footprint of the code).
Since array_change_key_case() does not work recursively, I search for an elegant way with few lines of code and efficient performance.
At the moment I use parse_str( strtolower( $input ), $arr ); and then loop (recursively) the array to change the keys. Unfortunately that needs two methods and "many" code lines.
Any faster / better / smaller solution for that?
Flip your logic and uppercase everything and then recursively lower case the values:
parse_str(strtoupper($string), $array);
array_walk_recursive($array, function(&$v, $k) { $v = strtolower($v); });
This will work for multiple dimensions such as:
$string = "appliCAation=webCALL&Arg1=ABC&arG2=xyZ&someMore=Dec-1950&a[yZ][zzz]=efG";
Yielding:
Array
(
[APPLICAATION] => webcall
[ARG1] => abc
[ARG2] => xyz
[SOMEMORE] => dec-1950
[A] => Array
(
[YZ] => Array
(
[ZZZ] => efg
)
)
)
After rereading the question I see you want to be able to change or control whether the keys and values are uppercase or lowercase. You can use() a parameters array to use as function names:
$params = ['key' => 'strtoupper', 'val' => 'strtolower'];
parse_str($params['key']($string), $array);
array_walk_recursive($array, function(&$v, $k) use($params){ $v = $params['val']($v); });
To change just the keys, I would use a Regular Expression on the original string:
$keys = 'strtoupper';
$string = preg_replace_callback('/[^=&]*=/', function($m) use($keys) { return $keys($m[0]); }, $string);
parse_str($string, $array);
[^=&]*= is a character class [] matching characters that are ^ not = or & 0 or more times * followed by =.
And finally, here is one that will do keys and values if you supply a function name (notice val is empty), if not then it is not transformed:
$params = ['key' => 'strtoupper', 'val' => ''];
$string = preg_replace_callback('/([^=&]*)=([^=&]*)/',
function($m) use($params) {
return (empty($params['key']) ? $m[1] : $params['key']($m[1]))
.'='.
(empty($params['val']) ? $m[2] : $params['val']($m[2]));
}, $string);
parse_str($string, $array);

How to remove outer quotes from square bracket in array value

I have this array and I need to use it in Charts
in data index I have this value [1,9] and it's coming form the comma split explode function without any quotes around it.
$main_arr = array(
"label" => 'Total Clicks',
"data" => [$total_clicks],
"backgroundColor" => "rgba(255, 0, 0, 1)",
);
Then I use json_encode to turn the array into json format,
[{"label":"Total Clicks","data":["1, 9"],"backgroundColor":"rgba(255, 0, 0, 1)"}]
As you can see above there are double quotes in the square bracket, if I pass static value in the data index i.e [1, 9] it works fine. I tried regex, substring, rtrim etc but didn't work anyone.
Your help would be much appreciated!
You have several problems at once here. First of all your values are strings, and secondly you have an multiple values that you want to explode so you have singular values:
$total_clicks = '1, 9'; // value guessed based on unexpected output in question
$clickArray = explode(',', $total_clicks);
$clickArray = array_map('trim', $clickArray); // remove white spaces
$clickArray = array_map('intval', $clickArray); // cast everything to int
$main_arr = array(
"label" => 'Total Clicks',
"data" => $clickArray,
"backgroundColor" => "rgba(255, 0, 0, 1)",
);
echo json_encode($main_arr);
this outputs:
{"label":"Total Clicks","data":[1,9],"backgroundColor":"rgba(255, 0, 0, 1)"}
For a more sloppy approach you could even skip the line where I trim the whitespaces away, as casting to integer will do this implicitly, however I like to have a clean flow of handled data.
Converting string to array of ints:
$total_clicks = "1, 9";
print_r(array_map('intval', explode(', ', $total_clicks)));
Converting string to array of strings:
$total_clicks = "1, 9";
print_r(array_map('trim', explode(', ', $total_clicks)));

Get matches from a preg_replace and use them as an array key

I want to get matches from a String and use them in a array as key to change the value in the string to the value of the array.
If it would be easier to realize, i can change the fantasy tags from %! also to whatever don't have problems in JS/jQuery. This script is for external JS Files and change some variables, which I can't Access from JS/jQuery. So I want to insert them with PHP and send them minified and compressed to the Browser.
$array = array ( 'abc' => 'Test', 'def' => 'Variable', 'ghi' => 'Change' );
$string ='This is just a %!abc!% String and i wanna %!ghi!% the %!def!%';
$string = preg_replace('%!(.*?)!%',$array[$1],$string);
echo $string;
You can use array_map with preg_quote to turn the keys of your array into regexes, and then use the values of the array as replacement strings in the array form of preg_replace:
$array = array ( 'abc' => 'Test', 'def' => 'Variable', 'ghi' => 'Change' );
$string ='This is just a %!abc!% String and i wanna %!ghi!% the %!def!%';
$regexes = array_map(function ($k) { return "/" . preg_quote("%!$k!%") . "/"; }, array_keys($array));
$string = preg_replace($regexes, $array, $string);
echo $string;
Output:
This is just a Test String and i wanna Change the Variable
Demo on 3v4l.org

PHP - preg_replace on an array not working as expected

I have a PHP array that looks like this..
Array
(
[0] => post: 746
[1] => post: 2
[2] => post: 84
)
I am trying to remove the post: from each item in the array and return one that looks like this...
Array
(
[0] => 746
[1] => 2
[2] => 84
)
I have attempted to use preg_replace like this...
$array = preg_replace('/^post: *([0-9]+)/', $array );
print_r($array);
But this is not working for me, how should I be doing this?
You've missed the second argument of preg_replace function, which is with what should replace the match, also your regex has small problem, here is the fixed version:
preg_replace('/^post:\s*([0-9]+)$/', '$1', $array );
Demo: https://3v4l.org/64fO6
You don't have a pattern for the replacement, or a empty string place holder.
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject)
Is what you are trying to do (there are other args, but they are optional).
$array = preg_replace('/post: /', '', $array );
Should do it.
<?php
$array=array("post: 746",
"post: 2",
"post: 84");
$array = preg_replace('/^post: /', '', $array );
print_r($array);
?>
Array
(
[0] => 746
[1] => 2
[2] => 84
)
You could do this without using a regex using array_map and substr to check the prefix and return the string without the prefix:
$items = [
"post: 674",
"post: 2",
"post: 84",
];
$result = array_map(function($x){
$prefix = "post: ";
if (substr($x, 0, strlen($prefix)) == $prefix) {
return substr($x, strlen($prefix));
}
return $x;
}, $items);
print_r($result);
Result:
Array
(
[0] => 674
[1] => 2
[2] => 84
)
There are many ways to do this that don't involve regular expressions, which are really not needed for breaking up a simple string like this.
For example:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
$o = explode(': ', $n);
return (int)$o[1];
}, $input);
var_dump($output);
And here's another one that is probably even faster:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
return (int)substr($n, strpos($n, ':')+1);
}, $input);
var_dump($output);
If you don't need integers in the output just remove the cast to int.
Or just use str_replace, which in many cases like this is a drop in replacement for preg_replace.
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = str_replace('post: ', '', $input);
var_dump($output);
You can use array_map() to iterate the array then strip out any non-digital characters via filter_var() with FILTER_SANITIZE_NUMBER_INT or trim() with a "character mask" containing the six undesired characters.
You can also let preg_replace() do the iterating for you. Using preg_replace() offers the most brief syntax, but regular expressions are often slower than non-preg_ techniques and it may be overkill for your seemingly simple task.
Codes: (Demo)
$array = ["post: 746", "post: 2", "post: 84"];
// remove all non-integer characters
var_export(array_map(function($v){return filter_var($v, FILTER_SANITIZE_NUMBER_INT);}, $array));
// only necessary if you have elements with non-"post: " AND non-integer substrings
var_export(preg_replace('~^post: ~', '', $array));
// I shuffled the character mask to prove order doesn't matter
var_export(array_map(function($v){return trim($v, ': opst');}, $array));
Output: (from each technique is the same)
array (
0 => '746',
1 => '2',
2 => '84',
)
p.s. If anyone is going to entertain the idea of using explode() to create an array of each element then store the second element of the array as the new desired string (and I wouldn't go to such trouble) be sure to:
split on or : (colon, space) or even post: (post, colon, space) because splitting on : (colon only) forces you to tidy up the second element's leading space and
use explode()'s 3rd parameter (limit) and set it to 2 because logically, you don't need more than two elements

PHP replace all symbol in the beginning and the end of string or array

Hello I have this variable
$str="101,102,103,104,105,#,106#107"
//or array
$str_arr = array( 0 => '101', 1 => '102', 2 => '103', 3 => '104',
4 => '105', 8 => '#' , 9 => '106# 107');
I want to remove the symbol # between comma
The symbol may be /,\,-,| not comma
The symbol between number is correct, so it remains (key 9)
I do not know, if I had these cases but I will study it
$str="101,102,103,104,105#, 106" // One of the symbols in the end of number
$str="101,102,103,104,105,#106" // One of the symbols in the the beginning of number
This is The different possibilities
$str="101,102,103,/,104|,#105,106#107" //replace all symbol in the beginning and the end of number not betwwen number
this is result
$str="101,102,103,104,105,106#107";
Thanks
Convert the string to array using explode by ,. Parse the array using foreach loop. trim() the # or any set of characters like #-|\/ from the beginning and end of every string, then check for empty values and push non empty values to the $arr array. Then you can join the array into a string using implode. You can do it like this:
$arr = array();
$str="101,102,103,104,105,#,106#107";
$str = explode(',', $str);
foreach($str as $s){
$s = trim($s, "#-|\/");
if(!empty($s)){
$arr[] = $s;
}
}
$final_str = implode(',', $arr);
var_dump($final_str);

Categories