Execute PHP command inside of preg_replace - php

Is it possible to execute a php command e.g. strtolower() through preg_replace()?
I would like to make just a party of a array in lower case letters and the other part into uppercase. The problem is that the letters are dynamically changing and are not fixed, just one word stays the same but the rest not.
e.g.
arraypart1 (should stay uppercase) (constantword)+arraypart2 (both should change to lower case letters)
arraypart2 is also changing in size of character numbers.

It's not 100% clear what you want to do, but I think it's the following: extract words from a string and lowercase/uppercase some of them according to their presence in one of arrays. preg_replace_callback will help you.
PHP 5.3 and higher:
$initial = "Mary had a little lamb";
$toupper = array("Mary", "lamb");
$tolower = array("had", "any");
$out = preg_replace_callback(
"/\b(?P<word>\w+)\b/", // for every found word
function($matches) use ($toupper, $tolower) { // call this function
if (in_array($toupper, $matches['word'])) // is this word in toupper array?
return strtoupper($matches['word']);
if (in_array($tolower, $matches['word'])) // is this word in tolower array?
return strtolower($matches['word']);
// ... any other logic
return $matches['word']; // if nothing was returned before, return original word
},
$initial);
print $out; // "MARY had a little LAMB"
If you have other arrays that need to be taken in account, put them in use statement so that they are available inside anonymous function.
PHP >= 4.0.5:
$initial = "Mary had a little lamb";
$toupper = array("Mary", "lamb");
$tolower = array("had", "any");
function replace_callback($matches) {
global $tolower, $toupper;
if (in_array($toupper, $matches['word'])) // is this word in toupper array?
return strtoupper($matches['word']);
if (in_array($tolower, $matches['word'])) // is this word in tolower array?
return strtolower($matches['word']);
// ... any other logic
return $matches['word']; // if nothing was returned before, return original word
}
$out = preg_replace_callback(
"/\b(?P<word>\w+)\b/", // for every found word
'replace_callback', // call this function
$initial);
print $out; // "MARY had a little LAMB"
As you see, nothing changed significantly, I just replaced anonymous function with a named one. To provide it with other arrays of strings, refer to them with global keyword.

I hope I understand you correctly ,preg_replace is a function and like all other functions you can do:
preg_replace(strtolower($val),$pattern,$someString);
preg_replace would be called with the lowercase version of $val

Related

very large php string magically turns into array

I am getting an "Array to string conversion error on PHP";
I am using the "variable" (that should be a string) as the third parameter to str_replace. So in summary (very simplified version of whats going on):
$str = "very long string";
str_replace("tag", $some_other_array, $str);
$str is throwing the error, and I have been trying to fix it all day, the thing I have tried is:
if(is_array($str)) die("its somehow an array");
serialize($str); //inserted this before str_replace call.
I have spent all day on it, and no its not something stupid like variables around the wrong way - it is something bizarre. I have even dumped it to a file and its a string.
My hypothesis:
The string is too long and php can't deal with it, turns into an array.
The $str value in this case is nested and called recursively, the general flow could be explained like this:
--code
//pass by reference
function the_function ($something, &$OFFENDING_VAR, $something_else) {
while(preg_match($something, $OFFENDING_VAR)) {
$OFFENDING_VAR = str_replace($x, y, $OFFENDING_VAR); // this is the error
}
}
So it may be something strange due to str_replace, but that would mean that at some point str_replace would have to return an array.
Please help me work this out, its very confusing and I have wasted a day on it.
---- ORIGINAL FUNCTION CODE -----
//This function gets called with multiple different "Target Variables" Target is the subject
//line, from and body of the email filled with << tags >> so the str_replace function knows
//where to replace them
function perform_replacements($replacements, &$target, $clean = TRUE,
$start_tag = '<<', $end_tag = '>>', $max_substitutions = 5) {
# Construct separate tag and replacement value arrays for use in the substitution loop.
$tags = array();
$replacement_values = array();
foreach ($replacements as $tag_text => $replacement_value) {
$tags[] = $start_tag . $tag_text . $end_tag;
$replacement_values[] = $replacement_value;
}
# TODO: this badly needs refactoring
# TODO: auto upgrade <<foo>> to <<foo_html>> if foo_html exists and acting on html template
# Construct a regular expression for use in scanning for tags.
$tag_match = '/' . preg_quote($start_tag) . '\w+' . preg_quote($end_tag) . '/';
# Perform the substitution until all valid tags are replaced, or the maximum substitutions
# limit is reached.
$substitution_count = 0;
while (preg_match ($tag_match, $target) && ($substitution_count++ < $max_substitutions)) {
$target = serialize($target);
$temp = str_replace($tags,
$replacement_values,
$target); //This is the line that is failing.
unset($target);
$target = $temp;
}
if ($clean) {
# Clean up any unused search values.
$target = preg_replace($tag_match, '', $target);
}
}
How do you know $str is the problem and not $some_other_array?
From the manual:
If search and replace are arrays, then str_replace() takes a value
from each array and uses them to search and replace on subject. If
replace has fewer values than search, then an empty string is used for
the rest of replacement values. If search is an array and replace is a
string, then this replacement string is used for every value of
search. The converse would not make sense, though.
The second parameter can only be an array if the first one is as well.

PHP str_replace with function

Is it possible use str_replace() and use function in replace?
$value = "gal($data)";
$replace = str_replace($dat, $value, $string);
gal($data) is a function and I need replace one code for this function and show, but the script only give me finally this gal($data), and the function no show nothing
Is it possible use str_replace() for replace code and replace by the function or some similar method?
PHP has a function called preg_replace_callback that does this. When you pass it a callback function, it will pass each match through your function. You can choose to replace, based upon the matched value, or ignore it.
As an example, suppose I have a pattern that matches various strings, such as [a-z]+. I may not want to replace every instance with the same value, so I can call a function upon eat match found, and determine how I ought to respond:
function callback ($match) {
if ($match[0] === "Jonathan")
return "Superman";
return $match[0];
}
$subject = "This is about Jonathan.";
$pattern = "/[a-z]+/i";
$results = preg_replace_callback($pattern, "callback", $subject);
// This is about Superman.
echo $results;
Note in our callback function how I am able to return special values for certain matches, and not all matches.
Expanding Abbreviations
Another example would be a lookup. Suppose we wanted to find abbreviations of programming languages, and replace them with their full titles. We may have an array that has abbreviations as keys, with long-names as values. We could then use our callback ability to lookup the full-length names:
function lookup ($match) {
$langs = Array(
"JS" => "JavaScript",
"CSS" => "Cascading Style Sheets",
"JSP" => "Java Server Pages"
);
return $langs[$match[0]] ?: $match[0];
}
$subject = "Does anybody know JS? Or CSS maybe? What about PHP?";
$pattern = "/(js|css|jsp)/i";
$results = preg_replace_callback($pattern, "lookup", $subject);
// Does anybody know JavaScript? Or Cascading Style Sheets maybe? What about PHP?
echo $results;
So every time our regular expression finds a match, it passes the match through lookup, and we can return the appropriate value, or the original value.

php replace regular expression instead of string replace

I'm trying to give my client the ability to call a function that has various code snippets by inserted a short code in their WYSIWYG editor.
For example, they will write something like...
[getSnippet(1)]
This will call my getSnippet($id) php function and output the appropriate 'chunk'.
It works when I hard code the $id like this...
echo str_replace('[getSnippet(1)]',getSnippet(1),$rowPage['sidebar_details']);
However, I really want to make the '1' dynamic. I'm sort of on the right track with something like...
function getSnippet($id) {
if ($id == 1) {
echo "car";
}
}
$string = "This [getSnippet(1)] is a sentence.This is the next one.";
$regex = '#([getSnippet(\w)])#';
$string = preg_replace($regex, '. \1', $string);
//If you want to capture more than just periods, you can do:
echo preg_replace('#(\.|,|\?|!)(\w)#', '\1 \2', $string);
Not quite working :(
Firstly in your regex you need to add literal parentheses (the ones you have just capture \w but that will not match the parentheses themselves):
$regex = '#(\[getSnippet\((\w)\)\])#';
I also escaped the square brackets, otherwise they will open a character class. Also be aware that this captures only one character for the parameter!
But I recommend you use preg_replace_callback, with a regex like this:
function getSnippet($id) {
if ($id == 1) {
return "car";
}
}
function replaceCallback($matches) {
return getSnippet($matches[1]);
}
$string = preg_replace_callback(
'#\[getSnippet\((\w+)\)\]#',
'replaceCallback',
$string
);
Note that I changed the echo in your getSnippet to a return.
Within the callback $matches[1] will contain the first captured group, which in this case is your parameter (which now allows for multiple characters). Of course, you could also adjust you getSnippet function to read the id from the $matches array instead of redirecting through the replaceCallback.
But this approach here is slightly more flexible, as it allows you to redirect to multiple functions. Just as an example, if you changed the regex to #\[(getSnippet|otherFunction)\((\w+)\)\]# then you could find two different functions, and replaceCallback could find out the name of the function in $matches[1] and call the function with the parameter $matches[2]. Like this:
function getSnippet($id) {
...
}
function otherFunction($parameter) {
...
}
function replaceCallback($matches) {
return $matches[1]($matches[2]);
}
$string = preg_replace_callback(
'#\[(getSnippet|otherFunction)\((\w+)\)\]#',
'replaceCallback',
$string
);
It really depends on where you want to go with this. The important thing is, there is no way of processing an arbitrary parameter in a replacement without using preg_replace_callback.

Replace text within brackets with thus-named variable in PHP

I want to replace all strings in square brackets ([]) with a randomly chosen item from an array that's named that string.
It's very similar to this issue, but with a twist, in that I want to replace different brackets' contents with strings from arrays named that.
An example should make this a bit clearer.
So say I've got the string
"This is a very [adjective] [noun], and this is a [adjective] [noun]."
And the variables:
$adjective = array("big","small","good","bad");
$noun = array("house","dog","car");
And we want it to return "This is a very big house, and this is a good dog." or whatever, by choosing randomly. That is, I want to write a PHP function that will replace each [string] with a randomly chosen item from the array named $string. For now it doesn't matter if by randomly choosing it ends up repeating choices, but it must make a fresh choice for each [] item.
I hope I've explained this clearly. If you get what I'm trying to achieve and can think of a better way to do it I'd be very grateful.
Algorithm
Match for this regex: (\[.*?\])
For each match group pick an item from the related array.
Replace in string by order.
Implementation
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun].";
$adjective = array("big","small","good","bad");
$noun = array("house","dog","car");
// find matches against the regex and replaces them the callback function.
$result = preg_replace_callback(
// Matches parts to be replaced: '[adjective]', '[noun]'
'/(\[.*?\])/',
// Callback function. Use 'use()' or define arrays as 'global'
function($matches) use ($adjective, $noun) {
// Remove square brackets from the match
// then use it as variable name
$array = ${trim($matches[1],"[]")};
// Pick an item from the related array whichever.
return $array[array_rand($array)];
},
// Input string to search in.
$string
);
print $result;
Explanation
preg_replace_callback function performs a regular expression search and replace using provided callback function.
First parameter is regular expression to match (enclosed between slashes): /(\[.*?\])/
Second parameter is callback function to call for each match. Takes the current match as parameter.
We have to use use() here to access the arrays from inside the function, or define the arrays as global: global $adjective = .... Namely, we have to do one of the followings:
a) Define arrays as global:
...
global $adjective = array("big","small","good","bad");
global $noun = array("house","dog","car");
...
function($matches) {
...
b) Use use:
...
$adjective = array("big","small","good","bad");
$noun = array("house","dog","car");
...
function($matches) use ($adjective, $noun) {
...
First line of the callback function:
trim: Removes square brackets ([]) from the match using trim function.
${}: Creates a variable to use as array name with the match name. For example, if the $match is [noun] then trim($matches[1],"[]") returns noun (without brackets) and ${noun} becomes the array name: $noun. For more information on the topic, see variable variables.
Second line randomly picks an index number available for the $array and then returns the element at this position.
Third parameter is the input string.
The code below will do the work:
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]."
function replace_word ( $matches )
{
$replaces = array(
'[adjective]' => array("big", "small", "good", "bad"),
'[noun]' => array("house", "dog", "car")
);
return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])];
}
echo preg_replace_callback("(\[.*?\])", "replace_word", $string);
First, we regular expression match on the [something] parts of the word, and call the replace_word() callback function on it with preg_replace_callback(). This function has an internal $replaces two dimension deep array defined inside, each row defined in a [word type] => array('rep1', 'rep2', ...) format.
The tricky and a bit obfuscated line is the return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])];. If I chunk it down a bit, it'll be a lot more parsable for you:
$random = array_rand( $replaces[ $matches[0] ] );
$matches[0] is the word type, this is the key in the $replaces array we are searching for. This was found by regular expression in the original string. array_rand() basically selects one element of the array, and returns its numerical index. So $random right now is an integer somewhere between 0 and the (number of elements - 1) of the array containing the replaces.
return $replaces[ $matches[0] ][$random];
This will return the $randomth element from the replace array. In the code snippet, these two lines are put together into one line.
Showing one element only once
If you want disjunct elements (no two adjective or noun repeated twice), then you will need to do another trick. We will set the $replaces array to be defined not inside the replace_word() function, but outside it.
$GLOBALS['replaces'] = array(
'[adjective]' => array("big", "small", "good", "bad"),
'[noun]' => array("house", "dog", "car")
);
Inside the function, we will set the local $replaces variable to be a reference to the newly set array, with calling $replaces = &$GLOBALS['replaces'];. (The & operator sets it a reference, so everything we do with $replaces (remove and add elements, for example) modifies the original array too. Without it, it would only be a copy.)
And before arriving on the return line, we call unset() on the currently to-be-returned key.
unset($replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]);
The function put together now looks like this:
function replace_word ( $matches )
{
$replaces = &$GLOBALS['replaces'];
unset($replaces[$matches[0]][array_rand($replaces[ $matches[0] ])]);
return $replaces[$matches[0]][array_rand($replaces[ $matches[0] ])];
}
And because $replaces is a reference to the global, the unset() updates the original array too. The next calling of replace_word() will not find the same replace again.
Be careful with the size of the array!
Strings containing more replace variables than the amount of replace values present will throw an Undefined index E_NOTICE. The following string won't work:
$string = "This is a very [adjective] [noun], and this is a [adjective] [noun]. This is also an [adjective] [noun] with an [adjective] [noun].";
One of the outputs look like the following, showing that we ran out of possible replaces:
This is a very big house, and this is a big house. This is also an small with an .
Another good (easier) method of doing this (not my solution)
https://stackoverflow.com/a/15773754/2183699
Using a foreach to check on which variables you want to replace and replacing them with
str_replace();
You can use preg_match and str_replace function to achive this goal.
First find the matches using preg_match function and then create search & replace array from the result.
Call str_replace function by passing the previous arrays as parameters.
This is my minor update to mmdemirbas' answer above. It lets you set the variables outside of the function (i.e. use globals, as said).
$result = preg_replace_callback(
// Matches parts to be replaced: '[adjective]', '[noun]'
'/(\[.*?\])/',
// Callback function. Use 'use()' or define arrays as 'global'
function($matches) use ($adjective, $noun) {
// Remove square brackets from the match
// then use it as variable name
$arrayname = trim($matches[1],"[]");
$array = $GLOBALS[$arrayname];
// Pick an item from the related array whichever.
return $array[array_rand($array)];
},
// Input string to search in.
$string
);
print $result;

stristr Case-insensitive search PHP

Please excuse my noob-iness!
I have a $string, and would like to see if it contains any one or more of a group of words, words link ct, fu, sl** ETC. So I was thinking I could do:
if(stristr("$input", "dirtyword1"))
{
$input = str_ireplace("$input", "thisWillReplaceDirtyWord");
}
elseif(stristr("$input", "dirtyWord1"))
{
$input = str_ireplace("$input", "thisWillReplaceDirtyWord2");
}
...ETC. BUT, I don't want to have to keep doing if/elseif/elseif/elseif/elseif...
Can't I just do a switch statement OR have an array, and then simply say something like?:
$dirtywords = { "f***", "c***", w****", "bit**" };
if(stristr("$input", "$dirtywords"))
{
$input = str_ireplace("$input", "thisWillReplaceDirtyWord");
}
I'd appreciate any help at all
Thank you
$dirty = array("fuc...", "pis..", "suc..");
$censored = array("f***", "p***", "s***");
$input= str_ireplace($dirty, $censored , $input);
Note, that you don't have to check stristr() to do a str_ireplace()
http://php.net/manual/en/function.str-ireplace.php
If search and replace are arrays, then str_ireplace() takes a value from each array and uses them to do search and replace on subject. If replace has fewer values than search, then an empty string is used for the rest of replacement values. If search is an array and replace is a string, then this replacement string is used for every value of search.
Surely not the best solution since I don't know too much PHP, but what about a loop ?
foreach (array("word1", "word2") as $word)
{
if(stristr("$input", $word))
{
$input = str_ireplace("$input", $word" "thisWillReplaceDirtyWord");
}
}
When you have several objects to test, think "loop" ;-)

Categories