PHP preg_replace datetime and matches - php

I want to style MySQL datetime format string to be something like the following:
<b>2018-07-09</b><i>10:25:00</i>
I'm trying to use preg_replace() to replace matched patterns like the following:
preg_replace("/([^\s]+)/",\'<b>$1</b><i>$2</i>\',$date)
However, the pattern https://regex101.com/r/LLRx3x/1, indicates that there two matches where each one has one group. The first match is the date, while the second is the time. I could not able to utilize $1 and $2 to access and replace each match. The above preg_match code returns something like:
<b>2018-07-09</b><i></i> <b>13:25:18</b><i></i>
So How could I access each match and replace them to get my goal?

You may capture the date and time into separate 2 groups,then you can use $1 and $2:
preg_replace('~^(\S+)\s+(\S+)$~', '<b>$1</b><i>$2</i>', $date)
See the regex demo and a PHP demo.
Note that the $n replacement backreferences only refer to the corresponding capturing group values, so if you defined one capturing group in your pattern, only 1 capture is accessible with $1 and $2 will hold an empty string, i.e. preg_replace('~^(\S+)\s+\S+$~', '<b>$1</b><i>$2</i>', '2018-07-09 13:25:18') will yield <b>2018-07-09</b><i></i>).
So, the point here is to match both the date and time but capture them into separate capturing groups, and then use the corresponding backreferences accordingly.
Pattern details
^ - start of the string
(\S+) - Capturing group 1 (later referred to with $1 backreference): any 1+ non-whitespace chars
\s+ - 1+ whitespaces
(\S+) - Capturing group 2 (later referred to with $2 backreference): any 1+ non-whitespace chars
$ - end of string.

Related

How to apply regular expressions to get a number from a dynamic string

I have a variable that can contain a few variations, it also contains a number which can be any number.
The variations:
($stuksprijs+9.075);
($stuksprijs-9.075);
($stuksprijs*9.075);
($m2+9.075);
($m2-9.075);
($m2*9.075);
($o+9.075);
($o-9.075);
($o*9.075);
These are the only variations except for the numbers in it, they can change. And I need that number.
So there can be:
($m2+5);
or
($o+8.25);
or
($stuksprijs*3);
How can I get the number from those variations? How can I get the 9.075 or 5 or 8.25 or 3 from my above examples with regular expression?
I am trying to fix this with PHP, my variable that contains the string is: $explodeberekening[1]
I read multiple regex tutorials and got it to work for a single string that never changes, but how can I write a regex to get the number from above variations?
As per my comment, which seems to have worked, you can try:
^\(\$(?:stuksprijs|m2|o)[+*-](\d+(?:\.\d+)?)\);$
The number is captured in the 1st capture group. See the online demo.
A quick breakdown:
^ - Start string anchor.
\(\$ - Literally match "($".
(?: - Open a non-capture group to list alternation:
stuksprijs|m2|o - Match one of these literal alternatives.
) - Close non-capture group.
[+*-] - Match one of the symbols from the character-class.
( - Open 1st capture group:
\d+ - 1+ digits.
(?:\.\d+)? - Extra optional non-capture group to match a literal dot and 1+ digits.
) - Close 1st capture group.
\); - Literally match ");".
$ - End string anchor.

Using Regex to detect if string exists

I need to use PHP's preg_match() and Regex to detect the following conditions:
If a URL path is one of the following:
products/new items
new items/products
new items/products/brand name
Do something...
I can't seem to figure out how to check if the a string exists before or after the word products. The closest I can get is:
if (preg_match("([a-zA-Z0-9_ ]+)\/products\/([a-zA-Z0-9_ ]+)", $url_path)) {
// Do something
Would anyone know a way to check if the first part of the string exists within the one regex line?
You could use an alternation with an optional group for the last item making the / part of the optional group.
If you are only looking for a match, you can omit the capturing groups.
(?:[a-zA-Z0-9_ ]+/products(?:/[a-zA-Z0-9_ ]+)?|products/[a-zA-Z0-9_ ]+)
Explanation
(?: Non catpuring group
[a-zA-Z0-9_ ]+/products Match 1+ times what is listed in the character class, / followed by products
(?:/[a-zA-Z0-9_ ]+)? Optionally match / and what is listed in the character class
| Or
products/[a-zA-Z0-9_ ]+ Match products/, match 1+ times what is listed
) Close group
Regex demo
Note that [a-zA-Z0-9_ ]+ might be shortened to [\w ]+
You can use alternation
([\w ]+)\/products|products\/([\w ]+)
Regex Demo
Note:- I am not sure how you're using the matched values, if you don't need back reference to any specific values then you can avoid capturing group, i.e.
[\w ]+\/products|products\/[\w ]+

Regex pattern for splitting BEM string into parts (PHP)

I would like to isolate the block, element and modifier parts of a string via PHP regex. The flavour of BEM I'm using is lowercase and hyphenated. For example:
this-defines-a-block__this-defines-an-element--this-defines-a-modifier
My string is always formatted as the above, so the regex does not need to filter out any invalid BEM, for example, I will never have dirty strings such as:
This.defines-a-block__this-Defines-an-ELEMENT--090283
Block, Element and Modifier names could contain numbers, so we could have any combination of the following:
this-is-block-001__this-is-element-001--modifier-002
Finally a modifier is optional so not every string will have one for example:
this-is-a-block-001__this-is-an-element
this-is-a-block-002__this-is-an-element--this-is-an-optional-modifier
I am looking for some regex to return each section of the BEM markup. Each string will be isolated and sent to the regex individually, not as a group or as multiline strings. The following sent individually:
# String 1
block__element--modifier
# String 2
block-one__element-one--modifier-one
# String 3
block-one-big__element-one-big--modifier-one-big
# String 4
block-one-001__element-one-001
Would return:
# String 1
block
element
modifier
# String 2
block-one
element-one
modifier-one
# String 3
block-one-big
element-one-big
modifier-one-big
# String 4
block-one-001
element-one-001
You could use 3 capturing groups and make the third one optional using the ?
As all 3 groups are lowercase, can contain numbers and use the hyphen as a delimiter you might use a character class [a-z0-9].
You could reuse the pattern for group 1 using (?1)
\b([a-z0-9]+(?:-[a-z0-9]+)*)__((?1))(?:--((?1)))?\b
Explanation
\b Word boundary
( First capturing group
[a-z0-9]+ Repeat 1+ times what is listed in the character class
(?:-[a-z0-9]+)* Repeat 0+ times matching - and 1+ times what is in the character class
) Close group 1
__ Match literally
((?1)) Capturing group 2, recurse group 1
(?: Non capturing group
-- Match literally
((?1)) Capture group 3, recurse group 1
)? Close non capturing group and make it optional
\b Word boundary
Regex demo
Or using named groups:
\b(?<block>[a-z0-9]+(?:-[a-z0-9]+)*)__(?<element>(?&block))(?:--(?<modifier>(?&block)))?\b
Regex demo

Phone no contain this patteren AABBCC e.g 112233

I want to check if phone no contains this pattern AABBCC
Where A[0-9],B[0-9],C[0,9] They should be different e.g 112233,553322,887766
Let Us Suppose
I Have a phone no 03334112233
It will say yes pattern matched.
PHP Code but It Is For Exact String
$str = 'aabbaabbccaass'; //or whatever
if (preg_match('/(?!.*?aabbcc)^.*$/', $str))
echo "accepted\n";
else
echo "rejected\n";
Problem i don't know how to do if string is for numbers
Possible Duplicate
but it does not contain answer and exact detail.
Edited :
I want to match the last 6 characters of the string in this pattern AABBCC e.g 03329112233
To match number with AABBCC format, you can use this pattern:
(?:(\d)\1(?!\1)){2}(\d)\2
example of use:
if (preg_match('/(?:(\d)\1(?!\1)){2}(\d)\2/', $str)
echo "rejected\n";
else
echo "accepted\n";
But if you have other tests to do (for example that there is only digits), it can be more flexible to use it in this way:
if (preg_match('/(?!.*(?:(\d)\1(?!\1)){2}(\d)\2)^\d+$/', $str)
echo "accepted\n";
else
echo "rejected\n";
pattern details:
(?: # open a non capturing group that describes a repeated digit
(\d) # capture the first digit with group 1
\1 # a backreference to group 1 (the same digit thus)
(?!\1) # check with a negative lookahead that the same digit doesn't follow
){2} # repeat the group two times
(\d)\2 # same thing for digits 5 & 6 (the lookahead isn't needed here)
Note that the digit in the capture group change at each repetition of the non capturing group (because the negative lookahead forces it).
Notice: if you want to reject numbers that contains, for example, 111122 or 112222 or 111111, you only need to remove the negative lookahead.
if you want to reject numbers with the format 112211 or 448844, you must change the pattern like this: (\d)\1(?!\d{0,2}\1)(\d)\2(?!\2)(\d)\3
As I understand, you only want to match the last 6 characters of the string, if they are digits, and of 3 all different digit pairs. Would also use a lookahead and some pattern like this:
(?>((\d)\2)(?!.*\1)){3}$
\2 checks for an equivalent of 2nd capturing group, which is one digit (shorthand \d)
using a negative lookahead to check, if not followed by .* any amount of any characters, followed by equivalent of 1st capturing group (which contains 2 equal digits).
{3} 3 repitions at $ end of string.
Test on regex101.com, Regex FAQ
Your regex should be like this:
^((\d)\2){3}$
It is simpler and also works.
You can use capturing groups and backreferences like this:
if (preg_match('/(?!.*(.)\1(.)\2(.)\3)^.*$/', $str))
The (.) will match any single character and assign it to a group. The first instance is assigned to group 1, the second to group 2 and so on. Later in the pattern, the backreference \1 will match exactly what was previously captured in group the first group, \2 will match what was captured in the second group, etc.
You probably will also want to use \d to match any single digit (it's only necessary to use this outside of the lookahead) and a {n,m} quantifier to match between n and m digits. For example, the following will match any sequence of 7 to 10 digits that does not contain a subsequence like AABBCC:
if (preg_match('/(?!.*(.)\1(.)\2(.)\3)^\d{7,10}$/', $str))

regex matches numbers, but not letters

I have a string that looks like this:
[if-abc] 12345 [if-def] 67890 [/if][/if]
I have the following regex:
/\[if-([a-z0-9-]*)\]([^\[if]*?)\[\/if\]/s
This matches the inner brackets just like I want it to. However, when I replace the 67890 with text (ie. abcdef), it doesn't match it.
[if-abc] 12345 [if-def] abcdef [/if][/if]
I want to be able to match ANY characters, including line breaks, except for another opening bracket [if-.
This part doesn't work like you think it does:
[^\[if]
This will match a single character that is neither of [, i or f. Regardless of the combination. You can mimic the desired behavior using a negative lookahead though:
~\[if-([a-z0-9-]*)\]((?:(?!\[/?if).)*)\[/if\]~s
I've also included closing tags in the lookahead, as this avoid the ungreedy repetition (which is usually worse performance-wise). Plus, I've changed the delimiters, so that you don't have to escape the slash in the pattern.
So this is the interesting part ((?:(?!\[/?if).)*) explained:
( # capture the contents of the tag-pair
(?: # start a non-capturing group (the ?: are just a performance
# optimization). this group represents a single "allowed" character
(?! # negative lookahead - makes sure that the next character does not mark
# the start of either [if or [/if (the negative lookahead will cause
# the entire pattern to fail if its contents match)
\[/?if
# match [if or [/if
) # end of lookahead
. # consume/match any single character
)* # end of group - repeat 0 or more times
) # end of capturing group
Modifying a little results in:
/\[if-([a-z0-9-]+)\](.+?)(?=\[if)/s
Running it on [if-abc] 12345 [if-def] abcdef [/if][/if]
Results in a first match as: [if-abc] 12345
Your groups are: abc and 12345
And modifying even further:
/\[if-([a-z0-9-]+)\](.+?)(?=(?:\[\/?if))/s
matches both groups. Although the delimiter [/if] is not captured by either of these.
NOTE: Instead of matching the delimeters I used a lookahead ((?=)) in the regex to stop when the text ahead matches the lookahead.
Use a period to match any character.

Categories