Insert a string into a string at a specific point using PHP - php

I'm wondering if there is a way to insert a string into another string at a specific point (in this case, near the end)? For example:
$string1 = "item one, item two, item three, item four";
$string2 = "AND";
//do something fancy here
echo $string1;
OUTPUT:
item one, item two, item three, AND item four
I need some help with the fancy string work part. Basically inserting the word after the last ", " if possible.

You can use preg_replace for this, and I find it to be terser than other string manipulation methods and also more easily adaptable if your use case should change:
$string1 = "item one, item two, item three, item four";
$string2 = "AND";
$pattern = "/,(?!.*,)/";
$string1 = preg_replace($pattern, ", $string2", $string1);
echo $string1;
Where you pass preg_replace a regex pattern, the replacement string, and the original string. Instead of modifying the original string, preg_replace returns a new string, so you will set $string1 equal to the output of preg_replace.
The pattern: You can use any delimiter to signal the beginning and end of the expression. Typically I see / used*, so the expression will be "/pattern/", where the pattern consists of the comma and a negative lookahead (?!) to find the comma that isn't followed by another comma. It isn't necessary to explicitly declare $pattern. You can just use the expression directly in the preg_replace arguments, but sometimes it can be just a little easier (especially for complex patterns) to separate the pattern declaration from its use.
The replacement: preg_replace is going to replace the entire match, so you need to prepend your replacement text with the comma (that's getting replaced) and a space. Since variables wrapped in double quotes are evaluated in strings, you put $string2 inside the quotes**.
The target: you just put your original string here.
* I prefer to use ~ as my delimiter, since / starts to get cumbersome when you deal with urls, but you can use anything.
Here is a cheat sheet for regex patterns, but there are plenty of these floating around. Just google regex cheat sheet if you need one.
https://www.rexegg.com/regex-quickstart.html
Also, you can find plenty of online regex testers. Here is one that includes a quick reference and also lets you switch regex engines (there are a few, and some can be just a little bit different than others):
https://regex101.com/
** I prefer to also wrap the variable in curly braces to make it more explicit that I am inserting the value, but it's optional. That would look like ", {$string2}"

Lots of ways to do this - but since you specifically stated "after the last ," then strrpos seemed appropriate:
// insert this line where you indicate 'do something fancy here'
$string1 = substr_replace($string1, " ".$string2, strrpos($string1,",")+1, 0);
Find the right-most comma and insert the $string2 (with a space prepended) one position after it. The last parameter indicates the length of the substring to replace so a 0 means "do not replace anything but only insert."
Note the extra space added to $string2. Obviously you could modify how $string2 is initialized to include the space and eliminate this part.

You can use a pattern to match the last comma in the string using .*, and then use \K to forget what is matched so far.
In the replacement use AND
$string1 = "item one, item two, item three, item four";
$string2 = " AND";
$string1 = preg_replace("/.*,\K/", $string2, $string1);
echo $string1;
Output
item one, item two, item three, AND item four
See a PHP demo.

Related

Use regex to quote the name in name-value pair of a list of pairs

I am trying to put quotes around the names of name-value pairs separated by commas. I use preg_replace and regex to achieve that. However, my pattern is not working properly.
$str="f1=1,f2='2',f3='a',f4=4,f5='5'";
$newstr=Preg_replace(/'(?.[^=]+)'/,"'$1'",$str);
I expected $newstr to come out like so:
'f1'=1,'f2'='2','f3'='a','f4'=4,'f5'='5'
But it doesn't and the qoutes don't contain the name.
What should the pattern be and how can I use the comma to get all of them correctly?
There are a few issues with your attempt:
PHP does not have a regex-literal syntax as in JavaScript, so starting the regex value with a forward slash is a syntax error. It should be a string, so start with a quote. Maybe you accidently swapped the slash and quote at the start and the end.
(?. is not valid. Maybe you intended (?:, but then there is no capture group and $1 is not a valid back reference. To have the capture group, you should not have (?., but just (.
[^=]+ could include substrings like 1,f2. There should be logic to not start matching while still inside a value (whether quoted or not).
I would suggest a regex where you match both parts around the = (both key and value), and then in the replacement, just reproduce the second part without change. This will ensure you don't accidently use anything in the value side for wrapping in quotes:
$newstr = preg_replace("/([^,=]+)=('[^']*'|[^,]*)/","'$1'=$2",$str);
Basically, match beginning of line or a comma (with negative capture) and then capture everything until a =
$reg = "/(?<=^|,)([^=]+)/";
$str = "f1=1,f2='2',f3='a',f4=4,f5='5'";
print_r(preg_replace($reg, "'$1'", $str));
// output:
// 'f1'=1,'f2'='2','f3'='a','f4'=4,'f5'='5'
This will also work, a different approach, but assuming there will be no comma in the values or names except the separators..
$newstr = preg_replace("/(.)(?==)|(?<=,|^)(.)/", "$1'$2", $str);
But I believe string and simple array operations will be faster as the regex is really getting complex and there are so many steps to get the characters.. Here is the same output but with array functions only.
$newstr = implode(",", array_map(function($element){ return "'". implode("'=", explode("=", $element)); }, explode(",", $str)));
RegEx is not always fast than string or array operations, but yes it can do complex things with little bit of code.

preg_replace - similar patterns

I have a string that contains something like "LAB_FF, LAB_FF12" and I'm trying to use preg_replace to look for both patterns and replace them with different strings using a pattern match of;
/LAB_[0-9A-F]{2}|LAB_[0-9A-F]{4}/
So input would be
LAB_FF, LAB_FF12
and the output would need to be
DAB_FF, HAD_FF12
Problem is, for the second string, it interprets it as "LAB_FF" instead of "LAB_FF12" and so the output is
DAB_FF, DAB_FF
I've tried splitting the input line out using 2 different preg_match statements, the first looking for the {2} pattern and the second looking for the {4} pattern. This sort of works in that I can get the correct output into 2 separate strings but then can't combine the two strings to give the single amended output.
\b is word boundary. Meaning it will look at where the word ends and not only pattern match.
https://regex101.com/r/upY0gn/1
$pattern = "/\bLAB_[0-9A-F]{2}\b|\bLAB_[0-9A-F]{4}\b/";
Seeing the comment on the other answer about how to replace the string.
This is one way.
The pattern will create empty entries in the output array for each pattern that fails.
In this case one (the first).
Then it's just a matter of substr.
$re = '/(\bLAB_[0-9A-F]{2}\b)|(\bLAB_[0-9A-F]{4}\b)/';
$str = 'LAB_FF12';
preg_match($re, $str, $matches);
var_dump($matches);
$substitutes = ["", "DAB", "HAD"];
For($i=1; $i<count($matches); $i++){
If($matches[$i] != ""){
$result = $substitutes[$i] . substr($matches[$i],3);
Break;
}
}
Echo $result;
https://3v4l.org/gRvHv
You can specify exact amounts in one set of curly braces, e.g. `{2,4}.
Just tested this and seems to work:
/LAB_[0-9A-F]{2,4}/
LAB_FF, LAB_FFF, LAB_FFFF
EDIT: My mistake, that actually matches between 2 and 4. If you change the order of your selections it matches the first it comes to, e.g.
/LAB_([0-9A-F]{4}|[0-9A-F]{2})/
LAB_FF, LAB_FFFF
EDIT2: The following will match LAB_even_amount_of_characters:
/LAB_([0-9A-F]{2})+/
LAB_FF, LAB_FFFF, LAB_FFFFFF...

Split string on non-alphanumerics in PHP? Is it possible with php's native function?

I was trying to split a string on non-alphanumeric characters or simple put I want to split words. The approach that immediately came to my mind is to use regular expressions.
Example:
$string = 'php_php-php php';
$splitArr = preg_split('/[^a-z0-9]/i', $string);
But there are two problems that I see with this approach.
It is not a native php function, and is totally dependent on the PCRE Library running on server.
An equally important problem is that what if I have punctuation in a word
Example:
$string = 'U.S.A-men's-vote';
$splitArr = preg_split('/[^a-z0-9]/i', $string);
Now this will spilt the string as [{U}{S}{A}{men}{s}{vote}]
But I want it as [{U.S.A}{men's}{vote}]
So my question is that:
How can we split them according to words?
Is there a possibility to do it with php native function or in some other way where we are not dependent?
Regards
Sounds like a case for str_word_count() using the oft forgotten 1 or 2 value for the second argument, and with a 3rd argument to include hyphens, full stops and apostrophes (or whatever other characters you wish to treat as word-parts) as part of a word; followed by an array_walk() to trim those characters from the beginning or end of the resultant array values, so you only include them when they're actually embedded in the "word"
Either you have PHP installed (then you also have PCRE), or you don't. So your first point is a non-issue.
Then, if you want to exclude punctuation from your splitting delimiters, you need to add them to your character class:
preg_split('/[^a-z0-9.\']+/i', $string);
If you want to treat punctuation characters differently depending on context (say, make a dot only be a delimiter if followed by whitespace), you can do that, too:
preg_split('/\.\s+|[^a-z0-9.\']+/i', $string);
As per my comment, you might want to try (add as many separators as needed)
$splitArr = preg_split('/[\s,!\?;:-]+|[\.]\s+/', $string, -1, PREG_SPLIT_NO_EMPTY);
You'd then have to handle the case of a "quoted" word (it's not so easy to do in a regular expression, because 'is" "this' quoted? And how?).
So I think it's best to keep ' and " within words (so that "it's" is a single word, and "they 'll" is two words) and then deal with those cases separately. For example a regexp would have some trouble in correctly handling
they 're 'just friends'. Or that's what they say.
while having "'re" and a sequence of words of which the first is left-quoted and the last is right-quoted, the first not being a known sequence ('s, 're, 'll, 'd ...) may be handled at application level.
This is not a php-problem, but a logical one.
Words could be concatenated by a -. Abbrevations could look like short sentences.
You can match your example directly by creating a solution that fits only on this particular phrase. But you cant get a solution for all possible phrases. That would require a neuronal-computing based content-recognition.

Search and Replace with Regex

I am trying to search through text for a specific word and then add a html tag around that word.For example if i had the string "I went to the shop to buy apples and oranges" and wanted to add html bold tags around apples.
The problem, the word i search the string with is stored in a text file and can be uppercase,lowercase etc.When i use preg_replace to do this i manage to replace it correctly adding the tags but for example if i searched for APPLES and the string contained "apples" it would change the formatting from apples to APPLES, i want the format to stay the same.
I have tried using preg_replace but i cant find a way to keep the same word casing.This is what i have:
foreach($keywords as $value)
{
$pattern = "/\b$value\b/i";
$replacement = "<b>$value</b>";
$new_string = preg_replace($pattern, $replacement, $string);
}
So again if $value was APPLES it would change every case format of apples in the $string to uppercase due to $replacemant having $value in it which is "APPLES".
How could i achieve this with the case format staying the same and without having to do multiple loops with different versions of case format?
Thanks
Instead of using $value verbatim in the replacement, you can use the literal strings \0 or $0. Just as \n/$n, for some integer n, refers back to the nth capturing group of parentheses, \0/$0 is expanded to the entire match. Thus, you'd have
foreach ($keywords as $value) {
$new_string = preg_replace("/\\b$value\\b/i", '<b>$0</b>', $string);
}
Note that '<b>$0</b>' uses single quotes. You can get away with double quotes here, because $0 isn't interpreted as a reference to a variable, but I think this is clearer. In general, you have to be careful with using a $ inside a double-quoted string, as you'll often get a reference to an existing variable unless you escape the $ as \$. Similarly, you should escape the backslash in \b inside the double quotes for the pattern; although it doesn't matter in this specific case, in general backslash is a meaningful character within double quotes.
I might have misunderstood your question, but if what you are struggling on is differentiating between upper-case letter (APPLE) and lower-case letter (apple), then the first thing you could do is convert the word into upper-case, or lower-case, and then run the tests to find it and put HTML tags around it. That is just my guess and maybe I completely misunderstood the question.
In the code exists offtopic error: the result value have been rewritten on not first loop iteration. And ending value of $new_string will be only last replacement.

Replace from one custom string to another custom string

How can I replace a string starting with 'a' and ending with 'z'?
basically I want to be able to do the same thing as str_replace but be indifferent to the values in between two strings in a 'haystack'.
Is there a built in function for this? If not, how would i go about efficiently making a function that accomplishes it?
That can be done with Regular Expression (RegEx for short).
Here is a simple example:
$string = 'coolAfrackZInLife';
$replacement = 'Stuff';
$result = preg_replace('/A.*Z/', $replacement, $string);
echo $result;
The above example will return coolStuffInLife
A little explanation on the givven RegEx /A.*Z/:
- The slashes indicate the beginning and end of the Regex;
- A and Z are the start and end characters between which you need to replace;
- . matches any single charecter
- * Zero or more of the given character (in our case - all of them)
- You can optionally want to use + instead of * which will match only if there is something in between
Take a look at Rubular.com for a simple way to test your RegExs. It also provides short RegEx reference
$string = "I really want to replace aFGHJKz with booo";
$new_string = preg_replace('/a[a-zA-z]+z/', 'boo', $string);
echo $new_string;
Be wary of the regex, are you wanting to find the first z or last z? Is it only letters that can be between? Alphanumeric? There are various scenarios you'd need to explain before I could expand on the regex.
use preg_replace so you can use regex patterns.

Categories