well, first of all let me say, before posting this I've tested many things, many time, but currently, I don't actually know what else to do, because nothing works fine for me.
This is the code I have currently:
<?php
// These are the arrays given by the application. All of them has an "%s" within.
// For example...
$arrs = array(
"this is a %s array" => "converted1 %s text",
"value %s test" => "converted2 %s text",
"test %s test" => "converted3 %s text"
);
$text = "This is a random text. Which can contains or not some of the expressions listed above. In this case it contains this: this is a magic array, value hey test, test php test";
// The output should be:
// "This is a random text. Which can contains or not some of the expressions listed above. In this case it contains this: CONVERTED magic TEXT, CONVERTED2 hey TEXT, CONVERTED3 php TEXT"
foreach($arrs as $k => $v){
// Seriously, I don't know what's next here... also I'm thinking this foreach is not right here.
}
?>
The main objective, is to write something random in a textbox input. So I check within the textbox if some of the array keys ($arrs) has been filled in. The problem, is that I can not detect it using strpos, due %s will be always random, so it's a bit harder to find its position...
Let's say I write "this is a random array" (it is into the array), so if we check its value, we'll see it would be "converted1 RANDOM text".
I've tested for using patterns, also with explode();, and preg_replace_callback, and nothing works for me. This is really driving me crazy...
Thank you very much guys.
Use regular expression.
<?php
$pattern = '~this is a ([^ ]*) array~U';
$replace = 'converted1 $1 text';
$text = preg_replace($pattern,$replace,$text);
you have assoc array already, you can change keys to be regular expressions and values to replace strings (with escaped group like $1 above). Also within foreach() you can check first:
<?php
if (preg_match($k,$text)) {
// do the replacing here
}
Note:
I've used [^ ]* to match single word. It's not only way, it may not be the best way. You can also use \w, but I personally don't like it :)
Edit:
Here you go with ready code that works (just tested it on my XAMPP)
<?php
$arrs = array(
"~this is a ([^ ]*) array~U" => "converted1 $1 text",
"~value ([^ ]*) test~U" => "converted2 $1 text",
"~test ([^ ]*) test~U" => "converted3 $1 text"
);
$text = "This is a random text. Which can contains or not some of the expressions listed above. In this case it contains this: this is a magic array, value hey test, test php test";
foreach($arrs as $k => $v){
if (preg_match($k,$text)) {
$text = preg_replace($k,$v,$text);
}
}
?>
Related
I have an email system, where user write a message and it will send the message.
The main problem which I just found, consider this code
$findEmail = $this->Data->field('body', array('id' => 1610));
//$getUserEmailTemplate will take frm dbase and e.g:
//Hi, ##MESSAGE##. From: StackOverflow
//It should change ##MESSAGE## part to data from $findEmail (in this example is the $74.97 ...)
$getUserEmailTemplate = $findUser['User']['email_template'];
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', $findEmail, $getUserEmailTemplate);
debug($findEmail);
debug($emailMessage);
and consider this input for the email for $findemail result:
$74.97
$735.00s
$email Message will result in:
.97
5.00s
How can I fix this? I feel like there's problem with my preg_replace pattern.
User template can be anything, as long as there is ##MESSAGE## which, that part will be changed to the user message input.
Thank you
Pre-parse the replacement text to escape the $ when followed by a number (remember that $n has special meaning when using in the replacement text). See the comment on the php.net docs page:
If there's a chance your replacement text contains any strings such as
"$0.95", you'll need to escape those $n backreferences:
<?php
function escape_backreference($x){
return preg_replace('/\$(\d)/', '\\\$$1', $x);
}
?>
The high-voted function escape_backreference is incomplete in the general case: it will only escape backreferences of the form $n, but not those of the form ${n} or \n.
To escape any potential backreferences, change
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', $findEmail, $getUserEmailTemplate);
to
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', addcslashes($findEmail, '\\$'), $getUserEmailTemplate);
Here is the reason:
The $1 portion of a replacement text stands for the first group/match found. So if you have abc 123 and you try preg_match('/([\w]+)-([\d]+)/'), regex will store internally something like $1 = abc and $2 = 123. Those variables are going to exists, even if they have no value.
So, for example:
$text = '[shortcode]';
$replacement = ' some $var $101 text';
$result = preg_replace('/\[shortcode\]/', $var, $text);
// returns "some $var 1 text"
As the match group $10 is empty is going to be replaced by a null string.
That's why you need to scape any $NN from your REPLACEMENT text before running the preg_replace function.
Happy coding.
If (ever) an template hast been in $getUserEmailTemplate, you did overwrite (destroy) it with this line;
$getUserEmailTemplate = "##MESSAGE##";
So just remove this line and make sure, $getUserEmailTemplate really contains anything and best of all a template.
Guess your template just includes "pure" PHP and tries to use $74 as variable, which does not exist and does not hold any data. So change the quotes in the template to single quotes '.
guessed template:
$tpl = "Sum: $74.97"; //results in "Sum: .97"
corrected template:
$tpl = 'Sum: $74.97'; //results in "Sum: $74.97"
I have an email system, where user write a message and it will send the message.
The main problem which I just found, consider this code
$findEmail = $this->Data->field('body', array('id' => 1610));
//$getUserEmailTemplate will take frm dbase and e.g:
//Hi, ##MESSAGE##. From: StackOverflow
//It should change ##MESSAGE## part to data from $findEmail (in this example is the $74.97 ...)
$getUserEmailTemplate = $findUser['User']['email_template'];
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', $findEmail, $getUserEmailTemplate);
debug($findEmail);
debug($emailMessage);
and consider this input for the email for $findemail result:
$74.97
$735.00s
$email Message will result in:
.97
5.00s
How can I fix this? I feel like there's problem with my preg_replace pattern.
User template can be anything, as long as there is ##MESSAGE## which, that part will be changed to the user message input.
Thank you
Pre-parse the replacement text to escape the $ when followed by a number (remember that $n has special meaning when using in the replacement text). See the comment on the php.net docs page:
If there's a chance your replacement text contains any strings such as
"$0.95", you'll need to escape those $n backreferences:
<?php
function escape_backreference($x){
return preg_replace('/\$(\d)/', '\\\$$1', $x);
}
?>
The high-voted function escape_backreference is incomplete in the general case: it will only escape backreferences of the form $n, but not those of the form ${n} or \n.
To escape any potential backreferences, change
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', $findEmail, $getUserEmailTemplate);
to
$emailMessage = preg_replace('/\B##MESSAGE##\B/u', addcslashes($findEmail, '\\$'), $getUserEmailTemplate);
Here is the reason:
The $1 portion of a replacement text stands for the first group/match found. So if you have abc 123 and you try preg_match('/([\w]+)-([\d]+)/'), regex will store internally something like $1 = abc and $2 = 123. Those variables are going to exists, even if they have no value.
So, for example:
$text = '[shortcode]';
$replacement = ' some $var $101 text';
$result = preg_replace('/\[shortcode\]/', $var, $text);
// returns "some $var 1 text"
As the match group $10 is empty is going to be replaced by a null string.
That's why you need to scape any $NN from your REPLACEMENT text before running the preg_replace function.
Happy coding.
If (ever) an template hast been in $getUserEmailTemplate, you did overwrite (destroy) it with this line;
$getUserEmailTemplate = "##MESSAGE##";
So just remove this line and make sure, $getUserEmailTemplate really contains anything and best of all a template.
Guess your template just includes "pure" PHP and tries to use $74 as variable, which does not exist and does not hold any data. So change the quotes in the template to single quotes '.
guessed template:
$tpl = "Sum: $74.97"; //results in "Sum: .97"
corrected template:
$tpl = 'Sum: $74.97'; //results in "Sum: $74.97"
I have this code for my search box of my website:
<? echo preg_replace("/({$term})/i", "<b>$0</b>", NoticiaInfo($news_results, 'subtitulo')); ?>
And I'd like to know if there is any way to make, for example, the letter "c" replace an "ç" with regex.
So, if I search for "ca", the letters "çã" of "Função" will be bolded...
Is there any way to do this with regex?
You would need to use preg_replace with an array. try:
<?php
$replacements = array(
'/a/' => '<b>ã</b>',
'/c/' => '<b>ç</b>'
);
echo preg_replace(array_keys($replacements), array_values($replacements), NoticiaInfo($news_results, 'subtitulo'));
?>
and fill out the $replacements array with the other chars you'd like to replace.
#Ranty makes a good point so you could try using str_replace instead and your code will become:
<?php
$replacements = array(
'a' => '<b>ã</b>',
'c' => '<b>ç</b>'
);
echo str_replace(array_keys($replacements), array_values($replacements), NoticiaInfo($news_results, 'subtitulo'));
?>
No pretty way to do this and preserve the accent marks. You first have to assemble a list of all possible permutations of the search term with substituted chars.
<?
$termList = array($term);
// You'll need to programmatically create this list
// This is just a sample, assuming that $term == 'Funcao';
$termList[] = 'Funcão';
$termList[] = 'Funçao';
$termList[] = 'Função';
$bodyText = NoticiaInfo($news_results, 'subtitulo');
foreach($termList as $searchTerm) {
$bodyText = preg_replace("/({$searchTerm})/i", "<b>$0</b>", $bodyText);
}
echo $bodyText;
?>
Programmatically creating the search term array will be a nightmare, but there are numerous password cracking apps that do that already (ex: they sub chars for digits and create every permutation thereof) so the logic exists somewhere. Though, when you start getting longer search strings the overhead of this starts getting out of hand.
Of course, if you don't care about maintaining the accent marks this becomes much easier.
Does anyone know a better implementation of sprintf in PHP? I was looking for something like the string formatting we have in python:
print "Hello %(name)s. Your %(name)s has just been created!" % { 'name' : 'world' }
# prints::: Hello world. Your world has just been created!
This is pretty handy to avoid repeating the same variables without need, such as:
sprintf("Hello %s. Your %s has just been created!", 'world', 'world');
# prints::: Hello world. Your world has just been created!
I guess is fairly easy to build this on my own, but don't wanna reinvent the wheel, if you know what I mean... but I could not find (maybe wrong search keywords) any trace of this anywhere.
If anyone can help, I appreciate.
Cheers,
You can use positional (but not named) arguments to do this, for example
printf('Hello %1$s. Your %1$s has just been created!', 'world');
A word of caution here: you must use single quotes, otherwise the dollar signs will cause PHP to try to substitute $s with the value of this variable (which does not exist).
If you want named arguments then you will have to do this with a regular expression; for example, see How to replace placeholders with actual values?.
You can repeat the same placeholder with PHP's sprintf (though it might not look as nice):
$str = sprintf('%1$s %1$s', 'yay');
// str: 'yay yay'
You can use n$ right after the % in a placeholder, where n is the argument position (so %1$s refers to the first argument (as a string), %2$s refers to the second, etc.). As you can see above, when you use placeholders that are positionally-bound, you can repeat them within the string without duplicating arguments when you call sprintf.
The following code was stolen from a post by Salathe on TalkPHP.
$szAdjective = 'fluffy';
$szNoun = 'cat';
printf('Yesterday, I saw a %s. '.
'It was a %s %s! I have '.
'never seen a %s quite so %s.',
$szNoun,
$szAdjective,
$szNoun,
$szNoun,
$szAdjective);
printf('Yesterday, I saw a %1$s. '.
'It was a %2$s %1$s! I have '.
'never seen a %1$s quite so %2$s.',
$szNoun,
$szAdjective);
The above two expressions are equivalent and will both output
"Yesterday, I saw a cat. It was a fluffy cat! I have never seen a cat quite so fluffy."
I answered this very question in another post: vsprintf or sprintf with named arguments, or simple template parsing in PHP
But this has the same format youre looking for!
This is really the best way to go imho. No cryptic characters, just use the key names!
As taken from the php site:
http://www.php.net/manual/en/function.vsprintf.php
function dsprintf() {
$data = func_get_args(); // get all the arguments
$string = array_shift($data); // the string is the first one
if (is_array(func_get_arg(1))) { // if the second one is an array, use that
$data = func_get_arg(1);
}
$used_keys = array();
// get the matches, and feed them to our function
$string = preg_replace('/\%\((.*?)\)(.)/e',
'dsprintfMatch(\'$1\',\'$2\',\$data,$used_keys)',$string);
$data = array_diff_key($data,$used_keys); // diff the data with the used_keys
return vsprintf($string,$data); // yeah!
}
function dsprintfMatch($m1,$m2,&$data,&$used_keys) {
if (isset($data[$m1])) { // if the key is there
$str = $data[$m1];
$used_keys[$m1] = $m1; // dont unset it, it can be used multiple times
return sprintf("%".$m2,$str); // sprintf the string, so %s, or %d works like it should
} else {
return "%".$m2; // else, return a regular %s, or %d or whatever is used
}
}
$str = <<<HITHERE
Hello, %(firstName)s, I know your favorite PDA is the %(pda)s. You must have bought %(amount)s
HITHERE;
$dataArray = array(
'pda' => 'Newton 2100',
'firstName' => 'Steve',
'amount' => '200'
);
echo dsprintf($str, $dataArray);
// Hello, Steve, I know your favorite PDA is the Newton 2100. You must have bought 200
I've written a small component that allow you to make name substitutions in php strings. It's called StringTemplate.
With it you can get what you want with a code like this:
$engine = new StringTemplate\Engine;
$engine->render(
'"Hello {name}. Your {name} has just been created!"',
[
'name' => 'world',
]
);
//Prints "Hello world. Your world has just been created!"
Multidimensional array value are allowed too. Hope that can help.
So I'm working on a project that will allow users to enter poker hand histories from sites like PokerStars and then display the hand to them.
It seems that regex would be a great tool for this, however I rank my regex knowledge at "slim to none".
So I'm using PHP and looping through this block of text line by line and on lines like this:
Seat 1: fabulous29 (835 in chips)
Seat 2: Nioreh_21 (6465 in chips)
Seat 3: Big Loads (3465 in chips)
Seat 4: Sauchie (2060 in chips)
I want to extract seat number, name, & chip count so the format is
Seat [number]: [letters&numbers&characters] ([number] in chips)
I have NO IDEA where to start or what commands I should even be using to optimize this.
Any advice is greatly appreciated - even if it is just a link to a tutorial on PHP regex or the name of the command(s) I should be using.
I'm not entirely sure what exactly to use for that without trying it, but a great tool I use all the time to validate my RegEx is RegExr which gives a great flash interface for trying out your regex, including real time matching and a library of predefined snippets to use. Definitely a great time saver :)
Something like this might do the trick:
/Seat (\d+): ([^\(]+) \((\d+)in chips\)/
And some basic explanation on how Regex works:
\d = digit.
\<character> = escapes character, if not part of any character class or subexpression. for example:
\t
would render a tab, while \\t would render "\t" (since the backslash is escaped).
+ = one or more of the preceding element.
* = zero or more of the preceding element.
[ ] = bracket expression. Matches any of the characters within the bracket. Also works with ranges (ex. A-Z).
[^ ] = Matches any character that is NOT within the bracket.
( ) = Marked subexpression. The data matched within this can be recalled later.
Anyway, I chose to use
([^\(]+)
since the example provides a name containing spaces (Seat 3 in the example). what this does is that it matches any character up to the point that it encounters an opening paranthesis.
This will leave you with a blank space at the end of the subexpression (using the data provided in the example). However, his can easily be stripped away using the trim() command in PHP.
If you do not want to match spaces, only alphanumerical characters, you could so something like this:
([A-Za-z0-9-_]+)
Which would match any letter (within A-Z, both upper- & lower-case), number as well as hyphens and underscores.
Or the same variant, with spaces:
([A-Za-z0-9-_\s]+)
Where "\s" is evaluated into a space.
Hope this helps :)
Look at the PCRE section in the PHP Manual. Also, http://www.regular-expressions.info/ is a great site for learning regex. Disclaimer: Regex is very addictive once you learn it.
I always use the preg_ set of function for REGEX in PHP because the PERL-compatible expressions have much more capability. That extra capability doesn't necessarily come into play here, but they are also supposed to be faster, so why not use them anyway, right?
For an expression, try this:
/Seat (\d+): ([^ ]+) \((\d+)/
You can use preg_match() on each line, storing the results in an array. You can then get at those results and manipulate them as you like.
EDIT:
Btw, you could also run preg_match_all on the entire block of text (instead of looping through line-by-line) and get the results that way, too.
Check out preg_match.
Probably looking for something like...
<?php
$str = 'Seat 1: fabulous29 (835 in chips)';
preg_match('/Seat (?<seatNo>\d+): (?<name>\w+) \((?<chipCnt>\d+) in chips\)/', $str, $matches);
print_r($matches);
?>
*It's been a while since I did php, so this could be a little or a lot off.*
May be it is very late answer, But I am interested in answering
Seat\s(\d):\s([\w\s]+)\s\((\d+).*\)
http://regex101.com/r/cU7yD7/1
Here's what I'm currently using:
preg_match("/(Seat \d+: [A-Za-z0-9 _-]+) \((\d+) in chips\)/",$line)
To process the whole input string at once, use preg_match_all()
preg_match_all('/Seat (\d+): \w+ \((\d+) in chips\)/', $preg_match_all, $matches);
For your input string, var_dump of $matches will look like this:
array
0 =>
array
0 => string 'Seat 1: fabulous29 (835 in chips)' (length=33)
1 => string 'Seat 2: Nioreh_21 (6465 in chips)' (length=33)
2 => string 'Seat 4: Sauchie (2060 in chips)' (length=31)
1 =>
array
0 => string '1' (length=1)
1 => string '2' (length=1)
2 => string '4' (length=1)
2 =>
array
0 => string '835' (length=3)
1 => string '6465' (length=4)
2 => string '2060' (length=4)
On learning regex: Get Mastering Regular Expressions, 3rd Edition. Nothing else comes close to the this book if you really want to learn regex. Despite being the definitive guide to regex, the book is very beginner friendly.
Try this code. It works for me
Let say that you have below lines of strings
$string1 = "Seat 1: fabulous29 (835 in chips)";
$string2 = "Seat 2: Nioreh_21 (6465 in chips)";
$string3 = "Seat 3: Big Loads (3465 in chips)";
$string4 = "Seat 4: Sauchie (2060 in chips)";
Add to array
$lines = array($string1,$string2,$string3,$string4);
foreach($lines as $line )
{
$seatArray = explode(":", $line);
$seat = explode(" ",$seatArray[0]);
$seatNumber = $seat[1];
$usernameArray = explode("(",$seatArray[1]);
$username = trim($usernameArray[0]);
$chipArray = explode(" ",$usernameArray[1]);
$chipNumber = $chipArray[0];
echo "<br>"."Seat [".$seatNumber."]: [". $username."] ([".$chipNumber."] in chips)";
}
you'll have to split the file by linebreaks,
then loop thru each line and apply the following logic
$seat = 0;
$name = 1;
$chips = 2;
foreach( $string in $file ) {
if (preg_match("Seat ([1-0]): ([A-Za-z_0-9]*) \(([1-0]*) in chips\)", $string, $matches)) {
echo "Seat: " . $matches[$seat] . "<br>";
echo "Name: " . $matches[$name] . "<br>";
echo "Chips: " . $matches[$chips] . "<br>";
}
}
I haven't ran this code, so you may have to fix some errors...
Seat [number]: [letters&numbers&characters] ([number] in chips)
Your Regex should look something like this
Seat (\d+): ([a-zA-Z0-9]+) \((\d+) in chips\)
The brackets will let you capture the seat number, name and number of chips in groups.