PHP regex select word that contain specific character from string - php

000001 0001 000000000000001975 00 02 0 000 2017/12/13 14:13:27
i m developing a system with laravel.
this is the string i get from a csv file. i need to select this date and time. into an array. if i can select word that contain : (14:13:27) i can get time and same method to date.

Try this pattern:
/(\d{4}\/[^ ]+) \K([\d:]+)/
Online Demo

A simple solution would be -
$string= "000001 0001 000000000000001975 00 02 0 000 2017/12/13 44:13:27";
preg_match("/([0-9]+):([0-5][0-9]):([0-5][0-9])/", $string, $matches);
echo $matches[0];

I'm still unclear about the OP's exact desired output, but I was more-so underwhelmed by the patterns in the other answers. I'll post this battery of solutions for the betterment of Stackoverflow since I couldn't find a suitable duplicate to close with.
I'm using the tildes ~ as pattern delimiters so that the / characters in the pattern don't need to be escaped. Also, notice I am not calling \K to restart the fullstring match because there is no reason to do so.
Code: (Demo)
$string='000001 0001 000000000000001975 00 02 0 000 2017/12/13 14:13:27';
var_export(preg_match('~\d{4}/\d{2}/\d{2}~',$string,$out)?$out:[]); // date
echo "\n\n";
var_export(preg_match('~\d{2}:\d{2}:\d{2}~',$string,$out)?$out:[]); // time
echo "\n\n";
var_export(preg_match('~\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}~',$string,$out)?$out:[]); // full datetime
echo "\n\n";
var_export(preg_match('~(\d{4}/\d{2}/\d{2}) (\d{2}:\d{2}:\d{2})~',$string,$out)?$out:[]); // capture date and time
echo "\n\n";
var_export(preg_match_all('~\d{4}/\d{2}/\d{2}|\d{2}:\d{2}:\d{2}~',$string,$out)?$out:[]); // capture date or time
echo "\n\n";
var_export(preg_match('~(\d{4})/(\d{2})/(\d{2}) (\d{2}):(\d{2}):(\d{2})~',$string,$out)?$out:[]); // capture date digits and time digits
Output:
// date
array (
0 => '2017/12/13',
)
// time
array (
0 => '14:13:27',
)
full date time
array (
0 => '2017/12/13 14:13:27',
)
// capture date and time
array (
0 => '2017/12/13 14:13:27',
1 => '2017/12/13',
2 => '14:13:27',
)
// capture date or time
array (
0 =>
array (
0 => '2017/12/13',
1 => '14:13:27',
),
)
// capture date digits and time digits
array (
0 => '2017/12/13 14:13:27',
1 => '2017',
2 => '12',
3 => '13',
4 => '14',
5 => '13',
6 => '27',
)
p.s. For future readers, if you require stronger date validation than this, then regex is probably not the right tool for your task.

Related

PHP Regex Matching Multiple Options

I am attempting to write some code that looks for the following:
Yesterday
Last 7 Days
Last 30 Days
This Year
Last Year
I have the following regex:
/yesterday|(\d+)(?=\s+(\w+))|(\w+)(?=\s+(year))/i
using:
preg_match("/yesterday|(\d+)(?=\s+(\w+))|(\w+)(?=\s+(year))/i", $input, $output)
I get the following results using phpliveregex.com with the preg_match:
array(5
0 => Last
1 =>
2 =>
3 => Last
4 => Year
)
array(5
0 => This
1 =>
2 =>
3 => This
4 => year
)
array(1
0 => yesterday
)
array(3
0 => 30
1 => 30
2 => days
)
array(3
0 => 7
1 => 7
2 => days
My issue is with the 'Year' options and the fact that they have empty keys because I want to refer to $output[1] and $output[2] to get the interval and 'span' (days). Only a single string will be passed at a time so it will be one of the options listed above and not multiple options to look for at once.
If anyone can help me find the best solution to return 'yesterday' or ('7' and 'days') or ('30' and 'days') or ('This' and 'Year') or ('Last' and 'Year') I would appreciate it very much!
EDIT
This is my desired output:
'Yesterday'
$output[0] => 'Yesterday'
'Last 7 Days'
$output[0] => '7'
$output[1] => 'Days'
'Last 30 Days'
$output[0] => '30'
$output[1] => 'Days'
'This Year'
$output[0] => 'This'
$output[1] => 'Year'
'Last Year'
$output[0] => 'Last'
$output[1] => 'Year'
I am trying to capture the 'groups' necessary to process the rest of my code.
You can use the branch reset feature to avoid empty groups:
$text = <<<'EOD'
Yesterday
Last 7 Days
Last 30 Days
This Year
Last Year
EOD;
$pattern = '~\b(?|yesterday\b|\d+(?= (days\b))|\w+(?= (year\b)))~i';
if (preg_match_all($pattern, $text, $matches, PREG_SET_ORDER))
print_r($matches);
// or preg_match without PREG_SET_ORDER if you test the strings one by one
pattern details:
\b
(?| # open the branch reset group
yesterday \b # when this branch succeeds the capture group is not defined
|
\d+ (?=[ ](days\b)) # in each branch the capture group
|
\w+ (?=[ ](year\b)) # has the same number
) # (so there is only one capture group)
result:
Array
(
[0] => Array
(
[0] => Yesterday
)
[1] => Array
(
[0] => 7
[1] => Days
)
[2] => Array
(
[0] => 30
[1] => Days
)
[3] => Array
(
[0] => This
[1] => Year
)
[4] => Array
(
[0] => Last
[1] => Year
)
)
Note that when you build the branch reset, you must begin with alternatives that has no groups, then alternatives with one groups, then two groups, etc. otherwise you may obtain useless empty groups in the result.
Note too that the group 0 isn't really a capture group but it is the whole match.
You can use:
/((?:Last|This)\s+(?:\d+\s+Days|Year)|Yesterday)/
Matches:
MATCH 1
1. [0-9] `Yesterday`
MATCH 2
1. [10-21] `Last 7 Days`
MATCH 3
1. [22-34] `Last 30 Days`
MATCH 4
1. [35-44] `This Year`
MATCH 5
1. [45-54] `Last Year`
Regex Demo:
https://regex101.com/r/mA8jZ5/1
Regex Explanation:
/((?:Last|This)\s+(?:\d+\s+Days|Year)|Yesterday)/
1st Capturing group ((?:Last|This)\s+(?:\d+\s+Days|Year)|Yesterday)
1st Alternative: (?:Last|This)\s+(?:\d+\s+Days|Year)
(?:Last|This) Non-capturing group
1st Alternative: Last
Last matches the characters Last literally (case sensitive)
2nd Alternative: This
This matches the characters This literally (case sensitive)
\s+ match any white space character [\r\n\t\f ]
Quantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]
(?:\d+\s+Days|Year) Non-capturing group
1st Alternative: \d+\s+Days
\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]
\s+ match any white space character [\r\n\t\f ]
Quantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]
Days matches the characters Days literally (case sensitive)
2nd Alternative: Year
Year matches the characters Year literally (case sensitive)
2nd Alternative: Yesterday
Yesterday matches the characters Yesterday literally (case sensitive)
What you just described can be Achieved with the following Regex:
(yesterday|\d+(?=\s+\w+)|\w+(?=\s+year))\s*(\w*)$
Tested on Regex101.com Demo Here :

regex to find numbers in string that starts with 08 and are between 10-13 char

I am trying to parse a string that contain strings that are 9-11 characters long and are integers and starts with 08 or +62. How do I do this in PHP? Here's my regex thus far:
/^(\+?62|08)[0-9]{9,11}$/
so here's some sample string/integer I should be able to extract out of a long string
082298744807
087884962429
087783218768
0818809692
081224505277
+628129191929
+62812123929
It's unclear if you want to match numbers between 10-13 digits, or 9-11. In any case it's a simple fix (just count the initial two digits 08, or 62 as part of the total sum of digits. To implement this in php use preg_match_all:
$pat = "/^(?:\+?62|08)[0-9]{8,11}$/uim"; // note modfied range of digits
preg_match_all($pat, $str, $res);
print_r($res[0]);
Example:
http://ideone.com/GJYK7C
Result:
Array
(
[0] => 082298744807
[1] => 087884962429
[2] => 087783218768
[3] => 0818809692
[4] => 081224505277
[5] => +628129191929
[6] => +62812123929
[7] => +629490029944
)

How can I split a string into LETTERS and FLOAT/INTEGER numbers

I've been trying for the couple of days to split a string into letters and numbers. I've found various solutions but they do not work up to my expectations (some of them only separate letters from digits (not integers or float numbers/per say negative numbers).
Here's an example:
$input = '-4D-3A'; // edit: the TEXT part can have multiple chars, i.e. -4AB-3A-5SD
$result = preg_split('/(?<=\d)(?=[a-z])|(?<=[a-z])(?=\d)/i', $input);
print_r($result);
Result:
Array ( [0] => -4 [1] => D-3 [2] => A )
And I need it to be [0] => -4 [1] => D [2] => -3 [3] => A
I've tried doing several changes but no result so far, could you please help me if possible?
Thank you.
try this:
$input = '-4D-3A';
$result = preg_split('/(-?[0-9]+\.?[0-9]*)/i', $input, 0, PREG_SPLIT_DELIM_CAPTURE);
$result=array_filter($result);
print_r($result);
It will split by numbers BUT also capture the delimiter (number)
giving : Array ( [1] => -4 [4] => D [5] => -3 [8] => A )
I've patterened number as:
1. has optional negative sign (you may want to do + too)
2. followed by one or more digits
3. followed by an optional decimal point
4. followed by zero or more digits
Can anyone point out the solution to "-0." being valid number?
How about this regex? ([-]{,1}\d+|[a-zA-Z]+)
I tested it out on http://www.rubular.com/ seems to work as you want.

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)

Identify date-related text in a longer message

I'm currently writing a script that would extract all the dates from a message and convert them to timestamps. PHP's strtotime (similar to Unix's date -c 'some date') would be perfect for this, as it recognizes all kinds of dates, such as:
5pm today
2010-11-15 16:30
Thursday 8:00
However, I'm having trouble finding those dates in the first place. For example, in the following string,
I'll be there for dinner tomorrow at 9:00pm
I need to isolate "tomorrow at 9:00pm", as that's the part that strtotime recognizes.
Is there a regular expression or something similar that would return me all dates that can be parsed by strtotime?
The only thing I can think of is date_parse. A regular expression that matches any format accepted by strtotime would be huge.
An example of date_parse:
$str = "I'll be there for dinner tomorrow at 9:00pm";
$parsed = date_parse($str);
print_r($parsed);
It would output something like this (I removed the unimportant parts from it to make it the result lighter):
Array
(
[year] =>
[month] =>
[day] =>
[hour] => 21 // 9:00pm
[minute] => 0 // 9:00pm
[second] => 0 // 9:00pm
[fraction] => 0
[warning_count] => 1
[is_localtime] => 1
[zone_type] => 2
[zone] => -540
[is_dst] =>
[tz_abbr] => I
[relative] => Array
(
[year] => 0
[month] => 0
[day] => 1 // tomorrow (would be -1 for yesterday, etc.)
[hour] => 0
[minute] => 0
[second] => 0
)
)
Whether this works for you depends primarily on what your input looks like. If you have more than one instance of a date in your input string, it will not work as expected.
This might not be totally efficient, but should work for any date string that consists of up to 5 words in length. I would write the function, but I think you'll get the idea with the comments below...
$words = explode(' ',$original_string);
// Use the array_chunk() function break up this array into 1-word,
// 2-word, 3-word, and 4-word long substrings of the original string
// Reform them back into strings and pass each one through strtodate()

Categories