Use RegEx to get (parsed) times from string - php

I need some direction on how to alter my current RegEx line.
Example string:
9:00 AM - 9:30 AM
Desired output:
900 930 (each can be an index in an array or whatever)..
Current approach:
preg_match('/^([0-9]{1,2}):([0-9]{1,2}) ?([ap]m)/i', trim($presentationtime), $matches);
however this only seems to get me the FIRST (stripped/parsed) time.
results:
$presentationtime = $matches[1] . $matches[2];
echo 'Matches check: '. $matches[0] . '<br>';
echo 'Matches check: '. $matches[1] . '<br>';
returns:
Matches check: 9
Matches check: 00
How can I alter my regex to get BOTH times (stripped/parsed the same way)..
I'm expecting a 6 index array..but can only get a 3 index/count array

as #anubhava says use preg_match_all
$presentationtime = '9:00 AM - 9:30 AM';
preg_match_all('/([0-9]{1,2}):([0-9]{1,2}) /', trim($presentationtime), $matches);
print_r($matches);
results:
Array
(
[0] => Array
(
[0] => 9:00
[1] => 9:30
)
[1] => Array
(
[0] => 9
[1] => 9
)
[2] => Array
(
[0] => 00
[1] => 30
)
)
Edit to answer the comment:
very lazy workaround to get one dimensional array, banal regex
$presentationtime = '9:00 AM - 9:30 PM';
preg_match('/([0-9]{1,2}):([0-9]{1,2})\s([apm]+)\s-\s([0-9]{1,2}):([0-9]{1,2})\s([apm]+)/i', trim($presentationtime), $matches);
result
Array
(
[0] => 9:00 AM - 9:30 PM
[1] => 9
[2] => 00
[3] => AM
[4] => 9
[5] => 30
[6] => PM
)

You have to simply use preg_match_all (as stated by anubhava in the comment) and remove the ^ at the start of the regex:
preg_match_all('/([0-9]{1,2}):([0-9]{1,2}) ?([ap]m)/i', trim($presentationtime), $matches);
Then $matches will be like:
Array
(
[0] => Array
(
[0] => 9:00 AM
[1] => 9:30 AM
)
[1] => Array
(
[0] => 9
[1] => 9
)
[2] => Array
(
[0] => 00
[1] => 30
)
[3] => Array
(
[0] => AM
[1] => AM
)
)
If you want to refine the regex you may use:
preg_match('/([0-9]{1,2}):([0-5]\d)\s*([ap]m)/i', trim($presentationtime), $matches);
The minute section is will match 2 digits from 00 to 59, the space section \s* is optional and matches more than one whitespace char (space, tab, CR, FF...)

One way of doing that:
$data = '9:00 AM - 9:30 AM';
print str_replace('-', ' ', preg_replace("/[^0-9-]/","", $data));
Result:
900 930
keep digits and dash
replace dash with space
In the previous example, I was using limited regex with preg_replace. To keep things simple and using time with AM/PM, I'd just explode (as you already thought about),
$data = '9:00 AM - 9:30 PM';
$timeArray = array_map('trim', explode('-', $data)); // trim each array item
$timeArray = array_map('Time24Hr', $timeArray); // clean up time
print_r($timeArray);
function Time24Hr($time) {
$time_ampm = explode(' ', $time);
if (strtolower(trim($time_ampm[1])) === 'am') {
// A
return $time_ampm[0];
// B
//return str_replace(':', '', $time_ampm[0]);
// C
//return $time;
}
$hr_min = explode(':', trim($time_ampm[0]));
// A
return ($hr_min[0] + 12) . ':' . $hr_min[1];
// B
//return ($hr_min[0] + 12) . $hr_min[1];
// C
//return ($hr_min[0] + 12) . ':' . $hr_min[1]. ' ' . $time_ampm[1];
}
Results:
Result A:
Array
(
[0] => 9:00
[1] => 21:30
)
Result B:
Array
(
[0] => 900
[1] => 2130
)
Result C: -- obviously this is insane, but you can easily make it sane. This is just an example
Array
(
[0] => 9:00 AM
[1] => 21:30 PM
)
Of course, this simplistic method can be streamlined much further. This method doesn't need regex.

Related

Get two words (numbers) around a certain text in a string

There's a certain contents (from a webpage) where I need to get two numbers of a certain list.
Basically the list goes like:
..... 10 from 12....
..... 1 from 20....
..... 20 from 100...
and so on. For me, I need to get these numbers surrounding the word "from", so I can perform certain calculations with them later.
I looked into this and tried different ways to perform it with strpos or strstr but nothing worked. Does anyone have any idea how to accomplish something like that?
$text = "..... 10 from 12 etc....
..... 1 from 20....
..... 20 from 100...";
$r = preg_match_all('~(\d+) *from *(\d+)~u',$text,$match, PREG_SET_ORDER);
var_export($match);
Output:
array (
0 =>
array (
0 => '10 from 12',
1 => '10',
2 => '12',
),
1 =>
array (
0 => '1 from 20',
1 => '1',
2 => '20',
),
2 =>
array (
0 => '20 from 100',
1 => '20',
2 => '100',
),
)
Explanations:
\d+ one digit or more
(\d+) the sequence in brackets -> the digits in the result array
* no, one or more spaces
from the word from
Here is an example of what you can do with explode:
<?php
/* the text with many different gaps and mess! */
$text = "wlfsdjf;sd sdfljsdfk kfgjdlg d 10 from 200 kflgjdkgdklgsd slfksjd
dfgdf fgdlkjdf d 20 from 30 ldk;lfsd
dflksdjf 40 from 50 dkf;sd sdjfs ";
/* main array */
$array = explode("\n",$text);
echo '<pre>';
print_r($array);
/* looping and clearing out our values per line */
foreach($array as $k => $line){
$f = explode(" ",explode(" from ",$line)[0]);
$f = array_pop($f);
$numbers[$k]['first'] = $f;
$s = explode(" ",explode(" from ",$line)[1]);
$s = $s[0];
$numbers[$k]['second'] = $s;
}
/* our new array set per line */
print_r($numbers);
Will return:
Array
(
[0] => wlfsdjf;sd sdfljsdfk kfgjdlg d 10 from 200 kflgjdkgdklgsd slfksjd
[1] => dfgdf fgdlkjdf d 20 from 30 ldk;lfsd
[2] => dflksdjf 40 from 50 dkf;sd sdjfs
)
Array
(
[0] => Array
(
[first] => 10
[second] => 200
)
[1] => Array
(
[first] => 20
[second] => 30
)
[2] => Array
(
[first] => 40
[second] => 50
)
)

php detect and convert dates from a string

I was wondering if I could somehow to detect a date in a string and convert it into a standard date format.
Let's consider the input strings below:
Company registered on 16 March 2003
or
Activity between 10 May 2006 an 10 July 2008 - no changes.
Now I would like a PHP function to apply over the strings and get the dates as YYYY-mm-dd
Example:
$date = DateExtract($sting1); // output: 2003-03-16
$date = DateExtract($sting2); // output: ['2006-05-10','2008-07-10']
For finding first two digit number Date Regexp would be - (?<![0-9])[0-9]{2}(?![0-9]) This can also be apply to four digit for Year also and for Month you can use hard-coded string search code.
$string = "Activity between 10 May 2006 an 10 July 2008 - no changes.";
preg_match_all('/(\d{1,2}) (\w+) (\d{4})/', $string, $matches);
print_r($matches);
Output :
Array
(
[0] => Array
(
[0] => 10 May 2006
[1] => 10 July 2008
)
[1] => Array
(
[0] => 10
[1] => 10
)
[2] => Array
(
[0] => May
[1] => July
)
[3] => Array
(
[0] => 2006
[1] => 2008
)
)
Updates
For find Complete Date in string you can use this -
It works for short code for Month like Jan and complete name like January also.
Code:
$string = "Activity between 10 May 2006 an 10 July 2008 - no changes.";
preg_match_all('/(\b\d{1,2}\D{0,3})?\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|(Nov|Dec)(?:ember)?)\D?(\d{1,2}\D?)?\D?((19[7-9]\d|20\d{2})|\d{2})/', $string, $complete);
print_r($complete);
Result:
Array
(
[0] => Array
(
[0] => 10 May 2006
[1] => 10 July 2008
)
[1] => Array
(
[0] => 10
[1] => 10
)
[2] => Array
(
[0] =>
[1] =>
)
[3] => Array
(
[0] => 20
[1] => 20
)
[4] => Array
(
[0] => 06
[1] => 08
)
[5] => Array
(
[0] =>
[1] =>
)
)
So you can fetch complete date form here and convert it into standard date format.
Demo Here
Tricky. One approach might be to reason that dates always appear after certain grammatical words, as shown in your examples, e.g. "between", "on" etc. Using such words as a beginning anchor, we would then match until we find what we can reasonably assume to be the end of the date string. Here's what I hacked together:
//some strings
$strs = [
"Company was in business between 14 March 2008 and 21 November 2012 inclusive",
"I was born on 29 May 1980, 17:37 - it was a Thursday",
"The big bang did not occur at 2pm, 14 Jun 1971, that's for sure."
];
//container to store possible date matches from strings
$possible_dates = array();
//prep months - long and short forms, to be used in matching
$date_prefix_words = array('between', 'on', 'at', 'during', 'and');
$months = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
$months_short = array_map(function($month) { return substr($month, 0, 3); }, $months);
//iterate over and search strings - convert times like 2pm to 14:00, as, if they appear before the date, e.g. string 3, it doesn't get parsed
foreach($strs as $str) {
$str = preg_replace_callback('/\b\d{1,2}[ap]m\b/', function($time) { return date('H:i', strtotime($time[0])); }, $str);
preg_match_all('/(?<=\b'.implode('\b( |:)|\b', $date_prefix_words).'\b( |:))(\d|am|pm| |,|\'|:|'.implode('|', $months).'|'.implode('|', $months_short).')+/i', $str, $matches);
if (count($matches)) $possible_dates = array_merge($possible_dates, $matches[0]);
}
//output before and after results
foreach($possible_dates as &$pd) {
$pd = preg_replace('/, ?$/', '', $pd);
echo '<p>Before: '.$pd.'<br />After: '.date('Y-m-d', strtotime($pd)).'</p>';
}
Clearly I'm making certain assumptions about your date formats, and you may need to tweak the REGEX, but it sort of works.
First of all You have to extract all part of date from the string separately.
RegEx Demo
First approach:
<?php
function standard_date_format($str) {
preg_match_all('/(\d{1,2}) (\w+) (\d{4})/', $str, $matches);
foreach ( $matches[1] as $day ) { $days [] = $day; }
foreach ( $matches[2] as $month ) { $months[] = $month; }
foreach ( $matches[3] as $year ) { $years [] = $year; }
$all_months = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
for ($i = sizeof ($days) - 1; $i >= 0; $i--) {
$month = array_search ($months[$i], $all_months) + 1;
$month = strlen ($month) < 2 ? '0'.$month : $month;
$results[] = $years[$i] . '-' . $month . '-' . $days[$i];
}
return $results;
}
$str1 = "Company registered on 16 March 2003";
$str2 = "Activity between 10 May 2006 an 10 July 2008 - no changes.";
print_r(standard_date_format($str1)); // output: 2003-03-16
print_r(standard_date_format($str2)); // output: ['2006-05-10','2008-07-10']
PHP Demo
Second approach:
<?php
function standard_date_format($str) {
preg_match_all('/(\d{1,2}) (\w+) (\d{4})/', $str, $matches);
$dates = array_map("strtotime", $matches[0]);
$result = array_map(function($v) {return date("Y-m-d", $v); }, $dates);
return $result;
}
$str1 = "Company registered on 16 March 2003";
$str2 = "Activity between 10 May 2006 an 10 July 2008 - no changes.";
print_r(standard_date_format($str1)); // output: 2003-03-16
print_r(standard_date_format($str2)); // output: ['2006-05-10','2008-07-10']
PHP Demo

Using regular expressions to match a time interval

I'm having problems on how to preg_match this time statement.
TF 02:30 pm-04:00 am
I was able to separate the time into the array but I also want to get the AM and PM as well as the letter T and F.
This is for a class schedule module that I am working on. The data I got from the database is that string. I want to separate them so that I can manipulate the entries for the calendar that I have.
Here's what I have at this point.
$sampleString = 'T 02:30 pm-04:00 am';
$pattern = '/([0-1]?\d|2[0-9]):([0-5]?\d)/';
preg_match_all($pattern,$sampleString,$time);
print_r($time);
The output:
Array (
[0] => Array (
[0] => 02:30
[1] => 04:00 )
[1] => Array (
[0] => 02
[1] => 04 )
[2] => Array (
[0] => 30
[1] => 00 )
)
Thanks.
As recommended by IMSoP, splitting this up into parts makes it easier (looking again, I think your hour regex could use improvement, as it will accept hours from 0-29, I've changed it to 0?[1-9]|1[0-2] instead, to accept only 1 - 12)
Days: [MTWHFS]+
Space: \s
Hour: 0?[1-9]|1[0-2]
Colon: :
Minute: [0-5]?\d
Space: \s
am/pm: [ap]m
hyphen: -
Hour: 0?[1-9]|1[0-2]
Colon: :
Minute: [0-5]?\d
Space: \s
am/pm: [ap]m
Then just put them together, surrounding the desired capturing groups with parentheses:
([MTWHFS]+)\s(0?[1-9]|1[0-2]):([0-5]?\d)\s([pa]m)-(0?[1-9]|1[0-2]):([0-5]?\d)\s([pa]m)

match a string with an array of values and return the key

so i have an array with months:
$arr_month = array(
1=>'january',
2=>'february',
3=>'march',
4=>'april',
5=>'may',
6=>'june',
7=>'july',
8=>'august',
9=>'september',
10=>'october',
11=>'november',
12=>'december'
);
i also have strings (i know, they look weird...) that look like:
23 de january del 2003
12 de may de 1976
6 de february de 1987
What i want is to find and match the month in the string with the array and return the array key.
so:
23 de january del 2003 returns 1
12 de may de 1976 returns 5
6 de february de 1987 returns 2
and so on...
Any idea how?
This should work for you.
$dateString = "23 de january del 2003"; // as an example
$exploded = explode (" ", $dateString); // separate the string into an array of words
$month = $exploded[2]; // we want the 3rd word in the array;
$key = array_search ($month, $arr_month); // lets find the needle in the haystack
print $key;
yields 1.
See http://php.net/manual/en/function.array-search.php for more.
$index = -1;
foreach ($arr_month as $k => $v) {
if (strstr($mystring, $v)) {
$index = $k;
break;
}
}
// exists with $index set
You should be able to do like this:
<?php
function getMonth($time){
$matches = array();
preg_match("/[0-9] de ([a-z]+) de/", $time, $matches);
return date('n',strtotime($matches[1]));
}
?>
Then you don't even need your month array :D
EDIT if you for some reason want the array in there:
<?php
function getMonth($time){
$matches = array();
$pattern = "/[0-9] de ([a-z]+) de/";
preg_match($pattern, $time, $matches);
$month = $matches[1];
$arr_month (
1=>'january',
2=>'february',
3=>'march',
4=>'april',
5=>'may',
6=>'june',
7=>'july',
8=>'august',
9=>'september',
10=>'october',
11=>'november',
12=>'december'
);
return in_array($month, $arr_month) ? array_search($month, $arr_month) : false;
}
?>
You can do this with the optional search param with array keys:
$matchedKeys = array_keys($arr_month, "november");
var_dump($matchedKeys);
// array(1) { [0]=> int(11) }
As you can see this will return an array of all matching keys.
If you're trying to parse a date, bear in mind that PHP can do that for you (though it depends on how arbitrary your input data is - this is obviously more reliable if you know the date format in advance).
eg:
print_r(date_parse("6 de february de 1987"));
gives:
Array
(
[year] => 1987
[month] => 2
[day] =>
[hour] =>
[minute] =>
[second] =>
[fraction] =>
[warning_count] => 2
[warnings] => Array
(
[14] => Double timezone specification
[22] => The parsed date was invalid
)
[error_count] => 2
[errors] => Array
(
[0] => Unexpected character
[2] => The timezone could not be found in the database
)
[is_localtime] => 1
[zone_type] => 0
)
So it's given up on the day, but it did correctly identify the month and year.
Using the more modern DateTime api fails on your input (is that a mixture of French and English?)
But it does work for the following:
$d = new DateTime("6th february 1987", new DateTimeZone("UTC"));
print $d->format("Y-m-d H:i:s") . "\n";'
Gives:
1987-02-06 00:00:00

regex/php: parse times from string?

What is the best way to parse time from a string?
Example string: "this is 10:45 this is 10:48, 10:49, 10:50, 22:15";
Expected return:
[0] = 10:45
[1] = 10:48
[2] = 10:49
[3] = 10:50
[4] = 22:15
Thanks for any replies!!
This will give the output you want and limits your hour/minute numbers to valid values for the first position of the hour and the first position of the minute:
$y = "this is 10:45 this is 10:48, 10:49, 10:50, 22:15";
preg_match_all("/(([0-1]\d|2[0-3]):[0-5]\d)/",$y,$matches);
print_r($matches[1]);
/*
Outputs:
Array ( [0] => 10:45 [1] => 10:48 [2] => 10:49 [3] => 10:50 [4] => 22:15 )
/*
preg_match_all('/\d{2}:\d{2}/', $string, $matches);
You will have all your matches in $matches array.
That looks like a pretty simple case. try preg_match_all with "/\d\d:\d\d/"

Categories