I'm using preg_match() function which determines whether a function is executed.
if( preg_match( '/^([0-9]+,){0,3}[0-9]+$/', $string ) ) { ... }
However I have to use a integer variable and integrate it in the regular expression:
$integer = 4;
if( preg_match( '/^([0-9]+,){0,' . $integer . '}[0-9]+$/', $string ) ) { ... }
but it doesn't match when it should. How is it that I can't concatenate a variable in the regex string?
Edit:
strval($integer) has solved my problem. I had to convert the integer value into a string before concatenating it (although I don't understand why):
$integer = 4;
if( preg_match( '/^([0-9]+,){0,' . strval($integer) . '}[0-9]+$/', $string ) ) { ... }
Whenever concatenating a variable into a regex pattern, you should do so by passing the variable to the preg_quote function.
However, if the variable var is, like it is in your example 4, that won't make any difference. The pattern you're using will be:
/^([0-9]+,){0,4}[0-9]+$/
In which case, if it doesn't work: check the $string value, and make sure the pattern matches. BTW, /^(\d+,){,4}\d+$/ is shorter and does the same thing.
Calling strval doesn't solve anything, AFAIK... I've tested the code without strval, using the following snippet:
$string = '1234,32';
if (preg_match( '/^([0-9]+,){0,4}[0-9]+$/', $string) )
{
echo 'matches',PHP_EOL;
$count = 4;
if (preg_match( '/^([0-9]+,){0,'.$count.'}[0-9]+$/', $string ) )
echo 'matches, too',PHP_EOL;
}
The output was, as I expected:
matches
matches, too
In your case, I'd simply write:
$count = 4;
preg_match('/^(\d+,){,'.preg_quote($count, '/').'}\d+$/', $string);
This is undeniably safer than just calling strval, because you're not accounting for possible special regex chars (+[]{}/\$^?!:<=*. and the like)
Related
I've spent my last 4 hours figuring out how to ... I got to ask for your help now.
I'm trying to extract from a text multiple substring match my starting_words_array and ending_words_array.
$str = "Do you see that ? Indeed, I can see that, as well as this." ;
$starting_words_array = array('do','I');
$ending_words_array = array('?',',');
expected output : array ([0] => 'Do you see that ?' [1] => 'I can see that,')
I manage to write a first function that can find the first substring matching one of both arrays items. But i'm not able to find how to loop it in order to get all the substring matching my requirement.
function SearchString($str, $starting_words_array, $ending_words_array ) {
forEach($starting_words_array as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($ending_words_array as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
Do you guys have any idea about how to achieve such thing ?
I use preg_match for my solution. However, the start and end strings must be escaped with preg_quote. Without that, the solution will be wrong.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr[] = $match[0];
}
}
return $resArr;
}
The result is what the questioner expects.
If the expressions can occur more than once, preg_match_all must also be used. The regex must be modify.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*?".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr = array_merge($resArr,$match[0]);
}
}
return $resArr;
}
The resut for the second variant:
array (
0 => "Do you see that ?",
1 => "Indeed,",
2 => "I can see that,",
)
I would definitely use regex and preg_match_all(). I won't give you a full working code example here but I will outline the necessary steps.
First, build a regex from your start-end-pairs like that:
$parts = array_map(
function($start, $end) {
return $start . '.+' . $end;
},
$starting_words_array,
$ending_words_array
);
$regex = '/' . join('|', $parts) . '/i';
The /i part means case insensitive search. Some characters like the ? have a special purpose in regex, so you need to extend above function in order to escape it properly.
You can test your final regex here
Then use preg_match_all() to extract your substrings:
preg_match_all($regex, $str, $matches); // $matches is passed by reference, no need to declare it first
print_r($matches);
The exact structure of your $matches array will be slightly different from what you asked for but you will be able to extract your desired data from it
Benni answer is best way to go - but let just point out the problem in your code if you want to fix those:
strpos is not case sensitive and find also part of words so you need to changes your $starting_words_array = array('do','I'); to $starting_words_array = array('Do','I ');
When finding a substring you use return which exit the function so you want find any other substring. In order to fix that you can define $res = []; at the beginning of the function and replace return substr($str,$pos,... with $res[] = substr($str,$pos,... and at the end return the $res var.
You can see example in 3v4l - in that example you get the output you wanted
I would like to find part of a string and if true I want to ouput the whole of the string that it finds.
Below is an example:
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
if(strstr($Find, $Towns)){
echo outputWholeString($Find, $Towns); // Result: Eccleston.
}
If anyone can shed some light on how to do this as well, and bare in mind that it will not be static values; the $Towns and $Find variables will be dynamically assigned on my live script.
Use explode() and strpos() as
$Towns = "Eccleston, Aberdeen, Glasgow";
$data=explode(",",$Towns);//
$Find = "Eccle";
foreach ($data as $town)
if (strpos($town, $Find) !== false) {
echo $town;
}
DEMO
You have to use strpos() to search for a string inside another one:
if( strpos($Towns, $Find) === false ) {
echo $Towns;
}
Note that you have to use "===" to know if strpos() returned false or 0.
The solution using preg_match function:
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
preg_match("/\b\w*?$Find\w*?\b/", $Towns, $match);
$result = (!empty($match))? $match[0] : "";
print_r($result); // "Eccleston"
Assuming that you will always have $Towns separated by ", " then you could do something like this
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
$TownsArray = explode(", ", $Towns);
foreach($TownsArray as $Town)
{
if(stristr($Find, $Town))
{
echo $Town; break;
}
}
The above code will output the Town once it finds the needle and exit the foreach loop. You could remove the "break;" to continue letting the script run to see if it finds more results.
Using preg_match(), it is possible to search for Eccle and return the Eccleston word.
I use the Pearl Compatible Regular Expression (PCRE) '#\w*' . $Find . '\w*#' in the code below and the demo code.
The # characters are PCRE delimiters. The pattern searched is inside these delimiters. Some people prefer / as delimiter.
The \w indicates word characters.
The * indicates 0 or more repetions of the previous character.
So, the #\w*Eccle\w*# PCRE searches for an string containing Eccle surrounded by one or more word characters (letters)
<?php
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
if (preg_match('#\w*' . $Find . '\w*#', $Towns, $matches)) {
print_r($matches[0]);
}
?>
Running code: http://sandbox.onlinephpfunctions.com/code/4e4026cbbd93deaf8fef0365a7bc6cf6eacc2014
Note: '#\w*' . $Find . '\w*#' is the same as "#\w*$Find\w*#" (note the surrounding single or double quotes). See this.
You were nearly there...
This is probably what you are looking for:
<?php
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
if(stripos($Towns, $Find)) {
echo $Towns;
}
The output is: Eccleston, Aberdeen, Glasgow which is what I would call "the whole string".
If however you only want to output that partly matched part of "the whole string", then take a look at that example:
<?php
$Towns = "Eccleston, Aberdeen, Glasgow";
$Find = "Eccle";
foreach (explode(',', $Towns) as $Town) {
if(stripos($Town, $Find)) {
echo trim($Town);
}
}
The output of that obviously is: Eccleston...
Two general remarks:
the strpos() / stripos() functions are better suited here, since they return only a position instead of the whole matched string which is enough for the given purpose.
the usage of stripos() instead of strpos() performs a case insensitive search, which probably makes sense for the task...
I want to suppress Searches on a database from users inputting (for example) P*.
http://www.aircrewremembered.com/DeutscheKreuzGoldDatabase/
I can't work out how to add this to the code I already have. I'm guessing using an array in the line $trimmed = str_replace("\"","'",trim($search)); is the answer, replacing the "\"" with the array, but I can't seem to find the correct way of doing this. I can get it to work if I just replace the \ with *, but then I lose the trimming of the "\" character: does this matter?
// Retrieve query variable and pass through regular expression.
// Test for unacceptable characters such as quotes, percent signs, etc.
// Trim out whitespace. If ereg expression not passed, produce warning.
$search = #$_GET['q'];
// check if wrapped in quotes
if ( preg_match( '/^(["\']).*\1$/m', $search ) === 1 ) {
$boolean = FALSE;
}
if ( escape_data($search) ) {
//trim whitespace and additional disallowed characters from the stored variable
$trimmed = str_replace("\"","'",trim($search));
$trimmed = stripslashes(str_ireplace("'","", $trimmed));
$prehighlight = stripslashes($trimmed);
$prehighlight = str_ireplace("\"", "", $prehighlight);
$append = stripslashes(urlencode($trimmed));
} else {
$trimmed = "";
$testquery = FALSE;
}
$display = stripslashes($trimmed);
You already said it yourself, just use arrays as parameters for str_repace:
http://php.net/manual/en/function.str-replace.php
$trimmed = str_replace( array("\"", "*"), array("'", ""), trim($search) );
Every element in the first array will be replaced with the cioresponding element from the second array.
For future validation and sanitation, you might want to read about this function too:
http://php.net/manual/en/function.filter-var.php
use $search=mysql_real_escape_string($search); it will remove all characters from $search which can affect your query.
So I decided to have a stab at making a text highlighting system. At the moment, I'm just using str_replace to replace a word (e.g. $rstr = str_replace("Console", "<c>Console</c>", $str where $str is the input string.
Something that stumped me was how to replace content inside of speech marks (") and quotes ('). For example, if the string "Console" turned into Console.WriteLine("Words");, how would I replace "Words" with <sr>"Words"</sr> (<sr> is defined in an external stylesheet)?
I had a though that I could use regex, but 1. I don't know how to write regex, and 2. I don't know how to use regex with str_replace.
My workaround solution:
function hlStr($original)
{
$rstr = explode('"', $original);
return $rstr[0].'<sr>"'.$rstr[1].'"</sr>'.$rstr[2];
}
In light of comments below, I think this will be a better resource for you: http://www.regular-expressions.info/
In order to find "anything can go here" you should use regular expressions. This is what they were made for. A regular expression for that might look something like the answers in this question:
How can I match a quote-delimited string with a regex?
then you would use the function preg_replace() like this:
$return_value = preg_replace('/"[^"]+"/', 'replacement text', $str)
leaving this here anyway:
just escape the content with a backslash:
$rstr = str_replace("Console", "Console.WriteLine(\"$variable\");", $str)
this is mostly useful if you are using variables inside your strings. If it is just a straight text replacement, use single quotes:
$rstr = str_replace("Console", 'Console.WriteLine("Words");', $str)
the single quotes count everything but single quotes as just a character.
This is my solution. Explode the whole string by ( " ) symbols, and then run a specific code to each second of them. This code does automatic do it to every second value after " item, which means, if you does : hej " lol ; it would change to : hi <sr>" lol "</sr> ; or if you do : hi " with " you ; it would change to : hi <sr>" with "</sr> you ; etc.
function wrapInside($text,$symbol)
{
$string = explode($symbol, $text);
$i = 1;
$QS = '';
foreach( $queryString as $V )
{
( $i == 1 ) ? ( $QS .= $V ) : ( $QS .= '<sr>"'.trim($V).'"</sr>' );
( $i == 1 ) ? ( $i = 0 ) : ( $i = 1 );
}
$queryString = trim($QS);
return $queryString;
}
This question already has answers here:
Remove nested quotes
(3 answers)
Closed 2 years ago.
I'm trying to remove nested quoting from my bulletin board, but I'm having some issues.
Example input:
[quote author=personX link=topic=12.msg1910#msg1910 date=1282745641]
[quote author=PersonY link=topic=12.msg1795#msg1795 date=1282727068]
The message in the original quote
[/quote]
A second message quoting the first one
[/quote]
[quote author=PersonZ link=topic=1.msg1#msg1 date=1282533805]
A random third quote
[/quote]
Example output
[quote author=personX link=topic=12.msg1910#msg1910 date=1282745641]
Message in the second quote
[/quote]
[quote author=PersonZ link=topic=1.msg1#msg1 date=1282533805]
A random third quote
[/quote]
As you can see the nested quote (The original message) is removed, along with the quote tags.
I can't seem to figure it out.
When i try
$toRemove = '(\\[)(quote)(.*?)(\\])';
$string = $txt;
$found = 0; echo preg_replace("/($toRemove)/e", '$found++ ? \'\' : \'$1\'', $string);
It removes every occurrence of of the quote tag except the first one,
But when i expand the code to:
$toRemove = '(\\[)(quote)(.*?)(\\])(.*?)(\\[\\/quote\\])';
$string = $txt;
$found = 0; echo preg_replace("/($toRemove)/e", '$found++ ? \'\' : \'$1\'', $string);
It stops doing anything at all.
Any ideas on this ?
Edit:
Thanks for your help, Haggi.
Ik keep running in to trouble though.
The while loop around
while ( $input = preg_replace_callback( '~\[quoute.*?\[/quote\]~i', 'replace_callback', $input ) ) {
// replace every occurence
}
causes the page to loop indefinitely, when removed (along with the extra u in quoute), the page doesn't do anything.
I've determined that the cause is the matching
when changed to
$input = preg_replace_callback( '/\[quote(.*?)/i', 'replace_callback', $input );
the code does start working, but when changed to
$input = preg_replace_callback( '/\[quote(.*?)\[\/quote\]/i', 'replace_callback', $input );
It stopts doing anything again.
Also, there is an issue with the undo_replace function as it never finds the stored hash, it only gives warnings about unfound indexes. The regex matching the sha1 isn't working correctly i guess.
The complete code as I have it now:
$cache = array();
$input = $txt;
function replace_callback( $matches ) {
global $cache;
$hash = sha1( $matches[0] );
$cache["hash"] = $matches[0];
return "REPLACE:$hash";
}
// replace all quotes with placeholders
$input = preg_replace_callback( '/\[quote(.*?)\[quote\]/i', 'replace_callback', $input );
function undo_replace( $matches ) {
global $cache;
return $cache[$matches[1]];
}
// restore the outer most quotes
$input = preg_replace_callback( '~REPLACE:[a-f0-9]{40}~i', 'undo_replace', $input );
// remove the references to the inner quotes
$input = preg_replace( '~REPLACE:[a-f0-9]{40}~i', '', $input );
echo $input;
Thanks again for any ideas guys :)
that the first one is the only one that stays is quite easily found out:
'$found++ ? \'\' : \'$1\''
When starting $found is undefined and evaluates to false so the $1 is returned. Then $found gets incremented to 1 ( undefined + 1 = 1 ) so it is greater that zero and every time it gets called it's further incremented. As everything that is different from zero is evaluated as true after that you always get the '' back.
What you want to do is something like this
$cache = array();
function replace_callback( $matches ) {
global $cache;
$hash = sha1sum( $matches[0] );
$cache[$hash] = $matches[0];
return "REPLACE:$hash";
}
// replace all quotes with placeholders
$count = 0;
do {
$input = preg_replace_callback( '~\[quoute.*?\[/quote\]~i', 'replace_callback', $input, -1, $count );
// replace every occurence
} while ($count > 0);
function undo_replace( $matches ) {
global $cache;
return $cache[$matches[1]];
}
// restore the outer most quotes
$input = preg_replace_callback( '~REPLACE:[a-f0-9]{40}~i', 'undo_replace', $input );
// remove the references to the inner quotes
$input = preg_replace( '~REPLACE:[a-f0-9]{40}~i', '', $input );
This code is untested as I don't habe PHP at hand to test it. If there are any errors you cannot fix, please just post them here and I will fix them.
Cheers,haggi
I've searched for couple of solutions with preg_replace for nested quotes but no one worked. So i tried my littel version according to my requirement.
$position = strrpos($string, '[/quote:'); // this will get the position of last quote
$text = substr(strip_tags($string),$position+17); // this will get the data after the last quote used.
Hope this will help someone.