PHP Wrap Last and 2nd To Last Letter in Different Spans - php

I want to wrap the 2nd to last letter in a span with class "testing2" and the last letter in a span with class "testing". I got how to do the last letter, but what about the 2nd to last letter?
echo preg_replace('/(.)$/', '<span class="testing">\1</span>', $title)

This regex will find the last 2 letters in a string and capture them separately.
.*([a-zA-Z])([a-zA-Z]).*$
Demo: https://regex101.com/r/yR1sT8/1
PHP Usage:
$string = 'aaffffs3.4.4asdf234f4f3_+!#>,3';
preg_match('/.*([a-zA-Z])([a-zA-Z]).*$/', $string, $letters);
print_r($letters);
Output:
Array
(
[0] => aaffffs3.4.4asdf234f4f3_+!#>,3
[1] => d
[2] => f
)
...or...
$string = 'aaffffs3.4.4asdf234f4f3_+!#>,3';
echo preg_replace('/.*([a-zA-Z])([a-zA-Z]).*$/', '<span class="testing2">$1</span><span class="testing">$2</span>',$string);
Output:
<span class="testing2">d</span><span class="testing">f</span>
If you didn't care about the last letters and just wanted any character than this was much easier and just, (.)(.)$.
Possible alternative: https://regex101.com/r/yR1sT8/2
Update:
To keep the previous values as well we just need to add additional capture groups.
$string = 'aaffffs3.4.4asdf234f4f3_+!#>,3';
echo preg_replace('/(.*)([a-zA-Z])([a-zA-Z])(.*)$/', '$1<span class="testing2">$2</span><span class="testing">$3</span>$4',$string);
Output:
aaffffs3.4.4as<span class="testing2">d</span><span class="testing">f</span>234f4f3_+!#>,3
Additional:
The () is a capture group. Anything inside those is grouped which can be used in a number of ways. For example say you wanted to evaluate a sentence and you didn't care the word the started it, you could do.
`(?:The)? wolf was walking down the street`
Here the is grouped and the ? makes that whole word optional. The ?: makes the capturing group not capture so $1 wouldn't be present here. The $1, $2, etc. are named on the order they appear in the regex. You can read more about capture groups here, http://www.regular-expressions.info/refcapture.html and
http://www.rexegg.com/regex-capture.html. Depending on the language the reference to the captured value maybe \1.

Simplest would be an assertion instead of just $:
(?=.$|$)
This would lead the (.) to match at the end and one letter before that.

Related

PHP Regex to capture names if prefixed with key words

I'm in need of a PHP regular expression to capture the first initial an last name of people listed in a text document. But only capture the names when the sentence or line contains a few keywords. (from, with, of, and ,as ,observed). My current attempt captures list items ie. "A. General" or "B. Issues" because it doesn't seem to care about what's in front of the names.
I've been using preg_match_all() with hopes of it returning an array of names. (first inital, last name).
Example text
"from J. Smith and B. Miller"
"as T. Baker observed M. Kelly"
"We inquired with B. Brown, T. Stark and J. Maddox."
I've tried
$regex = "/[from|with|of|and|as|observed|,|.]\s+([A-Z]. \w+)/";
$regex = "/((from|with|of|and|as|observed|,|.)\s+([A-Z]. \w+))/";
$regex = "/\b(from|with|of|and|as|observed|,|.)\s+([A-Z].\ \w+)/";
$regex = "/\b(from|with|of|and|as|observed|,|.|\b)\s+([A-Z].\ \w+)/";
I cannot make it only capture when the word list is before the names. I can't use ^ to check 'starts with'. I'm horrible at regex and guess until it works. I feel the solution requires some sort of look-behind assertion, though I'm not sure how it works.
Output
Should be an array
[ 'J. Smith', 'B. Miller' ]
[ 'T. Baker', 'M. Kelly' ]
[ 'B. Brown', 'T. Stark', 'J. Maddox' ]
UPDATE
Final Regexp
$regex = "/\b(?:from|with|of|and|as|observed|,)\s+([A-Z].\ \w+)/";
Seems to work with the few documents I have. Thanks everyone!!
You can use this modified version of your third regex :
\b(?:from|with|of|and|as|observed|,)\s+([A-Z].\ \w+)\g
You need to escape . in the first group or it will accept any character. Not relevant after edit
The \g flag will find every occurrence of the pattern, and you will be able to access the results in $matches[1].
(The added ?: in first group prevent it from being captured, you can remove it if you need to know the keyword, but then the results will be stored in $matches[2] )
Edit : Removed \. in first group to not match end of sentences (see author comment).
You can try looking for a capital letter followed by a dot and a word
[A-Z]\.\s\w+
I think this should work
/(?!^from|with|of|and|as|observed|\s)([A-Z]{1,}\.\s\w*)/g
Where
?! = Discard the match of the first group, that begins with first ( and ends with ) and at least is included also the \s (space) at the beginning of the name.
^ = match the begins of the line/sentence/string
Then in second group it should match just one capital letter {1,} and then a dot \., a space \s and the word \w
The /g at the end stands for "global search"
https://regexr.com/3pa9o

Php preg_replace numbers characters

$my_string = '88888805';
echo preg_replace("/(^.|.$)(*SKIP)(*F)|(.)/","*",$,my_string);
This shows the first and last number like thus 8******5
But how can i show this number like this 888888**. (The last 2 number is hidden)
Thank you!
From this: 8******5
To: 888888**
I'm not sure if you have worked on this Regex pattern to do something unique. However, I will provide you with a general one that should fit your question without using your current pattern.
$my_string = '88888805';
echo preg_replace("/([0-9]+)[0-9]{2}$/","$1**",$,my_string);
Explanation:
The ([0-9]+) will match all digits, this could be replaced with \d+, it's between brackets to be captured as we are going to use it in the results.
[0-9]{2} is going to match the last 2 digits, again, it can be replaced with \d{2}, it's outside the brackets because we don't want to include them in the result. the $ after that is to indicate the end of the test, it's optional anyways.
Results:
Input: 88888805
Output: 888888**
echo preg_replace("/(.{2}$)(*SKIP)(*F)|(.)/","*",$my_string);
If it for a uni assignment, you'd probably want to do this. Basically says, don't match if its the last two characters, otherwise match.

Get string between first and third occurence of character

I have many Strings looking like this:
QR-DF-6549-1 and QR-DF-6549
I want to get these parts of the strings:
DF-6549
Edit:
So I also want to get rid of the "-1" at the end, in case it exists.
How can I do this with php? I know substr but I am a bit lost at this one.
Thank you very much!
A regular expression is probably the best way given your sample data
// ^ start matching at start of string
// [A-Z]{2}- must start with two capital letters and a dash
// ( we want to capture everything that follows
// [A-Z]{2}- next part must start with two capital letters and a dash
// \d+ a sequence of one or more digits
// ) end the capture - this will be index 1 in the $match array allowed
if (preg_match('/^[A-Z]{2}-([A-Z]{2}-\d+)/', $str, $match)) {
$data=$match[1];
}

preg_replace or regex string translation

I found some partial help but cannot seem to fully accomplish what I need. I need to be able to do the following:
I need an regular expression to replace any 1 to 3 character words between two words that are longer than 3 characters with a match any expression:
For example:
walk to the beach ==> walk(.*)beach
If the 1 to 3 character word is not preceded by a word that's longer than 3 characters then I want to translate that 1 to 3 letter word to '<word> ?'
For example:
on the beach ==> on ?the ?beach
The simpler the rule the better (of course, if there's an alternative more complicated version that's more performant then I'll take that as well as I eventually anticipate heavy usage eventually).
This will be used in a PHP context most likely with preg_replace. Thus, if you can put it in that context then even better!
By the way so far I have got the following:
$string = preg_replace('/\s+/', '(.*)', $string);
$string = preg_replace('/\b(\w{1,3})(\.*)\b/', '${1} ?', $string);
but that results in:
walk to the beach ==> 'walk(.*)to ?beach'
which is not what I want. 'on the beach' seems to translate correctly.
I think you will need two replacements for that. Let's start with the first requirement:
$str = preg_replace('/(\w{4,})(?: \w{1,3})* (?=\w{4,})/', '$1(.*)', $str);
Of course, you need to replace those \w (which match letters, digits and underscores) with a character class of what you actually want to treat as a word character.
The second one is a bit tougher, because matches cannot overlap and lookbehinds cannot be of variable length. So we have to run this multiple times in a loop:
do
{
$str = preg_replace('/^\w{0,3}(?: \w{0,3})* (?!\?)/', '$0?', $str, -1, $count);
} while($count);
Here we match everything from the beginning of the string, as long as it's only up-to-3-letter words separated by spaces, plus one trailing space (only if it is not already followed by a ?). Then we put all of that back in place, and append a ?.
Update:
After all the talk in the comments, here is an updated solution.
After running the first line, we can assume that the only less-than-3-letter words left will be at the beginning or at the end of the string. All others will have been collapsed to (.*). Since you want to append all spaces between those with ?, you do not even need a loop (in fact these are the only spaces left):
$str = preg_replace('/ /', ' ?', $str);
(Do this right after my first line of code.)
This would give the following two results (in combination with the first line):
let us walk on the beach now go => let ?us ?walk(.*)beach ?now ?go
let us walk on the beach there now go => let ?us ?walk(.*)beach(.*)there ?now ?go

Search a String for Alpha Numeric Characters in a Pattern

I have a string that contains 5 words. In the string one of the words is a Ham Radio Call Sign and can be anyone of the thousands of call signs in the US. In order to extract the Call Sign from the string I need to utilize the below pattern. The Call Sign I need to extract can be in any of the 5 positions in the string. The number is never the first character and the number is never the last character. The string is actually put together from an Array since it is originally read from a text file.
$string = $word[1] $word[2] $word[3] etc....
So the search can be either done on the whole string or each piece of the array.
Patterns:
1 Number and 3 Letters Example: AB4C A4BC
1 Number and 4 Letters Example: A4BCD
1 Number and 5 Letters Example: AB4CDE
I have tried everything I can think of and search till I cant search no more. I am sure I am over thinking this.
A two-step regular expression like this would do it:
$str = "hello A4AB there BC5AD";
$signs = array();
preg_match_all('/[A-Z][A-Z\d]{1,3}[A-Z]/', $str, $possible_signs);
foreach($possible_signs[0] as $possible_sign)
if (preg_match('/^\D+\d\D+$/', $possible_sign))
array_push($signs, $possible_sign);
print_r($signs); //Array ([0] => A4AB [1] => BC5AD)
Explanation
This is a regular expression approach, using two patterns. I don't think it could be done with one and still satisfy the exact requirements of the matching rules.
The first pattern enforces the following requirements:
substring starts and ends with a capital letter
substring contains only other capital letters or numbers between the first and last letter
substring is, overall, not more than 6 characters long
What I can't do in that same pattern, for complex REGEX reasons I won't go into (unless someone knows a way and can correct me), is enforce that only one number is contained.
#jeroen's answer does enforce this in a single pattern, but in turn does not enforce the correct length of the substring. Either way, we need a second pattern.
So after grabbing the initial matches, we loop over the results. We then apply each to a second pattern that enforces simply that there is only one number in the substring.
If so, we green-light the substring and it's added to the $signs array.
Hope this helps.
It depends on what the other words can contain, but you could use a regular expression like:
#\b[a-z]+\d[a-z]+\b#i
^ case insensitive
^^ a word boundary
^^^^^^ One or more letters
^^ One number
You can make it more restrictive by using {1,3} instead of + for the letters so that you have a sequence of 1 to 3 letters.
The complete expression would be something like:
$success = preg_match('#\b[a-z]+\d[a-z]+\b#i', $input_string, $matches);
where $matches[0] will contain the matched value, see the manual.

Categories