The best way to explain my problem is to just show you.
Input String:
/04-11-2010/12:45/
Regular Expression to get date and time parts:
preg_match('#/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d):(\d\d)/#', $input, $matches);
PHP Matches Array:
Array
(
[0] => /01-11-2010/12:45/
[1] => 01
[2] => 11
[3] => 2010
[4] => 12
[5] => 45
)
Now the above regex works perfectly at getting the individual component parts that represent the date and time in the input string.
The problem is that the time part needs to be optional without bringing down the entire regular expression.
Problem Input String:
/04-11-2010//
PHP Matches Array
Array
(
)
Basically what I need to be returned by the matches array is:
Array
(
[0] => /01-11-2010/12:45/
[1] => 01
[2] => 11
[3] => 2010
[4] =>
[5] =>
)
Note array elements 4 and 5 still need to exist but return empty.
Use the question mark operator and a non-capturing group to make stuff optional.
#/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/#
I'm not sure how this interacts with the match array - if having the empty array elements is absolutely critical, you might need to instead go for
#/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/#
Which has its own false-positives (the colon in the time is now optional).
Make the second part optional:
'#/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/#'
Here a non-capturing group (?:…) is used that cannot be referenced and thus doesn’t change the matching groups.
#/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/#
does what you want (i.e. populates groups 4 and 5), but also accepts incomplete times like in
/04-11-2010/12:/
don't know if this is fine with you
I'm not a php-head, but how about:
preg_match('#/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d)?:?(\d\d)?/#', $input, $matches);
As far as regexps go, that should match a string that has no time field.
#OP, don't need messy regex.
$str="/04-11-2010/12:45/";
$s = array_filter(explode('/',$str));
$date=$s[1];
$time=$s[2];
$date_parts=explode("-",$date);
$time_parts=explode(":",$time);
if ( checkdate($date_parts[1],$date_parts[0],$date_parts[2]) ){
print "date ok\n";
}
Use native PHP functions for this task, using regular expressions is a bit of an overkill.
PHP 5 has the date_parse function:
$string = '/04-11-2010/12:45/';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);
$string = '/04-11-2010//';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);
Output:
Array
(
[year] => 2010
[month] => 11
[day] => 4
[hour] => 12
[minute] => 45
[second] => 0
[fraction] => 0
[warning_count] => 0
[warnings] => Array
(
)
[error_count] => 0
[errors] => Array
(
)
[is_localtime] =>
)
Array
(
[year] => 2010
[month] => 11
[day] => 4
[hour] =>
[minute] =>
[second] =>
[fraction] =>
[warning_count] => 0
[warnings] => Array
(
)
[error_count] => 0
[errors] => Array
(
)
[is_localtime] =>
)
PHP 5.3 has a more flexible date_parse_from_format function that you could also use.
Related
I have an array which contains some words. I want to get all words as unique part. so when I come to a whitespace , it's broken to a new. I mean , finally I want something like this:
$output[0]='Aug',
$output[1]='20',
$output[2]='2016'
first I want to explode it , then trim between words . this is my code but unfortunately doesn't work.Aug 20 come together. I want them individually.
<?php
$firs_arr=new array();
$first_arr='Aug 20, 2016 ';
$second=explode(',',$first_arr);
$output=array_map('trim',$second);
If you call your source $source, then $result below is the array you want:
//split into parts separated by all non-word characters
$result = preg_split('/\W+/',trim($source));
Live demo
John John:
You can have a complete array with all the information of a given date inside a string, with the function date_parse: http://php.net/manual/en/function.date-parse.php
Code:
$first_arr='Aug 20, 2016 ';
print_r(date_parse($first_arr));
Output:
Array ( [year] => 2016 [month] => 8 [day] => 20 [hour] => [minute] => [second] => [fraction] => [warning_count] => 0 [warnings] => Array ( ) [error_count] => 0 [errors] => Array ( ) [is_localtime] => )
You can also try it:
<?php
function replaceComma($var){
return str_replace(',','',trim($var));
}
$first_arr='Aug 20, 2016 ';
$second=explode(' ',trim($first_arr));
$second=array_map('replaceComma',$second);
var_dump($second);
?>
array_map and trim can do the job
$trimmed_array=array_map('trim',$first_array);
print_r($trimmed_array);
I need to match multiple variations of a datestamp
$test = array(
'01-05-2011',
'01-05-11',
'01.12.2012',
'30042016'
);
$date_day_pattern = '01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31';
$date_year_pattern = '(?:20)?10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30';
$date_pattern = "(?<!\d)($date_day_pattern)[^\d\n]?($date_day_pattern)[^\d\n]?($date_year_pattern)(?!\d)";
foreach($test as $input){
preg_match("/$date_pattern/", $input, $matches);
print_r($matches);
}
http://www.tehplayground.com/#R1sjJxFho
This shortened regex should work for your examples:
$test = array(
'01-05-2011',
'01-05-11',
'01.12.2012',
'30042016'
);
$date_pattern =
'/\b(0[1-9]|[12][0-9]|3[01])([.-]?)(0[1-9]|1[0-2])\2((?:20)?(?:[12][0-9]|30))\b/';
foreach($test as $input){
echo $input."\n";
preg_match($date_pattern, $input, $matches); print_r($matches);
}
Though you should consider using date parsing functions such as strtotime for proper date validations and parsing.
Output:
01-05-2011
Array
(
[0] => 01-05-2011
[1] => 01
[2] => 05
[3] => 2011
)
01-05-11
Array
(
[0] => 01-05-11
[1] => 01
[2] => 05
[3] => 11
)
01.12.2012
Array
(
[0] => 01.12.2012
[1] => 01
[2] => 12
[3] => 2012
)
30042016
Array
(
[0] => 30042016
[1] => 30
[2] => 04
[3] => 2016
)
I have written a pattern that should work. It looks slightly different than yours, but matches every case you have described there and fails in any other case.
'(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[01])-(?:20)?(?:[1-2][0-9]|30))|(?:(?:0[1-9]|[1-2][0-9]|3[[01]])(\.?)(?:0[1-9]|1[0-2])(\1)20(?:[1-2][0-9]|30))'
Explanation:
I have combined case1&2 and case3&4 and have written a pattern for each of those and merged them together with a logical or. The code is pretty straightforward, the only noteworthy thing is the backreference in the second part that is used to allow two dots/no dots and not a mixture.
I'm working on some data loaded from an Excel file using PHPExcel. Everything is working fine with every fields but I'm having some troubles with a field which should contain a pattern.
The pattern is
(([0-2]?[0-9]\:[0-5]?[0-9]\:([0-5]?[0-9])\/([0-2]?[0-9]\:[0-5]?[0-9]\:([0-5]?[0-9])))\s?)*
that should check for time intervals such as "00:30:45/01:40:12 01:10:34/1:07:12" and so on.
My problem is that preg_match fails to check this pattern against the sting "1:00". If I add a variable to store the matches returns an one element array with the value "".
I check the pattern with an online tool (http://regexpal.com/) and work as expected but for an to me unknown reason, preg_match doesn't.
Is there something I am missing?
try this
<?php
$string = "00:30:45/01:40:12 01:10:34/1:07:12";
preg_match_all('!((\d{1,2}:\d{1,2}:\d{1,2}/(\d{1,2}:\d{1,2}:(\d{1,2}))))\s?!', $string, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";
you need to get this:
array (
0 =>
array (
0 => '00:30:45/01:40:12 ',
1 => '01:10:34/1:07:12',
),
1 =>
array (
0 => '00:30:45/01:40:12',
1 => '01:10:34/1:07:12',
),
2 =>
array (
0 => '00:30:45/01:40:12',
1 => '01:10:34/1:07:12',
),
3 =>
array (
0 => '01:40:12',
1 => '1:07:12',
),
4 =>
array (
0 => '12',
1 => '12',
),
)
demo
<?php
$str = '00:30:45/01:40:12 01:10:34/1:07:12/1:00';
//$str = '1:00';
$p = '/[0-9]+:[0-9]+(:[0-9]+|)/s';
preg_match_all($p, $str, $m);
print_r($m);
outputs
Array
(
[0] => Array
(
[0] => 00:30:45
[1] => 01:40:12
[2] => 01:10:34
[3] => 1:07:12
[4] => 1:00
)
[1] => Array
(
[0] => :45
[1] => :12
[2] => :34
[3] => :12
[4] =>
)
)
I finally managed to fix this up. After taking a break and come again to the code with a clear mind, I noticed the final '*' should by a '+' in order to force to have, at least, one instance of the time interval.
Thank you all for your responses.
I'm trying to separate some strings by different criteria but I can't get the desired results.
Here are 3 examples:
$ppl[0] = "Balko, Vlado \"Panelбk\" (2008) {Byt na tretom (#1.55)}";
$ppl[1] = "'Abd Al-Hamid, Ja'far A Two Hour Delay (2001)";
$ppl[2] = "'t Hoen, Frans De reьnie (1963) (TV)";
I'm currently using this for the last 2:
$pattern = '#,|\t|\(#'
But I will get and empty space.
result:
Array ( [0] => 'Abd Al-Hamid [1] => Ja'far [2] => A Two Hour Delay [3] => 2001) )
Array ( [0] => 't Hoen [1] => Frans [2] => [3] => De reünie [4] => 1963) [5] => TV) )
As for the 1st expression I used another pattern but I still get empty spaces. Any ideas?
EDIT:
Thanks this helped indeed. I tried using a modified version on the first string:
$pattern4 = '#[",\t]+|[{}]+|[()]+#';
However I still get an empty space:
Array ( [0] => Balko [1] => Vlado [2] => Panelák [3] => [4] => 2008 [5] => [6] => Byt na tretom [7] => #1.55 [8] => [9] => )
What should I do? I think that the " and the brackets are causing the problem but I don't know how to fix it.
I would surmise you have two tabs as separator in your second and third example string. (Can't see that here, the SO editor converts them into spaces).
But you could adapt your regex slightly in that case:
$pattern = '#,|\t+|\(#'
Or simpler even:
$pattern = '#[,\t(]+#'
And the alternatve, btw, would be just applying array_filter() on the result arrays to remove the empty entries.
This is what i've got now:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 53
[date] => 18 Sep 2010 10:29
[user] => 52
[post] => ytiuy
)
[1] => Array
(
[id] => 55
[date] => 11 Sep 2010 11:14
[user] => 52
[post] => this is a test post :]
)
)
[1] => Array
(
[0] => Array
(
[id] => 56
[date] => 4 Sep 2010 03:19
[user] => 55
[post] => pppost :DD:D:D:D
)
)
)
I want to remove the first two "steps" in the array, and then sort the array by the 'date' value, like this:
Array
(
[0] => Array
(
[id] => 56
[date] => 4 Sep 2010 03:19
[user] => 55
[post] => pppost :DD:D:D:D
)
[1] => Array
(
[id] => 55
[date] => 11 Sep 2010 11:14
[user] => 52
[post] => this is a test post :]
)
[2] => Array
(
[id] => 53
[date] => 18 Sep 2010 10:29
[user] => 52
[post] => ytiuy
)
)
Any ideas?
Thanks a bunch, appreciate all help! :)
EDIT: I should also mention that the amount of arrayitems will not always be the same.
You should be able to use an accumulator pattern with the array_merge function to merge all the lower level arrays together.
$result = array();
foreach ($oldarray as $child)
{
$result = array_merge($result, $child);
}
Finally, you can use the user defined sort function to sort the whole thing.
An alternative to Don Kirby's solution would be to use an SplMaxHeap which would allow you to iterate and sort in one go:
class PostHeap extends SplMaxHeap
{
public function compare($post, $other)
{
return strtotime($post['date']) - strtotime($other['date']);
}
}
$postHeap = new PostHeap;
foreach($posts as $subArray) {
foreach($subArray as $post) {
$postHeap->insert($post);
}
}
The $postHeap would then contain the posts in descending date order, e.g. newest date first. You can use the code in the compare function if you want to use usort instead. The order will be ascending then though.
Do you have two arrays? Or more? Are they already sorted? If so, you can use that to combine them more efficiently. If not, you probably need to sort them first.
Roughly:
Sort your input arrays (optionally)
Scan your input arrays for the lowest value, copy that value into your new array, delete the value from the input array.
Repeat until all your input arrays are empty.
Of course, if you don't care about performance at all you could simply combine all the arrays and then sort that.
And for sorting you may want to use: http://www.php.net/manual/en/function.sort.php#99700
#Don Kirkby: Indeed: It's basically a mergesort, but it only works on already sorted arrays. If they're both unsorted you're probably better off with combining them and using quicksort instead.