I'm stuck with this.
I've got a huge template that goes like this (simplified for this question):
$str = '[a] [b] [c]';
Then I have an array containing those above values:
$arr = array('[a]','[b]','[c]','[d]');
And finally, containing the values for replace comes an array that does not match the above one.
$rep = array("[d]" => "dVal","[a]" => "aVal","[b]" => "bVal", "[c]" => "cVal");
Can I some how, by some technique or any other php function match the $rep array to replace the key with the same name in $str. I current use str_replace.
sr_replace($arr,$rep,$str);//
The key names and names in $str are the same.
str_replace(array_keys($rep), array_values($rep), $str)
Related
Example:
$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>\d\d\d\d-\d\d-\d\d)|i', $string, $arr_result);
print_r($arr_result);
Returns:
Array
(
[0] => 2010-07-18
[date] => 2010-07-18
[1] => 2010-07-18
)
But I want it to be:
Array
(
[date] => 2010-07-18
)
In PHP's PDO object there is an option that is filtering results from database by removing these duplicate numbered values : PDO::FETCH_ASSOC. But I haven't seen similar modifier for the PCRE functions in PHP yet.
How to return only named groups with preg_match or preg_match_all?
This is currently (PHP7) not possible.
You will always get a mixed type array, containing numeric and named keys.
Lets quote the PHP manual (http://php.net/manual/en/regexp.reference.subpatterns.php):
This subpattern will then be indexed in the matches array by its
normal numeric position and also by name.
To solve the problem the following code snippets might help:
1. filter the array by using an is_string check on the array key (for PHP5.6+)
$array_filtered = array_filter($array, "is_string", ARRAY_FILTER_USE_KEY);
2. foreach over the elements and unset if array key is_int() (all PHP versions)
/**
* #param array $array
* #return array
*/
function dropNumericKeys(array $array)
{
foreach ($array as $key => $value) {
if (is_int($key)) {
unset($array[$key]);
}
}
return $array;
}
Its a simple PHP function named dropNumericKeys(). Its for the post-processing of an matches array after a preg_match*() run using named groups for matching. The functions accepts an $array. It iterates the array and removes/unsets all keys with integer type, leaving keys with string type untouched. Finally, the function returns the array with "now" only named keys.
Note: The function is for PHP downward compatiblity. It works on all versions. The array_filter solution relies on the constant ARRAY_FILTER_USE_KEY, which is only available on PHP5.6+. See http://php.net/manual/de/array.constants.php#constant.array-filter-use-key
preg_match does not have any flag or option that it only returns named matches (yet). So what you want is not directly possible. However you can remove all items with non-fitting keys from your matches array and then you get what you're looking for:
$matches = array_intersect_key($matches, array_flip(array('name', 'likes')));
I do not think you can make preg_* do it, but you can do it with a simple loop. But I don't see why those elements pose a problem.
It also possible to unset all numeric indexes before return:
foreach (range(0, floor(count($arr_result) / 2)) as $index) {
unset($arr_result[$index]);
}
Similar to the answer that hakre posted above, I use this snippet to get just the named parameters:
$subject = "This is some text written on 2010-07-18.";
$pattern = '|(?<date>\d\d\d\d-\d\d-\d\d)|i';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
echo '<pre>Before Diff: ', print_r($matches, 1), '</pre>';
$matches = array_diff_key($matches[0], range(0, count($matches[0])));
echo '<pre>After Diff: ', print_r($matches, 1), '</pre>';
...which produces this:
Before Array
(
[0] => Array
(
[0] => 2010-07-18
[date] => 2010-07-18
[1] => 2010-07-18
)
)
After Array
(
[date] => 2010-07-18
)
I read in your post that these are possible overloads of future memory etc ...
In this case, why no't can be solved with an unset():
$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>\d{4}-\d{2}-\d{2})|i', $string, $arr_result);
$date = array("date" => $arr_result['date']);
unset($arr_result, $string);//delete array and string preg_match origen
print_r($date);
//or create a new:
// $arr_result = $date;
//print_r($arr_result);
You could use T-Regx and go with group() or namedGroups() which only returns named capturing groups.
<?php
$subject = "This is some text written on 2010-07-18.";
pattern('(?<date>\d\d\d\d-\d\d-\d\d)', 'i')->match($subject)->first(function ($match) {
$date = $match->get('date');
// 2010-07-18
$groups = $match->namedGroups();
// [
// 'date' => '2010-07-18'
// ]
});
I use some of introduced codes and this is the final code works on php 5.6+:
$re = '/\d+\r\n(?<start>[\d\0:]+),\d+\s--\>\s(?<end>[\d\0:]+),.*\r\nHOME.*\r\nGPS\((?<x>[\d\.]+),(?<y>[\d\.]+),(?<d>[\d\.]+)\)\sBAROMETER\:(?<h>[\d\.]+)/';
$str= file_get_contents($srtFile);
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
echo '<pre>';
$filtered=array_map(function ($d){
return $array_filtered = array_filter($d, "is_string", ARRAY_FILTER_USE_KEY);
},$matches);
var_dump($filtered);
if you are interested what it does it read position data from a str file that DJI drones generate while recording video.
Try this:
$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>\d\d\d\d-\d\d-\d\d)|i',$string,$arr_result);
echo $arr_result['date'];
I am scraping the following kind of strings from an external resource which I can't change:
["one item",0,0,2,0,1,"800.12"],
["another item",1,3,2,5,1,"1,713.59"],
(etc...)
I use the following code to explode the elements into an array.
<?php
$id = 0;
foreach($lines AS $line) {
$id = 0;
// remove brackets and line end comma's
$found_data[] = str_replace(array('],', '[',']', '"'), array('','','',''), $line);
// add data to array
$results[$id] = explode(',', $line);
}
Which works fine for the first line, but as the second line uses a comma for the thousands seperator of the last item, it fails there. So somehow I need to disable the explode to replace stuff between " characters.
If all values would be surrounded by " characters, I could just use something like
explode('","', $line);
However, unfortunately that's not the case here: some values are surrounded by ", some aren't (not always the same values are). So I'm a bit lost in how I should proceed. Anyone who can point me in the right direction?
You can use json_decode here since your input string appears to be a valid json string.
$str = '["another item",1,3,2,5,1,"1,713.59"]'
$arr = json_decode($str);
You can then access individual indices from resulting array or print the whole array using:
print_r($arr);
Output:
Array
(
[0] => another item
[1] => 1
[2] => 3
[3] => 2
[4] => 5
[5] => 1
[6] => 1,713.59
)
I searched every single str_replace, preg_replace, substr on StackOverflow and can't wrap my head around this.
The strings in my data are as such: "010758-01-700" or "860862-L-714". These are just examples.
These strings are 's
Instance 1:
010758-01-700
/ImageServices/image.ashx?itemid=010758&config=01&format=l&imagenumber=1
If you look carefully at the URL and the string above it, I need to split this as "01075&config=01" and drop "-700" from the string to return a value I can insert into the URL
Instance 2:
860862-L-714
/ImageServices/image.ashx?itemid=870078&color=001&format=l&imagenumber=1
I need to split this as "860862&&color=714" and drop all instances of "-XXS-, -XS-, -S-, -M-, -L-, -XL- ,-XXL-" for the string to return a value I can insert into the URL
There are strings that look like this throughout the data, 860862-L-714, 860862-M-999, 860862-XS-744. These are variations of product with the same name but different
I have tried str_replace("-", "&config=", {ItemNo[1]}) but it returns 010758&config=01&config=700
I'd need to contain this all into a function that I can call into the URL
myFunction({ItemNo[1]})
Then I can setup the URL as so /ImageServices/image.ashx?itemid=
myFunction({ItemNo[1]})&format=l&imagenumber=1
and if my logic is correct, it should work. I'm using WP All Import to import XML data.
How do I create a function that will manipulate the string based on both instances above and output the results I'm trying to achieve?
Ok - based on the responses, I've solved the first instance to get the correct url to display - $content being the ItemNo
<?php
function ItemNoPart1 ( $content ) {
$content1 = explode("-", $content);
return $content1[0];
}
function ItemNoPart2 ( $content ) {
$content2 = explode("-", $content);
return $content2[1];
}
?>
/ImageServices/image.ashx?itemid=[ItemNoPart1({ItemNo[1]})]&config=[ItemNoPart2({ItemNo[1]})]&format=l&imagenumber=1
Now I just need to figure out how to do part 2 and combine it all into 1 function.
Don't use str_replace, use explode instead:
$str = '010758-01-700';
$chunks = explode( '-', $str );
By this way, resulting $chunks is an array like this:
[0] => 010758
[1] => 01
[2] => 700
So, now you can format desired URL in this way:
$url = "/ImageServices/image.ashx?itemid={$chunks[0]}&config={$chunks[1]}&format=l&imagenumber=1"
Your desired function is this:
function myFunction( $itemID )
{
$chunks = explode( '-', $itemID );
return "/ImageServices/image.ashx?itemid={$chunks[0]}&config={$chunks[1]}";
}
... but, really you want a function for this stuff?
Read more about explode()
Here's some psuedo code that may lead you in the right direction. The idea is to build out an array that contains all of the possible pieces of data from our string.
I've used a given constant of /ImageServices/image.ashx? to split upon, as we know the URL of our endpoint.
// explode our string into multiple parts
$parts = explode('/ImageServices/image.ashx?', $str);
// we know that the string we need to parse as at the index of 1
parse_str($parts[1], $parsed);
//$wanted will contain all of the data we can possibly need.
$wanted = array($parts[0], $parsed);
This will yield an array that looks like the following:
array (
0 => '860862-L-714 ',
1 =>
array (
'itemid' => '870078',
'color' => '001',
'format' => 'l',
'imagenumber' => '1',
),
)
Now you can perform your conditionals such as when you need to look for color and create a specific URL structure:
if(array_key_exists('color', $wanted[1]){
//create our custom sting structure here.
}
Hopefully this helps.
I want to split a string such as the following (by a divider like '~##' (and only that)):
to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date
into an array containing e.g.:
to => enquiry#test.com
subject => test
text => this is body/text
date => date
I'm using php5 and I've got the following regex, which almost works, but there are a couple of errors and there must be a way to do it in one go:
//Split the string in the url of $text at every ~##
$regexp = "/(?:|(?<=~##))(.*?=.*?)(?:~##|$|\/(?!.*~##))/";
preg_match_all($regexp, $text, $a);
//$a[1] is an array containing var1=content1 var2=content2 etc;
//Now create an array in the form [var1] = content, [var2] = content2
foreach($a[1] as $key => $value) {
//Get the two groups either side of the equals sign
$regexp = "/([^\/~##,= ]+)=([^~##,= ]+)/";
preg_match_all($regexp, $value, $r);
//Assign to array key = value
$val[$r[1][0]] = $r[2][0]; //e.g. $val['subject'] = 'hi'
}
print_r($val);
My queries are that:
It doesn't seem to capture more than 3 different sets of parameters
It is breaking on the # symbol and so not capturing email addresses e.g. returning:
to => enquiry
subject => test
text => this is body/text
I am doing multiple different regex searches where I suspect I would be able to do one.
Any help would be really appreciated.
Thanks
Why are you using regex when there is much simple method to do this by explode like this
$str = 'to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date';
$array = explode('~##',$str);
$finalArr = array();
foreach($array as $val)
{
$tmp = explode('=',$val);
$finalArr[$tmp['0']] = $tmp['1'];
}
echo '<pre>';
print_r($finalArr);
I have a string that looks like this:
[2005]
one
two
three
[2004]
six
What would be the smoothest was to get an array from it that would look like this:
array(
['2005'] => "one \n two \n three",
['2005'] => "six",
)
... or maybe even get the inner array sliced into lines array...
I tried doing it with preg_split, which worked but didn't give associative array keys so I didn't have the year numbers as keys.
Is there any cool way of doing this without iterating through all the lines ?
/(\[[0-9]{4}\])([^\[]*)/ will give you the date and whatever is after until the next one.
Use the groups to create your array: With preg_match_all() you get a $matches array where $matches[1] is the date and $matches[2] is the data following it.
Using Sylverdrag's regex as a guide:
<?php
$test = "[2005]
one
two
three
[2004]
six";
$r = "/(\[[0-9]{4}\])([^\[]*)/";
preg_match_all($r, $test, $m);
$output = array();
foreach ($m[1] as $key => $name)
{
$name = str_replace(array('[',']'), array('',''), $name);
$output[ $name ] = $m[2][$key];
}
print_r($output);
?>
Output (PHP 5.2.12):
Array
(
[2005] =>
one
two
three
[2004] =>
six
)
That's slightly more complex:
preg_match_all('/\[(\d+)\]\n((?:(?!\[).+\n?)+)/', $ini, $matches, PREG_SET_ORDER);
(Could be simplified with knowing the real format constraints.)