I want to use class method as a second variable in preg_replace, like
$x = preg_replace('/\[\[\[(.+)\]\]\]/',
(new ButtonGroupWidget(['idsForLoad' => ['\0']]))->run(),
$code);
Idea is generate buttons instead of [[[button id]]]. Yes, this is kinda strange) And yes, I know what smarty is)
You may use preg_replace_callback and pass a callback function instead of a string replacement pattern into that function. If you define the match object argument as $m, the whole match will reside in $m[0].
function repl($m) {
return (new ButtonGroupWidget(['idsForLoad' => [$m[0]]]))->run();
}
$code = "[[[btn1]]] [[[btn2]]]";
$x = preg_replace_callback('/\[\[\[(.+?)]]]/', 'repl', $code);
I also advise to use a lazy dot matching pattern in the regex to enforce the regex to match the shortest strings between [[[ and ]]]. Note that ] does not have to be escaped here.
Related
Is there a simple way I can have php camelcase a string for me? I am using the Laravel framework and I want to use some shorthand in a search feature.
It would look something like the following...
private function search(Array $for, Model $in){
$results = [];
foreach($for as $column => $value){
$results[] = $in->{$this->camelCase($column)}($value)->get();
}
return $results;
}
Called like
$this->search(['where-created_at' => '2015-25-12'], new Ticket);
So the resulting call in the search function I would be using is
$in->whereCreateAt('2015-25-12')->get();
The only thing is I can't figure out is the camel casing...
Have you considered using Laravel's built-in camel case functtion?
$camel = camel_case('foo_bar');
Full details can be found here:
https://laravel.com/docs/4.2/helpers#strings
So one possible solution that could be used is the following.
private function camelCase($string, $dontStrip = []){
/*
* This will take any dash or underscore turn it into a space, run ucwords against
* it so it capitalizes the first letter in all words separated by a space then it
* turns and deletes all spaces.
*/
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-z0-9'.implode('',$dontStrip).']+/', ' ',$string))));
}
It's a single line of code wrapped by a function with a lot going on...
The breakdown
What is the dontStrip variable?
Simply put it is an array that should contain anything you don't want removed from the camelCasing.
What are you doing with that variable?
We are taking every element in the array and putting them into a single string.
Think of it as something like this:
function implode($glue, $array) {
// This is a native PHP function, I just wanted to demonstrate how it might work.
$string = '';
foreach($array as $element){
$string .= $glue . $element;
}
return $string;
}
This way you're essentially gluing all your elements in your array together.
What's preg_replace, and what's it doing?
preg_replace is a function that uses a regular expression (also known as regex) to search for and then replace any values that it finds, which match the desired regex...
Explanation of the regex search
The regex used in the search above implodes your array $dontStrip onto a little bit a-z0-9 which just means any letter A to Z as well as numbers 0 to 9. The little ^ bit tells regex that it's looking for anything that isn't whatever comes after it. So in this case it's looking for any and all things that aren't in your array or a letter or number.
If you're new to regex and you want to mess around with it, regex101 is a great place to do it.
ucwords?
This can be most easily though of as upper case words. It will take any word (a word being any bit of characters separated by a space) and it will capitalize the first letter.
echo ucwords('hello, world!');
Will print `Hello, World!'
Okay I understand what preg_replace is, what str_replace?
str_replace is the smaller, less powerful but still very useful little brother/sister to preg_replace. By this I mean that it has a similar use. str_replace doesn't regex, but does use a literal string so whatever you type into the first parameter is exactly what it will look for.
Side note, it is worth mentioning for anyone considering only using preg_replace where str_replace would work just as well. str_replace has been noted to be benchmarked a bit faster than preg_replace on larger apps.
lcfirst What?
Since about PHP 5.3 we have been able to use the lcfirst function, which much like ucwords, it's just a text manipulation function. `lcfirst turns the first letter into it's lower case form.
echo lcfirst('HELLO, WORLD!');
Will print 'hELLO, WORLD!'
Results
All this in mind the camelCase function uses distinct non-alphanumeric characters as break points to turn a string to a camelCase string.
There's a general purpose open source library that contains a method that performs case convertions for several popular case formats. library is called TurboCommons, and the formatCase() method inside the StringUtils does camel case conversion.
https://github.com/edertone/TurboCommons
To use it, import the phar file to your project and:
use org\turbocommons\src\main\php\utils\StringUtils;
echo StringUtils::formatCase('sNake_Case', StringUtils::FORMAT_CAMEL_CASE);
// will output 'sNakeCase'
You can use Laravel's built-in camel case helper function
use Illuminate\Support\Str;
$converted = Str::camel('foo_bar');
// fooBar
Full details can be found here:
https://laravel.com/docs/9.x/helpers#method-camel-case
Use the in-built Laravel Helper Function - camel_case()
$camelCase = camel_case('your_text_here');
I have the following HTML statement
[otsection]Wallpapers[/otsection]
WALLPAPERS GO HERE
[otsection]Videos[/otsection]
VIDEOS GO HERE
What I am trying to do is replace the [otsection] tags with an html div. The catch is I want to increment the id of the div from 1->2->3, etc..
So for example, the above statement should be translated to
<div class="otsection" id="1">Wallpapers</div>
WALLPAPERS GO HERE
<div class="otsection" id="2">Videos</div>
VIDEOS GO HERE
As far as I can research, the best way to do this is via a preg_replace_callback to increment the id variable between each replacement. But after 1 hour of working on this, I just cant get it working.
Any assistance with this would be much appreciated!
Use the following:
$out = preg_replace_callback(
"(\[otsection\](.*?)\[/otsection\])is",
function($m) {
static $id = 0;
$id++;
return "<div class=\"otsection\" id=\"ots".$id."\">".$m[1]."</div>";
},
$in);
In particular, note that I used a static variable. This variable persists across calls to the function, meaning that it will be incremented every time the function is called, which happens for each match.
Also, note that I prepended ots to the ID. Element IDs should not start with numbers.
For PHP before 5.3:
$out = preg_replace_callback(
"(\[otsection\](.*?)\[/otsection\])is",
create_function('$m','
static $id = 0;
$id++;
return "<div class=\"otsection\" id=\"ots".$id."\">".$m[1]."</div>";
'),
$in);
Note: The following is intended to be a general answer and does not attempt to solve the OP's specific problem as it has already been addressed before.
What is preg_replace_callback()?
This function is used to perform a regular expression search-and-replace. It is similar to str_replace(), but instead of plain strings, it searches for a user-defined regex pattern, and then applies the callback function on the matched items. The function returns the modified string if matches are found, unmodified string otherwise.
When should I use it?
preg_replace_callback() is very similar to preg_replace() - the only difference is that instead of specifying a replacement string for the second parameter, you specify a callback function.
Use preg_replace() when you want to do a simple regex search and replace. Use preg_replace_callback() when you want to do more than just replace. See the example below for understanding how it works.
How to use it?
Here's an example to illustrate the usage of the function. Here, we are trying to convert a date string from YYYY-MM-DD format to DD-MM-YYYY.
// our date string
$string = '2014-02-22';
// search pattern
$pattern = '~(\d{4})-(\d{2})-(\d{2})~';
// the function call
$result = preg_replace_callback($pattern, 'callback', $string);
// the callback function
function callback ($matches) {
print_r($matches);
return $matches[3].'-'.$matches[2].'-'.$matches[1];
}
echo $result;
Here, our regular expression pattern searches for a date string of the format NNNN-NN-NN where N could be a digit ranging from 0 - 9 (\d is a shorthand representation for the character class [0-9]). The callback function will be called and passed an array of matched elements in the given string.
The final result will be:
22-02-2014
Note: The above example is for illustration purposes only. You should not use to parse dates. Use DateTime::createFromFormat() and DateTime::format() instead. This question has more details.
I'm getting Syntax error, unexpected T_LNUMBER, expecting T_VARIABLE or '$'
This is the code i'm using
function wpse44503_filter_content( $content ) {
$regex = '#src=("|\')'.
'(/images/(19|20)(0-9){2}/(0|1)(0-9)/[^.]+\.(jpg|png|gif|bmp|jpeg))'.
'("|\')#';
$replace = 'src="'.get_site_url( $2 ).'"';
$output = preg_replace( $regex, $replace, $content );
return $output;
}
This is the line where i'm getting that error $replace = 'src="'.get_site_url( $2 ).'"';
Can anyone help me to fix it?
Thanks
You can't have '$2' as a variable name. It must start with a letter or underscore.
http://php.net/manual/en/language.variables.basics.php
Variable names follow the same rules as other labels in PHP. A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
Edit Above was my original answer and is the correct answer to the simple "syntax error" question. More in-depth answer below...
You are trying to use $2 to represent "the second capture group", but you haven't done anything at that point to match your regex. Even if $2 was a valid PHP variable name, it still wouldn't be set at that point in your script. Because of this, you can determine that you are using preg_replace improperly and that it may not suit your actual needs.
Note that the preg_replace documentation doesn't support using $n as a separate variable outside of the replacement operation. In other words, 'foo' . $1 . 'bar' is not a valid replacement string, but 'foo$1bar' is.
Depending on the complexity of get_site_url, you have 2 options:
If get_site_url is simply adding a root directory or server name, you could change your replacement string to src="/myotherlocation$2". This will effectively replace "/image/..." with "/myotherlocation/image/..." in the img src. This will not work if get_site_url is doing something more complex.
If get_site_url is complex, you should use preg_replace_callback per other answers. Give the documentation a read and post a new question (or I guess update this question?) if you have trouble with the implementation.
What you're trying to do (ie replacing the matched string with the result of a function call) can't be done using preg_replace, you'll need to use preg_replace_callback instead to get a function called for every match.
A short example of preg_replace_callback;
$get_site_url = // Returns replacement
function($row) {
return '!'.$row[1].'!'; // row[1] is first "backref"
};
$str = 'olle';
$regex = '/(ll)/'; // String to match
$output = preg_replace_callback( // Match, calling get_site_url for replacement
$regex,
$get_site_url,
$str);
var_dump($output); // output "o!ll!e"
PHP variable names cant begin with a number.
$2 is not a valid PHP variable. If you meant the second group in the regex then you want to put \2 in a string. However, since you're passing it to a function then you'll need to use preg_replace_callback() instead and substitute appropriately in the callback.
if PHP variable begins with number use following:
when I was getting the following as the result set from thrid party API
Code Works
$stockInfo->original->data[0]->close_yesterday
Code Failed
$stockInfo->original->data[0]->52_week_low
Solution
$stockInfo->original->data[0]->{'52_week_high'}
$end = preg_replace($pattern, $replacement, $str);
How can I make the replacement string $replacement vary with each match in $str? For example, I want to replace each matched string with an associated image. Something about callbacks... right?
Yes, something with callbacks. Specifically preg_replace_callback, which makes repeated calls redundant. For a list of things to replace:
$src = preg_replace_callback('/(thing1|thing2|thing3)/', 'cb_vars', $src);
Where the callback can do some form of lookup or conversion:
function cb_vars($m) {
return strtoupper($m[1]);
}
Likewise can you do that inline with the normal preg_replace and the /e modifier.
You need to either use preg_replace_callback, or the /e modifier in the pattern string. The first is more powerful, but the second is more convenient if you are only after something relatively simple.
I need to read a string, detect a {VAR}, and then do a file_get_contents('VAR.php') in place of {VAR}. The "VAR" can be named anything, like TEST, or CONTACT-FORM, etc. I don't want to know what VAR is -- not to do a hard-coded condition, but to just see an uppercase alphanumeric tag surrounded by curly braces and just do a file_get_contents() to load it.
I know I need to use preg_match and preg_replace, but I'm stumbling through the RegExps on this.
How is this useful? It's useful in hooking WordPress.
Orion above has a right solution, but it's not really necessary to use a callback function in your simple case.
Assuming that the filenames are A-Z + hyphens you can do it in 1 line using PHP's /e flag in the regex:
$str = preg_replace('/{([-A-Z]+)}/e', 'file_get_contents(\'$1.html\')', $str);
This'll replace any instance of {VAR} with the contents of VAR.html. You could prefix a path into the second term if you need to specify a particular directory.
There are the same vague security worries as outlined above, but I can't think of anything specific.
You'll need to do a number of things. I'm assuming you can do the legwork to get the page data you want to preprocess into a string.
First, you'll need the regular expression to match correctly. That should be fairly easy with something like /{\w+}/.
Next you'll need to use all of the flags to preg_match to get the offset location in the page data. This offset will let you divide the string into the before, matching, and after parts of the match.
Once you have the 3 parts, you'll need to run your include, and stick them back together.
Lather, rinse, repeat.
Stop when you find no more variables.
This isn't terribly efficient, and there are probably better ways. You may wish to consider doing a preg_split instead, splitting on /[{}]/. No matter how you slice it you're assuming that you can trust your incoming data, and this will simplify the whole process a lot. To do this, I'd lay out the code like so:
Take your content and split it like so: $parts = preg_split('/[{}]/', $page_string);
Write a recursive function over the parts with the following criteria:
Halt when length of arg is < 3
Else, return a new array composed of
$arg[0] . load_data($arg[1]) . $arg[2]
plus whatever is left in $argv[3...]
Run your function over $parts.
You can do it without regexes (god forbid), something like:
//return true if $str ends with $sub
function endsWith($str,$sub) {
return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
}
$theStringWithVars = "blah.php cool.php awesome.php";
$sub = '.php';
$splitStr = split(" ", $theStringWithVars);
for($i=0;$i<count($splitStr);$i++) {
if(endsWith(trim($splitStr[$i]),$sub)) {
//file_get_contents($splitStr[$i]) etc...
}
}
Off the top of my head, you want this:
// load the "template" file
$input = file_get_contents($template_file_name);
// define a callback. Each time the regex matches something, it will call this function.
// whatever this function returns will be inserted as the replacement
function replaceCallback($matches){
// match zero will be the entire match - eg {FOO}.
// match 1 will be just the bits inside the curly braces because of the grouping parens in the regex - eg FOO
// convert it to lowercase and append ".html", so you're loading foo.html
// then return the contents of that file.
// BEWARE. GIANT MASSIVE SECURITY HOLES ABOUND. DO NOT DO THIS
return file_get_contents( strtolower($matches[1]) . ".html" );
};
// run the actual replace method giving it our pattern, the callback, and the input file contents
$output = preg_replace_callback("\{([-A-Z]+)\}", replaceCallback, $input);
// todo: print the output
Now I'll explain the regex
\{([-A-Z]+)\}
The \{ and \} just tell it to match the curly braces. You need the slashes, as { and } are special characters, so they need escaping.
The ( and ) create a grouping. Basically this lets you extract particular parts of the match. I use it in the function above to just match the things inside the braces, without matching the braces themselves. If I didn't do this, then I'd need to strip the { and } out of the match, which would be annoying
The [-A-Z] says "match any uppercase character, or a -
The + after the [-A-Z] means we need to have at least 1 character, but we can have up to any number.
Comparatively speaking, regular expression are expensive. While you may need them to figure out which files to load, you certainly don't need them for doing the replace, and probably shouldn't use regular expressions. After all, you know exactly what you are replacing so why do you need fuzzy search?
Use an associative array and str_replace to do your replacements. str_replace supports arrays for doing multiple substitutions at once. One line substitution, no loops.
For example:
$substitutions = array('{VAR}'=>file_get_contents('VAR.php'),
'{TEST}'=>file_get_contents('TEST.php'),
...
);
$outputContents = str_replace( array_keys($substitutions), $substitutions, $outputContents);