I am trying to use certain words in a array called keywords, which will be used to be replaced in a string by "as".
for($i = 0; $i<sizeof($this->keywords[$this->lang]); $i++)
{
$word = $this->keywords[$this->lang][$i];
$a = preg_replace("/\b$word\b/i", "as",$this->code);
}
It works with if I replace the variable $word with something like /\bhello\b/i, which then would replace all hello words with "as".
Is the approach am using even possible?
Before to be a pattern, it's a double quoted string, so variables will be replaced, it's not the problem.
The problem is that you use a loop to change several words and you store the result in $a:
the first iteration, all the occurences of the first word in $this->code are replaced and the new string is stored in $a.
but the next iteration doesn't reuse $a as third parameter to replace the next word, but always the original string $this->code
Result: after the for loop $a contains the original string but with only the occurences of the last word replaced with as.
When you want to replace several words with the same string, a way consists to build an alternation: word1|word2|word3.... It can easily be done with implode:
$alternation = implode('|', $this->keywords[$this->lang]);
$pattern = '~\b(?:' . $alternation . ')\b~i';
$result = preg_replace($pattern, 'as', $this->code);
So, when you do that, the string is parsed only once and all the words are replaced in one shot.
If you have a lot of words and a very long string:
Testing a long alternation has a significant cost. Even if the pattern starts with \b that highly reduces the possible positions for a match, your pattern will have hard time to succeed and more to fail.
Only in this particular case, you can use this another way:
First you define a placeholder (a character or a small string that can't be in your string, lets say §) that will be inserted in each positions of word boundaries.
$temp = preg_replace('~\b~', '§', $this->code);
Then you change all the keywords like this §word1§, §word2§ ... and you build an associative array where all values are the replacement string:
$trans = [];
foreach ($this->keywords[$this->lang] as $word) {
$trans['§' . $word . '§'] = 'as';
}
Once you have do that you add an empty string with the placeholder as key. You can now use the fast strtr function to perform the replacement:
$trans['§'] = '';
$result = strtr($temp, $trans);
The only limitation of this technic is that it is case-sensitive.
it will work if you keep it like bellow:
$a = preg_replace("/\b".$word."\b/i", "as",$this->code);
Related
I've started with preg_replace in PHP and I wonder how I can replace only first matching array key with a specified array value cause I set preg_replace number of changes parameter to '1' and it's changing more than one time anyways. I also splitted my string to single words and I'm examining them one by one:
<?php
$internal_message = 'Hey, this is awesome!';
$words = array(
'/wesome(\W|$)/' => 'wful',
'/wful(\W|$)/' => 'wesome',
'/^this(\W|$)/' => 'that',
'/^that(\W|$)/' => 'this'
);
$splitted_message = preg_split("/[\s]+/", $internal_message);
$words_num = count($splitted_message);
for($i=0; $i<$words_num; $i++) {
$splitted_message[$i] = preg_replace(array_keys($words), array_values($words), $splitted_message[$i], 1);
}
$message = implode(" ", $splitted_message);
echo $message;
?>
I want this to be on output:
Hey, that is awful
(one suffix change, one word change and stops)
Not this:
Hey, this is awesome
(two suffix changes, two word changes and back to original word & suffix...)
Maybe I can simplify this code? I also can't change order of the array keys and values cause there will be more suffixes and single words to change soon. I'm kinda newbie in php coding and I'll be thankful for any help ;>
You may use plain text in the associative array keys that you will use to create dynamic regex patterns from, and use preg_replace_callback to replace the found values with the replacements in one go.
$internal_message = 'Hey, this is awesome!';
$words = array(
'wesome' => 'wful',
'wful' => 'wesome',
'this' => 'that',
'that' => 'this'
);
$rx = '~(?:' . implode("|", array_keys($words)) . ')\b~';
echo "$rx\n";
$message = preg_replace_callback($rx, function($m) use ($words) {
return isset($words[$m[0]]) ? $words[$m[0]] : $m[0];
}, $internal_message);
echo $message;
// => Hey, that is awful!
See the PHP demo.
The regex is
~(?:wesome|wful|this|that)\b~
The (?:wesome|wful|this|that) is a non-capturing group that matches any of the values inside, and \b is a word boundary, a non-consuming pattern that ensures there is no letter, digit or _ after the suffix.
The preg_replace_callback parses the string once, and when a match occurs, it is passed to the anonymous function (function($m)) together with the $words array (use ($words)) and if the $words array contains the found key (isset($words[$m[0]])) the corresponding value is returned ($words[$m[0]]) or the found match is returned otherwise ($m[0]).
I'm working on a search / advertising system that matches a given ad group with keywords. Query is the string that is the search string, what we're looking for is the best and most efficient way to enhance the simple 'contains' script below that searches through the query, but looks for keyword matches on an AND (&&) explosion. With this script one could build either 'IF' or it could be a "CASE" below is the pseudo code:
$query = "apple berry tomato potato":
if contains ($query,"tomato") { }
if contains ($query,"potato,berry") { }
if contains ($query,"apple,berry") { }
else i.e. none of the above do { }
the function contains would use strpos but would also use some combination of explode to distinguish words that are separated by commas. So Apple,berry would be where a string contains the list of keywords separated by commas.
What would be the best way to write a contains script that searches through the query string and matches against the comma-separated values in the second parameter? Love your ideas. Thanks.
Here is a the classic simple 'contains' function, but it doesn't handle the comma-separated AND Explosion - it only works with single words or phrases
function contains($haystack,$needle)
{
return strpos($haystack, $needle) !== false;
}
Note : the enhanced contains function should scan for the match of the string on an AND basis. If commas exist in the $needle it needs to include all of the keywords to show a match. The simple contains script is explained on this post Check if String contains a given word . What I'm looking for is an expanded function by the same name that also searches for multiple keywords, not just a single word.
The $query string will always be space delimited.
The $needle string will always be comma delimited, or it could be delimited by spaces.
The main thing is that the function works in multiple directions
Suppose the $query = 'business plan template'
or $query = 'templates for business plan'
if you ran contains ($query,"business plan")
or contains ($query,"business,plan") both tests would show a match. The sequence of the words should not matter.
Here's a simple way. Just compare the count of $needle with the count of $needle(s) that are in $haystack using array_intersect():
function contains($haystack, $needle) {
$h = explode(' ', $haystack);
$n = explode(',', $needle);
return count(array_intersect($h, $n)) == count($n);
}
You could optionally pass $needle in as an array and then no need for that explode().
If you need it case-insensitive:
$h = explode(' ', strtolower($haystack));
$n = explode(',', strtolower($needle));
I have a string as : ABSOLUTEWORKLEADSTOSUCCESS
I have another string as : '+'
Now how can I insert the second string at various indexes lets say (3,6,9) of the first string.
PS: I know how to do it via substr(). What i am looking for is something using regex/preg_replace()
Disclaimer: I think that the solution below is stupid, but it does exactly what you ask for: inserts a plus sign at specific indexes using a regular expression and preg_replace function:
<?php
// find 3 groups: three first symbols, two after them, and two more
// find the pattern from the beginning of a string
$regex = '/^(.{3})(.{2})(.{2})/';
$str = 'ABSOLUTEWORKLEADSTOSUCCESS';
// perform a replace: use first group (3 symbols), insert a plus
// then use a second group (2 symbols) and insert another plus,
// then use a third group (2 more symbols) and insert the last plus
$out = preg_replace($regex, '$1+$2+$3+', $str);
echo $out;
Preview here.
You can't insert string with preg_replace, for that you need to loop through the indexes and insert second string at specific index by using substr_rplace as follow
$var = 'ABSOLUTEWORKLEADSTOSUCCESS';
$indexes = array(3,6,9);
$newString = $var;
foreach($indexes as $key=>$value) {
$newString = substr_replace($newString, '+', $value+$key, 0) . "\n";
}
echo $newString;
check output here : https://eval.in/714177
I have following issue:
I import WKT dynamicaly from DB into WKT Wicket Javascript library. I must do some substitutions to fit the WKT correctly. Since mysql fetches WKT AsText(SHAPE) i recive several arrays e.g. POLYGON((xxxx)),POLYGON((yyyy)) and so on.
First, I had to remove all "POLYGON" doing
$str = preg_replace('/^POLYGON/', '', $WKT[1]);
and add MULTIPOLYGON before <?php
tag in the wicket. It works.
Second, I must add comma between polygons, preicisely between "))((" brackets:
$str2 = str_replace(array('((', '))'), array('((', ')),'), $str);
It works but last comma remains what "slightly" deforms my multipolygon:
MULTIPOLYGON((xxx)),((yyy)),((zzz)),
How can I remove last comma?
I would be thankful for every regex or some other solution which can solve my problem.
In any string, you can remove the last X if you are sure that no X follows. So, you can use a negative lookahead: (,)(?!.*,), as seen here and replace it with empty string.
$result = preg_replace('/(,)(?!.*,)/', '', $str)
This doesn't look at the context though, it will just remove the last comma of any string, no matter where it is.
Thank you both - your answers were right and very helpful.
The problem was not string replacement. It was more the data fetching from DB.
Mysqli_fetch_array and mysqli_fetch_assoc return stringstringsring or arrayarrayarray for 3 rows fetched. That is why all commas were replaced.
I changed to mysqli_fetch_all ,then did minor replacements for each row (as array) and implode each one as variable. After i merged them into single variable, then I could apply your solutions. It is not sofisticated solution, but if it is packed into function it'll be fine.
($WKT = mysqli_fetch_all($result)) {
$str = preg_replace('/POLYGON/', '', $WKT[0]);
$str1 = preg_replace('/POLYGON/', '', $WKT[1]);
$str2 = preg_replace('/POLYGON/', '', $WKT[2]);
$str3 = implode($str);
$str4 = implode($str1);
$str5 = implode($str2);
$str6 = $str3 . $str4 . $str5;
$str7 = preg_replace('/\)\)/', ')),', $str6);
$str8 = rtrim($str7, ",");
echo $str8;
}
I have strings like:
t_est1_1
test213_4
tes_tsdfsdf_9
The common part of every string is the LAST underscore _ character.
I need to get the string before this character.
t_est1_12 --> test1
test213_4 --> test213
tes_tsdfsdf_9343 --> testsdfsdf
How can i achieve this in PHP?
Using the basic string functions strpos and substr.
http://fr.php.net/manual/fr/function.explode.php
$a = "abcdef_12345"
$b = array();
// $b[0] = "abcdef";
$b[0] = explode('_',$a,'1');
you can use preg_match function available in php
you need to write regular expression for that...
for example
to get this test1_12 ->> test1
$string='test1_12';
preg_match('((.+?)\_(.*))',$string,$match);
echo $match[1];
What you want is a simple explode, array_slice and implode, also using explode and end, you can get the "id" that is the common part too:
$description = implode('', array_slice(explode('_', $data), 0, -1));
$id = end(explode('_', $data));
As many _ you will have, you'll still be able to expode on them and retrieve the last item containing your id and the first items (0 to -1) will contain your description...