This question already has answers here:
PHP/REGEX: Get a string within parentheses
(2 answers)
Closed 8 years ago.
Currently I use arrays such as this one for version control of a Mysql database:
$pages_table = array (
"GUID" => array (
"type" => "CHAR(13)",
"length" => 13,
)
"Number" => array (
"type" => "TINYINT(4)",
"length" => 4,
)
"Pagename" => array (
"type" => "VARCHAR(30)",
"length" => 30,
)
It works, but I want to make it more clean, like:
$pages_table = array (
"GUID" => "CHAR(13)",
"Number" => "TINYINT(4)",
"Pagename" => "VARCHAR(30)",
);
And then if I iterate over the array, I want to set $new_length (INT) to the number between the brackets of the $new_type string:
while ($column = key($pages_table)) {
$new_type = current($pages_table);
$new_length = //Get this value from $new_type;
if ($existing_table[$column]['length'] < $new_length) {
$modify[$column] = $new_type;
}
next($pages_table);
}
Use regular expressions:
preg_match('/\(\d+\)/', $subject, $matches);
$new_length = $matches[0];
You could shorten the pattern if it is guaranteed that there are no other numbers in the string:
preg_match('/\d+/', $subject, $matches);
$new_length = $matches[0];
while ($column = key($pages_table)) {
$new_type = current($pages_table);
$hasLength = (preg_match('/\(\d+\)/', $new_type, $matches) == 1);
$new_length = intval($matches[0]);
if ($hasLength && $existing_table[$column]['length'] < $new_length) {
$modify[$column] => $new_type;
}
next($pages_table);
}
$new_length = (int) preg_replace('/\D/', '', $new_type);
Related
I have following code that removes adjacent duplicates from the $myArray
<?php
$myArray = array(
0 => 0,
1 => 0,
2 => 1,
5 => 1,
6 => 2,
7 => 2,
8 => 2,
9 => 0,
10 => 0,
);
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem) use (&$previtem) {
$p = $previtem;
$previtem= $currentItem;
return $currentItem!== $p ;
}
);
echo "<pre>";
print_r($newArray);
?>
It works perfectly fine, but I have to change a condition bit for value 2. That means for other values we can pick first occurrence and ignore the others. But for 2, we need to pick last occurrence and ignore others.
So required output is
Array
(
[0] => 0 //first occurrence of 0 in $myArray
[2] => 1 //first occurrence of 1 in $myArray
[8] => 2 //last occurrence of 2 in the $myArray
[9] => 0 //first occurrence of 0 in $myArray
)
How to modify my code to achieve above result??
In reality I have multidimensional array, but for better explanation I have used single dimensional array here in the question.
UPDATE
My actual array is
$myArray = array(
0 => array("Value"=>0, "Tax" => "11.00"),
1 => array("Value"=>0, "Tax" => "12.00"),
2 => array("Value"=>1, "Tax" => "13.00"),
5 => array("Value"=>1, "Tax" => "14.00"),
6 => array("Value"=>2, "Tax" => "15.00"),
7 => array("Value"=>2, "Tax" => "16.00"),
8 => array("Value"=>2, "Tax" => "17.00"),
9 => array("Value"=>0, "Tax" => "18.00"),
10 => array("Value"=>0, "Tax" => "19.00"),
);
And my actual code
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem) use (&$previtem) {
$p["Value"] = $previtem["Value"];
$previtem["Value"] = $currentItem["Value"];
return $currentItem["Value"]!== $p["Value"] ;
}
);
Thanks
This should do what you are looking for.
function array_filter($a) {
$na = array();
$first = true;
$p = null;
$wantlast = false;
foreach ($a as $v) {
if ($wantlast) {
($v != $p) ? $na[] = $p: null;
}
$wantlast = ($v == 2) ? true : false;
if (!$wantlast) {
(($v != $p) || ($first))? $na[] = $v : null;
}
$p = $v;
$first = false;
}
return $na;
}
$myArray = array(
0 => 0,
1 => 0,
2 => 1,
5 => 1,
6 => 2,
7 => 2,
8 => 2,
9 => 0,
10 => 0,
);
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem, $key) use (&$previtem,$myArray) {
$p = $previtem;
if($currentItem != 2){
$previtem = $currentItem;
}else{
$lastkey = array_search(2,(array_reverse($myArray, true)));
if($key != $lastkey)
$currentItem = $previtem;
}
return $currentItem!== $p ;
}, ARRAY_FILTER_USE_BOTH
);
echo "<pre>";
print_r($newArray);
This question already has answers here:
How to access and manipulate multi-dimensional array by key names / path?
(10 answers)
Closed 6 years ago.
Let's assume that I have an array like following:
$settings = array(
"age" => "25",
"data" => array(
"name" => "John Dewey",
"zip_code" => "00000"
)
);
Here's my input:
$target_directory = "data.name"; // targets $settings["data"]["name"]
$new_value = "Micheal"; // I want to change
// $settings["data"]["name"] with this value
I want something similar to following:
$new_array = dont_know_what_to_do($target_directory, $new_value, $settings);
A print_r($new_array) should return following:
Array
(
[age] => 25
[data] => Array
(
[name] => Micheal,
"zip_code" => "00000"
)
)
The change should be totally dynamic, meaning that data.zip_code = "98985" should also change only the zip code value from 00000 to 98985, and so on...
Here is the dynamic set funciton, you can use it set any depth. Demo here for you question.
function set($settings, $target_directory, $new_value)
{
$array = explode('.', $target_directory);
$ref = &$settings;
while($v = current($array))
{
$ref = &$ref[$v];
next($array);
}
$ref = $new_value;
return $settings;
}
$settings = array(
"age" => "25",
"data" => array(
"name" => "John Dewey",
"zip_code" => "00000"
)
);
$new_value = "Micheal";
$settings["data"]["name"] = $new_value;
print_r($settings);
//In your main function
public function something() {
$settings = array(
"age" => "25",
"data" => array(
"name" => "John Dewey",
"zip_code" => "00000"
)
);
$target = 'data.name';
$input = 'Other Name'
$new_arr = dont_know_what_to_do($target_dir, $input);
print_r($new_arr);
}
//Create new function
public function dont_know_what_to_do($settings, $target, $input) {
$key = explode('.', $target)
return $settings['data'][$key[1]] = $input;
}
This is quite basic, but I am missing a puzzle piece.
I have a multidimensional PHP array that - among other things - contains some strings. I would like to translate special strings in this array based on a translation table or array in PHP.
$r = array(
0 => 'something',
1 => array(
'othertext' => '1000 {{animals}} and {{cars}}',
'anytext' => '400 {{cars}}',
)
);
In $r, now I would like to replace {{animals}} with another string that is stored in a separate array.
Here it is:
$translations = array(
'animals' => array('Tiere','animaux','bestie'),
'cars' => array('Autos','voitures','macchine'),
);
Now let's set the language / column we want to look up
$langId = 0;
And now, take $r, look for all key that are wrapped in {{}}, look them up in $translations and replace them with key[$langId], so in return we get:
$r = array(
0 => 'something',
1 => array(
'othertext' => '1000 Tiere',
'anytext' => '400 Autos',
)
);
ehm... how's that done?
PS: the marker {{}} is random, could be anything robust
I was able to get the output you expected using the following code. Try it and tell me if it worked for you or not:
<?php
$r = array(
0 => 'something',
1 => array(
'othertext' => '1000 {{animals}} and {{cars}}',
'anytext' => '400 {{cars}}',
)
);
$translations = array(
'animals' => array('Tiere','animaux','bestie'),
'cars' => array('Autos','voitures','macchine'),
);
$langId = 0;
$pattern = "/\{\{[a-zA-Z]+\}\}/";
for($t=0; $t<count($r); $t++) {
$row = $r[$t];
if(!is_array($row))
continue;
foreach($row as $key=>$value) {
if(preg_match_all($pattern, $value, $match, PREG_SET_ORDER)) {
for($i = 0; $i < count($match); $i++) {
//remove {{ & }} to get key
$k = substr($match[$i][0], 2, strlen($match[$i][0])-4);
$replacer = $translations[$k][$langId];
$value = str_replace($match[$i][0], $replacer, $value);
$r[$t][$key] = $value;
}
}
}
}
?>
Output for $status
Array
(
[1] => 1
[2] => 0
[3] => 0
[4] => 4
[5] => 4
)
$color_code_string = implode(",",$status);
Ouput
1,0,0,4,4
$color_code_string = str_replace("0","'#F00'",$color_code_string);
$color_code_string = str_replace("1","'#00bcd4'",$color_code_string);
$color_code_string = str_replace("2","'#4caf50'",$color_code_string);
$color_code_string = str_replace("3","'#bdbdbd'",$color_code_string);
$color_code_string = str_replace("4","'#ff9900'",$color_code_string);
Exception
SyntaxError: illegal character
colors: ['#00bcd'#ff9900'','#F00','#F00','#ff9900','#ff9900']
//prints '#00bcd'#ff9900'','#F00','#F00','#ff9900','#ff9900'
How do I achieve expected output as below
'#00bcd','#ff9900','#F00','#F00','#ff9900','#ff9900'
That happens because you are also replacing numbers inside the color codes you replaced before.
Solution: traverse the array to do the replacement before imploding the array of colors:
// Translation table, saves you separate lines of stringreplace calls.
$colorCodes = array(
0 => "#F00",
1 => "#00bcd4",
2 => "#4caf50",
3 => "#bdbdbd",
4 => "#ff9900",
);
// Build an array of colors based on the array of status codes and the translation table.
// I'm adding the quotes here too, but that's up to you.
$statusColors = array();
foreach($status as $colorCode) {
$statusColors[] = "'{$colorCodes[$colorCode]}'";
}
// Last step: implode the array of colors.
$colors = implode(','$statusColors);
$status = [1,0,0,4,4,];
$color_code_string = implode(",",$status);
$replacements = ["0" => "'#F00'","1" => "'#00bcd4'","2" => "'#4caf50'","3" => "'#bdbdbd'","4" => "'#ff9900'",];
$color_code_string = strtr($color_code_string, $replacements);
echo $color_code_string;
There is a big Caution notice about your problem in the str_replace() documentation:
Caution
Replacement order gotcha
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements. See also the examples in this document.
Use strtr() instead, because str_replace() will overwrite previous replacements
$status = [
1,
0,
0,
4,
4,
];
$color_code_string = implode(",",$status);
$replacements = [
"0" => "'#F00'",
"1" => "'#00bcd4'",
"2" => "'#4caf50'",
"3" => "'#bdbdbd'",
"4" => "'#ff9900'",
];
$color_code_string = strtr($color_code_string, $replacements);
echo $color_code_string;
<?php
$color_code = array(1, 0, 0, 4, 4);
array_walk($color_code, 'color_code_replace');
$color_code_string = implode(",",$color_code);
function color_code_replace(&$cell) {
switch ($cell) {
case 0 : {
$cell = '#F00';
break;
}
case 1 : {
$cell = '#00bcd4';
break;
}
case 2 : {
$cell = '#4caf50';
break;
}
case 3 : {
$cell = '#bdbdbd';
break;
}
case 4 : {
$cell = '#ff9900';
break;
}
default : {
throw new Exception("Unhandled Color Code");
}
}
}
var_dump($color_code);
From a text like:
category=[123,456,789], subcategories, id=579, not_in_category=[111,333]
I need a regex to get something like:
$params[category][0] = 123;
$params[category][1] = 456;
$params[category][2] = 789;
$params[subcategories] = ; // I just need to know that this exists
$params[id] = 579;
$params[not_category][0] = 111;
$params[not_category][1] = 333;
Thanks everyone for the help.
PS
As you suggested, I clarify that the structure and the number of items may change.
Basically the structure is:
key=value, key=value, key=value, ...
where value can be:
a single value (e.g. category=123 or postID=123 or mykey=myvalue, ...)
an "array" (e.g. category=[123,456,789])
a "boolean" where the TRUE value is an assumption from the fact that "key" exists in the array (e.g. subcategories)
This method should be flexible enough:
$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$str = preg_replace('#,([^0-9 ])#',', $1',$str); //fix for string format with no spaces (count=10,paginate,body_length=300)
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
var_dump(isset($params['subcategories']));
Output:
Array
(
[category] => Array
(
[0] => 123
[1] => 456
[2] => 789
)
[subcategories] =>
[id] => 579
[not_in_category] => Array
(
[0] => 111
[1] => 333
)
)
bool(true)
Alternate (no string manipulation before process):
$str = 'count=10,paginate,body_length=300,rawr=[1,2,3]';
preg_match_all('#(.+?)(,([^0-9,])|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $k => $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
$key = isset($sections[3][$k-1]) ? trim($sections[3][$k-1]).$key : $key; //Fetch first character stolen by previous match
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
Another alternate: full re-format of string before process for safety
$str = 'count=10,paginate,body_length=300,rawr=[1, 2,3] , name = mike';
$str = preg_replace(array('#\s+#','#,([^0-9 ])#'),array('',', $1'),$str); //fix for varying string formats
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
{
$val = explode(',',$match[1]); //turn the comma separated numbers into an array
}
$params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
You can use JSON also, it's native in PHP : http://php.net/manual/fr/ref.json.php
It will be more easy ;)
<?php
$subject = "category=[123,456,789], subcategories, id=579, not_in_category=[111,333]";
$pattern = '/category=\[(.*?)\,(.*?)\,(.*?)\]\,\s(subcategories),\sid=(.*?)\,\snot_in_category=\[(.*?)\,(.*?)\]/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?>
I think this will get you the matches out... didn't actually test it but it might be a good starting point.
Then you just need to push the matches to the correct place in the array you need. Also test if the subcategories string exists with strcmp or something...
Also, notice that I assumed your subject string has that fixe dtype of structure... if it is changing often, you'll need much more than this...
$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$main_arr = preg_split('/(,\s)+/', $str);
$params = array();
foreach( $main_arr as $value) {
$pos = strpos($value, '=');
if($pos === false) {
$params[$value] = null;
} else {
$index_part = substr($value, 0, $pos);
$value_part = substr($value, $pos+1, strlen($value));
$match = preg_match('/\[(.*?)\]/', $value_part,$xarr);
if($match) {
$inner_arr = preg_split('/(,)+/', $xarr[1]);
foreach($inner_arr as $v) {
$params[$index_part][] = $v;
}
} else {
$params[$index_part] = $value_part;
}
}
}
print_r( $params );
Output :
Array
(
[category] => Array
(
[0] => 123
[1] => 456
[2] => 789
)
[subcategories] =>
[id] => 579
[not_in_category] => Array
(
[0] => 111
[1] => 333
)
)