Move multiple letters in string using regex - php

Using a regular expression I want to move two letters in a string.
W28
L36
W29-L32
Should be changed to:
28W
36L
29W-32L
The numbers vary between 25 and 44. The letters that need to be moved are always "W" and/or "L" and the "W" is always first when they both exist in the string.
I need to do this with a single regular expression using PHP. Any ideas would be awesome!
EDIT:
I'm new to regular expressions and tried a lot of things without success. The closest I came was using "/\b(W34)\b/" for each possibility. I also found something about using variables in the replace function but had no luck using these.

Your regex \b(W34)\b matches exactly W34 as a whole word. You need a character class to match W or L, and some alternatives to match the numeric range, and use the most of capturing groups.
You can use the following regex replacement:
$re = '/\b([WL])(2[5-9]|3[0-9]|4[0-4])\b/';
$str = "W28\nL36\nW29-L32";
$result = preg_replace($re, "$2$1", $str);
echo $result;
See IDEONE demo
Here, ([WL]) matches and captures either W or L into group 1, and (2[5-9]|3[0-9]|4[0-4]) matches integer numbers from 25 till 44 and captures into group 2. Backreferences are used to reverse the order of the groups in the replacement string.
And here is a regex demo in case you want to adjust it later.

Related

PHP RexExp match and substitute

I am testing RegExp with online regexr.com tool. I will test string with multiple cases, but I can't get substitution to work.
RexEx for matching string is:
/^[0-9]{1,3}[0-9]{6,7}$/
Which matches local mobile number in my country like this:
0921234567
But then I want to substitute number in this way: add "+" sign, add my country code "123", add "." sign, and then finaly, add matched number with stripped leading zero.
Final number will be:
+385.921234567
I have basic idea to insert matched string, but I am not sure how prepend characters, and strip zero from matched string in following substitution pattern:
\+$&\n\t
I will use PHP preg_replace function.
EDIT:
As someone mentioned wisely, there is posibility that there will be one, two or none of zeros, but I will create separate test cases with regex just testing number of zeroes. Doing so in one regex seems to complicated for now.
Possible numbers will be:
0921234567
00111921234567
Where 111 is country code. I know that some country codes consist of 2 or 3 digits, but I will create special cases, for most country codes.
You can use this preg_replace to strip optional zeroes from start of your mobile #:
$str = preg_replace('~^0*(\d{7,9})$~', '+385.$1', $str);
^[0-9]([0-9]{1,2}[0-9]{6,7})$
You just need to add groups.Replace by +385.$1.See demo.
https://regex101.com/r/cJ6zQ3/22
$re = "/^[0-9]([0-9]{1,2}[0-9]{6,7})$/m";
$str = "0921234567\n";
$subst = "+385.$1";
$result = preg_replace($re, $subst, $str);
I would use a 2-step solution:
Check if we match the main regex
Replace the number by pre-pending + + country code + . + number without leading zeros.
PHP code:
$re = "/^[0-9]{7,10}$/";
$str = "0921234567";
if (preg_match($re, $str, $match)) {
echo "+385." . preg_replace('/^0+/', '', $match[0]);
}
Note that splitting out character class in your regex pattern makes no sense when not using capture groups. ^[0-9]{7,10}$ is the same then as ^[0-9]{1,3}[0-9]{6,7}$, meaning match 7 to 10 digits from start to end of the string.
Leading zeros are easily trimmed from the start with /^0+/ regex.

Getting all URLs on multiple lines

I'm trying to get all these URLs from a website, but I only seem to be able to get the first URL. How can I match all the URLs?
So far I've tried
auto">(.*?)<\/pre>
and:
auto">(.*?)\s<\/pre>
I've tried adding several modifiers such as m and i, but it didn't seem to help.
This is what I'm searching:
auto">http://url-one.com
http://url-two.com
http://url-three.com
http://url-four.com
http://url-five.com</pre>
Can someone help me understand what I am missing?
Quick Answer
As Jonny5 hinted in his comment, . does not match newline characters by default: so (.*?) will not match beyond the first line without the s regex modifier, and his suggestion is then the quick answer:
/auto">(.*?)<\/pre>/s
You can check out his Regex101 demo or related PHP code...
$re = "/auto\">(.*?)<\\/pre>/s";
$str = "auto\">http://url-one.com\nhttp://url-two.com\nhttp://url-three.com\nhttp://url-four.com\nhttp://url-five.com</pre>";
preg_match($re, $str, $matches);
...for reference.
Digging Deeper
However, there is a little more going on here.
i and m Modifiers
First, regardless whether you use the i or m modifier(s), no line of the sample text would match with auto"> at the beginning and <\/pre> at the end of the pattern. You would have to group and follow each with a quantifier to make it optional (e.g. (?:auto">)? and (?:<\/pre>)?) to match each line of the sample text.
m Requires Matching Globally
Second, the m modifier would necessitate matching globally – and further tweaks to the pattern to avoid the last URL match ending with </pre>:
/(?:auto">)?(.+)(?=(?:\n|<\/pre>))/m
You can also check out a second Regex101 demo of this twist or try it out in PHP:
$re = "/(?:auto\">)?(.+)(?=(?:\\n|<\\/pre>))/m";
$str = "auto\">http://url-one.com\nhttp://url-two.com\nhttp://url-three.com\nhttp://url-four.com\nhttp://url-five.com</pre>";
preg_match_all($re, $str, $matches); // NOTE: preg_match_all to match globally
^^^^
Which Approach to Choose
The choice between simply adding the s modifier or tweaking the pattern, adding the m modifier, and matching globally mostly comes down to whether you want a single match with all the URLs (separated by newlines) or many matches, each with one of the URLs.
The latter yields the matches below...
MATCH 1
1. [6-24] `http://url-one.com`
MATCH 2
1. [25-43] `http://url-two.com`
MATCH 3
1. [44-64] `http://url-three.com`
MATCH 4
1. [65-84] `http://url-four.com`
MATCH 5
1. [85-104] `http://url-five.com`
...versus the single match that the original pattern and the s modifier yield:
MATCH 1
1. [6-104] `http://url-one.com
http://url-two.com
http://url-three.com
http://url-four.com
http://url-five.com`

Regex to extract substring

really struggling with this...hopefully someone can put me on the right path to a solution.
My input string is structured like this:
66-2141-A-AC107-7
I'm interested in extracting the string 'AC107' using a single regular expression. I know how to do this with other PHP string functions, but I have to do this with a regular expression.
What I need is to extract all data between the third and fourth hyphens. The structure of each section is not fixed (i.e, 66 may be 8798709 and 2141 may be 38). The presence of the number of hyphens is guaranteed (i.e., there will always be a total of four (4) hyphens).
Any help/guidance is greatly appreciated!
This will do what you need:
(?:[^-]*-){3}([^-]+)
Debuggex Demo
Explanation:
(?:[^-]*-) Look for zero or more non-hyphen characters followed by a hyphen
{3} Look for three of the blocks just described
([^-]+) Capture all the consecutive non-hyphen characters from that point forward (will automatically cut off before the next hyphen)
You can use it in PHP like this:
$str = '66-2141-A-AC107-7';
preg_match('/^(?:[^-]*-){3}([^-]+)/', $str, $matches);
echo $matches[1]; // prints AC107
This should look for anything followed by a hyphen 3 times and then in group 2 (the second set of parenthesis) it will have your value, followed by another hyphen and anything else.
/^(.*-){3}(.*)-(.*)/
You can access it by using $2. In php, it would be like this:
$string = '66-2141-A-AC107-7';
preg_match('/^(.*-){3}(.*)-(.*)/', $string, $matches);
$special_id = $matches[2];
print $special_id;

regex to match string that only has one uppercase letter

I am curling an page and getting the output
however what is happening is that the html encoding is being removed so new lines are being skipped,
so it looks like this
This is Bob. He lives in an boatBut he only has one oar to row with.
in order to detect new lines I figure it was easier to just check for strings that only have One upper case letter and spaces inbetween, so far I have this
(\s\w+\s\w+.\s\D+[a-z][A-Z])
However this does not seem to work
as it only matches this
is Bob. He lives in an boatB
see here http://regex101.com/r/gH0lW1
how to match all strings that have spaces and match all strings up to one Uppercase letter
Update: this will split on the condition without losing any characters
<?php
$string = "This is Bob. He lives in an boatBut he only has one oar to row with.He also does stuff, it is cool.";
$array = preg_split('/(?<=[a-z.])(?=[A-Z])/', $string);
print_r($array);
?>
Use a positive lookbehind to ensure you capture a capital after a lowercase:
(?<=[a-z])[A-Z]
http://regex101.com/r/cB7bD8
You could use php's preg_split if you want, to explode the result on this regex.
(.*?(?:\w+(?=[A-Z]))|\1)
This regex has a recursive part that will match more than 1 sentence in a whole text. So you can check the Live demo and see the matched groups.
But,
If you wanna include a newline on each sentence begins after a period (.) as well, then I modify above regex to this:
(.*?(?:(?:\w+|\. *)(?=[A-Z]))|\1)
and now you can compare results with the first regex HERE

Replacing a string using preg_match

I'm having trouble using preg_match to find and replace a string. The string of interest is:
<span style="font-size:0.6em">EXPIRATION DATE: 04/30/2011</span>
I need to target and replace the date, "04/30/2011" with a different date. Can someone throw me a bone a give me the regular expression to match this pattern using preg_match in PHP? I also need it to match in such a way that it only replaces up to the first closing span and not closing span tags later in the code, e.g.:
<span style="font-size:0.6em">EXPIRATION DATE: 04/30/2011</span><span class="hello"></span>
I'm not versed in regex, and although I've spent the last hour trying to learn enough to make this work, I'm utterly failing. Thanks so much!
EDIT: As you can see this has gotten me exhausted. I did mean preg_replace, not preg_match.
If you're after a replacement, consider using preg_replace(), something like
preg_replace('#(\d{2})/(\d{2})/(\d{4})#', '<new date>', $string);
How about this:
$toBeFoundPattern = '/([0-9][0-9])\/([0-9][0-9])\/([0-9][0-9][0-9][0-9])/';
$toBeReplacedPattern = '$2.$1.$3';
$inString = '<span style="font-size:0.6em">EXPIRATION DATE: 04/30/2011</span>';
// Will convert from US date format 04/30/2011 to european format 30.04.2011
echo preg_replace( $toBeFoundPattern, $toBeReplacedPattern, $inString );
and prints
EXPIRATION DATE: 30.04.2011
Patterns always begin and end with identical so called delimiter characters. Often the character / is used.
$1 references the string, which matched the first string matched by ([0-9][0-9]), $2 references be (...) and $3 the four letters matched by the last (...).
[...] matched a single character, which is one of those listed inside the brackets. E.g. [a-z] matches all lower case letters.
To use the special meaning character / inside of a pattern, you need to escape it by \ to make it be the literal slash character.
Update: Using {..} as pointed out below is shorthand for repeated patterns.
Regex should be:
(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d
If you want to only match one instance, this is OK. For multiple instances, use preg_match_all instead. Taken from http://www.regular-expressions.info/regexbuddy/datemmddyyyy.html.
Edit: are you looking to just search and replace inside a PHP script or do you want to do some javascript live replacement?

Categories