My string looks like this 05/21/2018 ghijkl 06/12/2018 mnopqrst
I need to extract all the values after each date and include the date. I tried
explode('/2018', $string);
But that splits up the date and is also not future-proof. I'm thinking there must be a way to include the delimiter in the element. Perhaps there is also a regular expression I should be using to find the date?
Thank you.
You could use preg_split with the PREG_SPLIT_DELIM_CAPTURE and the PREG_SPLIT_NO_EMPTY flags to keep the delimiter and remove the empty values from the resulting array.
You might use a pattern that matches a date format \b\d{1,2}/\d{1,2}/\d{4}\b (Note that it matches your date format in the example data and does not validate a date itself)
For example:
$str = '05/21/2018 ghijkl 06/12/2018 mnopqrst';
$result = preg_split('#(\b\d{1,2}/\d{1,2}/\d{4}\b)#', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
var_dump($result);
Demo
To validate a date you could use DateTime and perhaps specify your format using createFromFormat.
$date = DateTime::createFromFormat("m/d/Y", '05/21/2018');
You can use current(explode('/', $string));
You can do something like this
$str = '05/21/2018 ghijkl 10/12/2017 mnopqrst';
$arr = explode(' ',$str);
$new = array();
for($i=0;$i<count($arr);$i+=2){
$new[] = ["date"=>$arr[$i],"value"=>$arr[$i+1]];
}
print_r($new);
Live Demo
Output:
Array
(
[0] => Array
(
[date] => 05/21/2018
[value] => ghijkl
)
[1] => Array
(
[date] => 10/12/2017
[value] => mnopqrst
)
)
Assuming your date is guaranteed to be formatted as you mentioned (if it's user input data, it's generally not safe to assume that), you could use a regular expression to find strings after a date:
Using a PHP regex split with the below expression:
/([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4})([a-zA-Z\s]+)/g
Will break 05/21/2018 ghijkl 10/12/2017 mnopqrst into an array with the different groups. Depending how you actually want the output data, you can capture the date and subsequent string in one match group.
Sample code:
$string = '05/21/2018 ghijkl 10/12/2017 mnopqrst';
preg_split('/([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4})([a-zA-Z\s]+)/g', $string, $stringParts);
array (
0 => '05/21/2018',
1 => 'ghijkl',
2 => '10/12/2017',
3 => 'mnopqrst'
);
https://regex101.com/r/gPXkDz/2
You could do that using regular expressions. Here's an example code:
<?php
$string = '05/21/2018 ghijkl 06/12/2018 mnopqrst';
$matches = [];
if (preg_match_all('#(\d{2}\/\d{2}\/\d{4})#i', $string, $matches) > 0) {
echo "Found the following dates: \n";
foreach ($matches[0] as $date) {
printf("- %s\n", $date);
}
}
This would result in the following output:
Found the following dates:
- 05/21/2018
- 06/12/2018
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 want to extract matched parts of strings --digital part from an array
array("HK00003.Day","HK00005.Day").
<?php
$arr=array("HK00003.Day","HK00005.Day");
$result= array();
foreach ($arr as $item){
preg_match('/[0-9]+/',$item,$match);
array_push($result,$match[0]);
}
It can get the result :00003 00005,it seems tedious,preg_grep seems simple but the result is not what i want .
preg_grep('/[0-9]+/',$arr);
The output is "HK00003.Day","HK00005.Day", not 00003 00005,
is there more simple way to get the job done?
You can use preg_filter (which already uses preg_replace and does not require additional callback functions) to replace the each entry in the array with the number inside:
<?php
$arr = array("HK00003.Day","HK00005.Day");
$matches = preg_filter('/^.*?([0-9]+).*/', '$1',$arr);
print_r($matches);
?>
Output of a sample program:
Array
(
[0] => 00003
[1] => 00005
)
This should work for you:
(Here I just get rid off every character in your array which isn't a number with preg_replace())
<?php
$arr = ["HK00003.Day", "HK00005.Day"];
$result = preg_replace("/[^0-9]/", "", $arr);
print_r($result);
?>
output:
Array ( [0] => 00003 [1] => 00005 )
Your code is fine, not tedious at all. If you want a one-liner you can try something like this (remove everything that's not a digit):
array_push($result, preg_replace("~[^0-9]~", "", $item));
preg_grep return array entries that match the pattern! Therefore, it returns an array of entry rather than the matching string
try below:
preg_match_all('/[0-9]+/',implode('-',$arr),$result);
I am returning content that is entered into a textarea separated by linebreaks, like so:
06/10/2014
06/11/2014
However, I want to avoid the fact that if a user should enter it in this way in the textbox(too many breaks leaves an empty space):
06/10/2014
06/11/2014
I would like to account for that, yet still only return the two date values and not an extra line break. The array looks like this if returning the second example:
PHP Code
$date_array = preg_split("/(\r\n|\r|\n)/", $row['blackout_date'], -1, PREG_SPLIT_NO_EMPTY);
// check for any extra returns or white spaces
print_r($date_array);
ARRAY
Array ( [0] => 06/11/2014
[1] =>
[2] => 06/12/2014 )
I want to get rid of that empty array, but array_filter does NOT work. Any suggestions? Thanks!
The way the precedence works in the alternation | in the pattern may leave stray \n or \r that is not considered empty. Try:
$date_array = preg_split("/\s+/", $row['blackout_date'], -1, PREG_SPLIT_NO_EMPTY);
In this case PREG_SPLIT_NO_EMPTY is probably not needed, but I left it to be safe.
Just use array_filter like this to get rid of the empty array values:
// Set the test data.
$test_data = <<<EOT
06/10/2014
06/11/2014
EOT;
// Check for any extra returns or white spaces.
$date_array = preg_split("/(\r\n|\r|\n)/", $test_data, -1);
// Use 'array_filer' and 'array_values' to shake out the date array.
$date_array = array_values(array_filter($date_array));
// Check the cleaned date array by dumping the data.
echo '<pre>';
print_r($date_array);
echo '</pre>';
The output would be:
Array
(
[0] => 06/10/2014
[1] => 06/11/2014
)
Or how about attacking the empty lines issue another way: Maybe you should just use preg_match_all to match the actual dates you want instead of splitting with preg_split?
// Set the test data.
$test_data = <<<EOT
06/10/2014
06/11/2014
EOT;
// Match all of the dates that match your format.
preg_match_all('/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/is', $test_data, $matches);
// Set the date array based on the dates matched.
$date_array = array_values(array_filter($matches[0]));
// Check the cleaned date array by dumping the data.
echo '<pre>';
print_r($date_array);
echo '</pre>';
And the output of that would be:
Array
(
[0] => 06/10/2014
[1] => 06/11/2014
)
preg_split() with \r\n pattern can be used to fix your issue.
$date_array = preg_split('/[\r\n]+/', $row['blackout_date'], -1, PREG_SPLIT_NO_EMPTY);
How would I use regular expression with PHP to split the following string into 2 pars as depicted below:
String to be split: 4x330ml
Split into 4x330 and ml
I have tried the following but it does not return the accurate data:
$pdata = "4x330ml"
$data = preg_split('#(?<=\d)(?=[a-z])#i', $pdata);
Then I get something like 4 in $data[0] and x330 in $data[1]
EDIT: Please note that ml could also be cm, kg, etc. A little complicated, which I don't seem to find a solution.
EDIT: Also I have tried the following regex (which I prefer to use at this point) with incomplete results:
$pdata = "5x500ml";
$data = preg_split('/(\d+\.?\d+)|(\w+)i/', $pdata);
This returns:
Array
(
[0] => 5x
[1] => ml
)
500 from that string is not being returned...
Thanks,
You said it could be ml, cm, or kg. and that you don't have to use regex. So, assuming it is always 2 characters at the end, a very simple way to do this would be:
$string = "4x330ml";
$part1 = substr($string, 0, -2); //returns 4x330
$part2 = substr($string, -2, 2); //returns "ml"
This ought to give you what you want.
$pdata = "4x330cm";
$data = preg_match('/([^(ml|cm|kg)]*)(ml|cm|kg)/', $pdata, $group);
echo $group[0].' ';
echo $group[1].' ';
echo $group[2].' ';
Use the preg_match function, and store the results into an array. The 0 index will return the entire matched string. The $group[1] will return just "4x330". The $group[2]$ will return just the "cm".
I'd use preg_match:
$pdata = "4x330ml";
preg_match('/(\d+x\d+)(.*)/',$pdata, $m);
print_r($m);
Output:
Array
(
[0] => 4x330ml
[1] => 4x330
[2] => ml
)
Assuming the units will always be 2 characters long you can use this
$pdata = "4x330ml";
$strNumber = substr($pdata, 0, strlen($pdata)-2);
$strUnit = substr($pdata, strlen($pdata)-2,2);
echo $strNumber; //returns 4x330
echo $strUnit; //returns ml
you can do this without a regex
$string = '4x330ml';
$splitPoint = strrpos($string,'m');
$firstPart = substr($string,0,$string); //gets 4x330
$secondPart = substr($string,$splitPoint); //gets ml
I was able to solve this problem by using the following code:
$data = "4x500ml";
$pdata = preg_split('/(\d+x\d+)/', $data, NULL, PREG_SPLIT_DELIM_CAPTURE);
Which now prints:
array(
[0] =>
[1] => 4x500
[2] => ml
)
It looks like it is capturing the delimeter as array[1] and since the delimeter is actually the first section of the string I want to split, it is fine for now, until I find a better solution.
Thank you all for trying.
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'];