regexp - match multiple variations of datestamp - php

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.

Related

How to extract certain words from a php string?

I have a long string like this I1:1;I2:2;I8:2;NA1:5;IA1:[1,2,3,4,5];S1:asadada;SA1:[1,2,3,4,5];SA1:[1,2,3,4,5];. Now I just want to get certain words like 'I1','I2','I8','NA1' and so on i.e. words between ':'&';' only ,and store them in array. How to do that efficiently?
I have already tried using preg_split() and it works but giving me wrong output. As shown below.
// $a is the string I want to extract words from
$str = preg_split("/[;:]/", $a);
print_r($str);
The output I am getting is this
Array
(
[0] => I8
[1] => 2
[2] => I1
[3] => 1
[4] => I2
[5] => 2
[6] => I3
[7] => 2
[8] => I4
[9] => 4
[10] =>
)
Array
(
[0] => NA1
[1] => 5
[2] =>
)
Array
(
[0] => IA1
[1] => [1,2,3,4,5]
[2] =>
)
Array
(
[0] => S1
[1] => asadada
[2] =>
)
Array
(
[0] => SA1
[1] => [1,2,3,4,5]
[2] =>
)
But I am expecting 'I8','I1','I2','I3','I4' also in seperated array with position [0]. Any help on how to do this.
You could try something like.
<?php
$str = 'I1:1;I2:2;I8:2;NA1:5;IA1:[1,2,3,4,5];S1:asadada;SA1:[1,2,3,4,5];SA1:[1,2,3,4,5];';
preg_match_all('/(?:^|[;:])(\w+)/', $str, $result);
print_r($result[1]); // Matches are here in $result[1]
You can perform a greedy match to match the items between ; and : using preg_match_all()
<?php
$str = 'I1:1;I2:2;I8:2;NA1:5;IA1:[1,2,3,4,5];S1:asadada;SA1:[1,2,3,4,5];SA1:[1,2,3,4,5];';
preg_match_all('/;(.+?)\:/',$str,$matches);
print_r($matches[1]);
Live Demo: https://3v4l.org/eBsod
One possible approach is using a combination of explode() and implode(). The result is returned as a string, but you can easily put it into an array for example.
<?php
$input = "I1:1;I2:2;I8:2;NA1:5;IA1:[1,2,3,4,5];S1:asadada;SA1:[1,2,3,4,5];SA1:[1,2,3,4,5];.";
$output = array();
$array = explode(";", $input);
foreach($array as $item) {
$output[] = explode(":", $item)[0];
}
echo implode(",", $output);
?>
Output:
I1,I2,I8,NA1,IA1,S1,SA1,SA1,.

Explode array three times

I have a string and I would like to explode with three differents patterns. The string looks like to :
country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4
I would like to get the differents parts of this two strings. The two lines are separated by a /n, the dates are separated by : and the link associated to date are separated with a ->
At the beginning I explode by the line break
$var = explode("\n", $var);
but when I tried to explode again this string, I get an error : *preg_split() expects parameter 2 to be string, array given*
How can I get the different parts ?
Thanks in advance.
Ideone link
Instead of using preg_split, consider using preg_match. You can write it as one big regex.
<?php
// Implicit newline. Adding \n would make an empty spot in the array
$str = "country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4";
$arr = split("\n", $str);
for ($i = 0; $i < count($arr); $i++) {
preg_match("/^(\w+)\:(\d\d\/\d\d\/\d\d)->(\w+)\:(\d\d\/\d\d\/\d\d)->(\w+)/", $arr[$i], $matches);
print_r($matches);
}
?>
Output:
Array
(
[0] => country:00/00/00->link:00/00/00->link2
[1] => country
[2] => 00/00/00
[3] => link
[4] => 00/00/00
[5] => link2
)
Array
(
[0] => country2:00/00/00->link3:00/00/00->link4
[1] => country2
[2] => 00/00/00
[3] => link3
[4] => 00/00/00
[5] => link4
)
EDIT
In your comment, you're posting dates with 4 digits, whereas in your question, they only had 2 digits.
Therefore you need to change the regex to:
/^(\w+)\:(\d\d\/\d\d\/\d\d\d\d)->(\w+)\:(\d\d\/\d\d\/\d\d\d\d)->(\w+)/
How about using preg_match_all:
<?php
$data =<<<ENDDATA
country:00/00/00->link:00/00/00->link2
country2:00/00/00->link3:00/00/00->link4
ENDDATA;
preg_match_all('#(\d{2}/\d{2}/\d{2})->(.[^:\n]+)#', $data, $matches);
print_r($matches);
Gives the following result:
Array
(
[0] => Array
(
[0] => 00/00/00->link
[1] => 00/00/00->link2
[2] => 00/00/00->link3
[3] => 00/00/00->link4
)
[1] => Array
(
[0] => 00/00/00
[1] => 00/00/00
[2] => 00/00/00
[3] => 00/00/00
)
[2] => Array
(
[0] => link
[1] => link2
[2] => link3
[3] => link4
)
)
your problem is that after using explode first time, it is turning into an array and explode function connat explode an array. You need to use a loop probablr for loop that targets array elemets then use explode function on those elements and you will have it.
See example Below:
<?php
$val="abc~~~def~~~ghi####jkl~~~mno~~~pqr###stu~~~vwx~~~yz1";
$val=explode("####", $val);
//result will be
$valWillBe=array(3) {
[0]=>'abc~~~def~~~ghi',
[1]=>'jkl~~~mno~~~pqr',
[2]=>'stu~~~vwx~~~yz1'
}
//if you want to explode again you use a loop
for($r=0; $r<sizeof($val); $r++){
$val[$r]=explode("~~~", $val[$r]);
}
//now you have your string exploded all in places.
?>

PHP REGEX separate by different criteria

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.

help using php explode () and organizing output

Can someone pls show me how to map this correctly? I am trying to understand how to use php explode() and organizing the values in a way that I can retrieve and print them in some organized matter. For each record I want to put a name=value in a particular bucket. I have (7) max buckets per record. Sometimes I have records that won't fill each bucket.
(for example record (2) is missing attributes (5,6,7) and record (3) is missing attribute (4)).
1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=db9.nfl.colo2.;4-Column=00:00:03;5-Column=01:55:02;6-Column=87.24 MB;7-Column=Success;
1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=pdb2.colo2.;4-Column=04:00:02;
1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=gl3_lvm;5-Column=04:48:06;6-Column=54.64 MB;7-Column=Success;
So far I wrote this to view my output:
<?php
$InputFile = file("test.txt");
foreach ($InputFile as $line){
$pieces = explode(";", $line);
//print $pieces[0];
//print $pieces[1];
//print $pieces[2];
print $pieces[3];
//print $pieces[4];
//print $pieces[5];
//print $pieces[6];
//print_r($line);
}
?>
I would like to print out similar values for each attribute instead of this where its mixed.
Using 'print $pieces[3];'
4-Column=00:00:034-Column=04:00:025-Column=04:48:06
$InputFile = file("test.txt");
foreach ($InputFile as $line){
preg_match('~(1-Column[^;]*;?)?(2-Column[^;]*)?;?(3-Column[^;]*)?;?(4-Column[^;]*)?;?(5-Column[^;]*)?;?(6-Column[^;]*)?;?(7-Column[^;]*)?;?~',$line,$pieces);
$pieces = array_pad($pieces,8,'');
echo "<pre>";print_r($pieces);echo "</pre>";
}
output:
Array
(
[0] => 1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=db9.nfl.colo2.;4-Column=00:00:03;5-Column=01:55:02;6-Column=87.24 MB;7-Column=Success;
[1] => 1-Column=host1.colo.sub;
[2] => 2-Column=Fri Aug 13
[3] => 3-Column=db9.nfl.colo2.
[4] => 4-Column=00:00:03
[5] => 5-Column=01:55:02
[6] => 6-Column=87.24 MB
[7] => 7-Column=Success
)
Array
(
[0] => 1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=pdb2.colo2.;4-Column=04:00:02;
[1] => 1-Column=host1.colo.sub;
[2] => 2-Column=Fri Aug 13
[3] => 3-Column=pdb2.colo2.
[4] => 4-Column=04:00:02
[5] =>
[6] =>
[7] =>
)
Array
(
[0] => 1-Column=host1.colo.sub;2-Column=Fri Aug 13;3-Column=gl3_lvm;5-Column=04:48:06;6-Column=54.64 MB;7-Column=Success;
[1] => 1-Column=host1.colo.sub;
[2] => 2-Column=Fri Aug 13
[3] => 3-Column=gl3_lvm
[4] =>
[5] => 5-Column=04:48:06
[6] => 6-Column=54.64 MB
[7] => 7-Column=Success
)
If your input data is so irregular you would either need to parse it with a bit more code, not just a simple explode, or prepare it so that it works as expected with explode.
In the second case, you could use strpos to find all ";" characters in the string and check if the number after them is in order. If one (or more) number was skipped you should compensate by inserting another ";". This way explode will create an empty array element and all your resulting arrays should be aligned.
While it's not exactly clear what you're trying to accomplish, hopefully this code might help you figure out what's going on.
Note that here, I've added another loop inside the main foreach, to iterate over each name/value pair in the line:
<?php
$InputFile = file("test.txt");
$lineCnt = 0;
foreach ($InputFile as $line){
$lineCnt++;
echo "Processing line #" . $lineCnt. "\n";
$pieces = explode(";", $line);
foreach($pieces as $pair){
$pair = explode('=',$pair);
if (!empty($pair[1])){
print "\t".$pair[0] .' = ' . $pair[1] . "\n";
}
}
}
The script will produce nice-looking output if run from the command-line. If you're running it in the browser, you might want to change the \n's to , and the \t's to or something.
See if this helps...
$splits = explode(';',$_POST['data']);
foreach($splits as $id => $item) {
preg_match('/(.*?)=(.*)/',$item, $matches);
$parts[$matches[1]][] = $matches[2];
}
print_r($parts);
This will give you an array with keys as 1-Column, 2-Column as so on which will contain an array of related value. You can print this array in whatever way you want.
Here is the output:
[1-Column] => Array
(
[0] => host1.colo.sub
[1] => host1.colo.sub
[2] => host1.colo.sub
)
[2-Column] => Array
(
[0] => Fri Aug 13
[1] => Fri Aug 13
[2] => Fri Aug 13
)
[3-Column] => Array
(
[0] => db9.nfl.colo2.
[1] => pdb2.colo2.
[2] => gl3_lvm
)
[4-Column] => Array
(
[0] => 00:00:03
[1] => 04:00:02
)
[5-Column] => Array
(
[0] => 01:55:02
[1] => 04:48:06
)
[6-Column] => Array
(
[0] => 87.24 MB
[1] => 54.64 MB
)
[7-Column] => Array
(
[0] => Success
[1] => Success
)

Problem with simple regular expression in PHP

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.

Categories