I have the following string:
$str = "A string".
When I use:
preg_match("/A string/", $str)
I get the match everything works perfectly fine, but I want to use the same regular expression for another string:
$str2 = "A test string".
For this case I can use:
"/A (test )?string/"
But I want it to be more complex, it should also be able to match strings like this, for example:
A sttest ring
test A string
I mean that the substring "test " can appear anywhere in the subject.
Is it even possible to find a regular expression for this?
You could try something like this
$str = "My test String";
if (strpos($str, 'test') !== false) {
echo 'true';
}
Try this:
$str = "A sttest ring";
$newstr = preg_replace("/\s*test\s*/", "", $str);
preg_match("/A string/", $newstr, $matches);
echo $matches ? 'true' : 'false';
Online Demo
I would create a function for that:
function containsLetters($testString, $lettersString, $caseSensitive = false, $whiteSpaces = false){
if(!$caseSensitive){
$testString = strtolower($testString); $lettersString = strtolower($lettersString);
}
if($whiteSpaces){
$tw = $testString; $lw = $lettersString;
}
else{
$tw = preg_replace('/\s/', '', $testString); $lw = preg_replace('/\s/', '', $lettersString);
}
$tst = str_split($tw); $ltr = str_split($lw); $c = count($ltr); $r = array();
foreach($ltr as $l){
foreach($tst as $i => $t){
if($l === $t){
$a = array_splice($tst, $i, 1); $r[] = $a[0];
}
}
}
if(count($r) >= $c){
return true;
}
return false;
}
$test = containsLetters('A sttest ring', 'a test string');
Just pass true to the 3rd argument to make it case sensitive. Also, pass true to the 4th argument to compare white spaces.
Related
I am trying to replace every question mark "?" in a string with a values in an array.
I need to go through a string, and replace the first occurrence of '?' in the string with a value. I would need to do that for every occurrence
Here is what I tried
function sprintf2($str='', array $values = array(), $char = '?')
{
if (!$str){
return '';
}
if (count($values) > 0)
{
foreach ($values as $value)
{
$str = preg_replace('/'. $char . '/', $value, $str, 1);
}
}
echo $str;
}
But I am getting the following exception
preg_replace(): Compilation failed: nothing to repeat at offset 0
The following shows how I am calling the function
$bindings = array(10, 500);
$str = "select * from `survey_interviews` where `survey_id` = ? and `call_id` = ? limit 1";
sprintf2($str, $bindings);
What am I doing wrong here? why do I get this exception?
Use str_replace instead of preg_replace, since you're replacing a literal string, not a regular expression pattern.
However, str_replace always replaces all matches, there's no way to limit it to just the first match (preg_replace is similar). The 4th argument is not a limit, it's a variable that gets set to the number of matches that were found and replaced. To replace just one match, you can combine strpos and substr_replace:
function sprintf2($str='', array $values = array(), $char = '?')
{
if (!$str){
return '';
}
if (count($values) > 0)
{
$len = strlen($char);
foreach ($values as $value)
{
$pos = strpos($str, $char);
if ($pos !== false) {
$str = substr_replace($str, $value, $pos, strlen($char));
}
}
}
echo $str;
}
DEMO
You need to escape the '?' sign in your regexp using a backslash ( '\?' instead of '?').
But your code can be easily refactored to use preg_replace_callback instead:
$params = array(1, 3);
$str = '? bla ?';
echo preg_replace_callback('#\?#', function() use (&$params) {
return array_pop($params);
}, $str);
Hope this code helps you.
function sprintf2($string = '', array $values = array(), $char = '?')
{
if (!$string){
return '';
}
if (count($values) > 0)
{
$exploded = explode($char, $string);
$i = 0;
$string = '';
foreach ($exploded as $segment) {
if( $i < count($values)){
$string .= ($segment . $values[$i]);
++$i;
}
}
}
echo $string;
}
$bindings = array(10, 500);
$str = "select * from `survey_interviews` where `survey_id` = ? and `call_id`= ? limit 1";
echo sprintf2($str, $bindings);
Explanation:
In your code, you're using the preg_match and the first parameter in the preg_match method is a regex pattern. what you're trying to replace is ? has a valid meaning for 0 or 1 CHARACTER. So, you've to escape that by doing \?. Though all the characters are not needed to be escaped, so, for making your method work, you've to check the character that are valid for any regex.
In my code, I've split the string for the character you want. then appending the values at the end of the part what we get from the array. and this should be done till the values length of the value array, otherwise the offset error will occur.
i want : He had XXX to have had it. Or : He had had to have XXX it.
$string = "He had had to have had it.";
echo preg_replace('/had/', 'XXX', $string, 1);
output :
He XXX had to have had it.
in the case of, 'had' is replaced is the first.
I want to use the second and third. not reading from the right or left, what "preg_replace" can do it ?
$string = "He had had to have had it.";
$replace = 'XXX';
$counter = 0; // Initialise counter
$entry = 2; // The "found" occurrence to replace (starting from 1)
echo preg_replace_callback(
'/had/',
function ($matches) use ($replace, &$counter, $entry) {
return (++$counter == $entry) ? $replace : $matches[0];
},
$string
);
Try this:
<?php
function my_replace($srch, $replace, $subject, $skip=1){
$subject = explode($srch, $subject.' ', $skip+1);
$subject[$skip] = str_replace($srch, $replace, $subject[$skip]);
while (($tmp = array_pop($subject)) == '');
$subject[]=$tmp;
return implode($srch, $subject);
}
$test ="He had had to have had it.";;
echo my_replace('had', 'xxx', $test);
echo "<br />\n";
echo my_replace('had', 'xxx', $test, 2);
?>
Look at CodeFiddle
Probably not going to win any concours d'elegance with this, but very short:
$string = "He had had to have had it.";
echo strrev(preg_replace('/dah/', 'XXX', strrev($string), 1));
Try this
Solution
function generate_patterns($string, $find, $replace) {
// Make single statement
// Replace whitespace characters with a single space
$string = preg_replace('/\s+/', ' ', $string);
// Count no of patterns
$count = substr_count($string, $find);
// Array of result patterns
$solutionArray = array();
// Require for substr_replace
$findLength = strlen($find);
// Hold index for next replacement
$lastIndex = -1;
// Generate all patterns
for ( $i = 0; $i < $count ; $i++ ) {
// Find next word index
$lastIndex = strpos($string, $find, $lastIndex+1);
array_push( $solutionArray , substr_replace($string, $replace, $lastIndex, $findLength));
}
return $solutionArray;
}
$string = "He had had to have had it.";
$find = "had";
$replace = "yz";
$solutionArray = generate_patterns($string, $find, $replace);
print_r ($solutionArray);
Output :
Array
(
[0] => He yz had to have had it.
[1] => He had yz to have had it.
[2] => He had had to have yz it.
)
I manage this code try to optimize it.
I use php preg_match to match the first & last word in a variable with a given first & last specific words,
example:
$first_word = 't'; // I want to force 'this'
$last_word = 'ne'; // I want to force 'done'
$str = 'this function can be done';
if(preg_match('/^' . $first_word . '(.*)' . $last_word .'$/' , $str))
{
echo 'true';
}
But the problem is i want to force match the whole word at (starting & ending) not the first or last characters.
Using \b as boudary word limit in search:
$first_word = 't'; // I want to force 'this'
$last_word = 'ne'; // I want to force 'done'
$str = 'this function can be done';
if(preg_match('/^' . $first_word . '\b(.*)\b' . $last_word .'$/' , $str))
{
echo 'true';
}
I would go about this in a slightly different way:
$firstword = 't';
$lastword = 'ne';
$string = 'this function can be done';
$words = explode(' ', $string);
if (preg_match("/^{$firstword}/i", reset($words)) && preg_match("/{$lastword}$/i", end($words)))
{
echo 'true';
}
==========================================
Here's another way to achieve the same thing
$firstword = 'this';
$lastword = 'done';
$string = 'this can be done';
$words = explode(' ', $string);
if (reset($words) === $firstword && end($words) === $lastword)
{
echo 'true';
}
This is always going to echo true, because we know the firstword and lastword are correct, try changing them to something else and it will not echo true.
I wrote a function to get Start of sentence but it is not any regex in it.
You can write for end like this. I don't add function for the end because of its long...
<?php
function StartSearch($start, $sentence)
{
$data = explode(" ", $sentence);
$flag = false;
$ret = array();
foreach ($data as $val)
{
for($i = 0, $j = 0;$i < strlen($val), $j < strlen($start);$i++)
{
if ($i == 0 && $val{$i} != $start{$j})
break;
if ($flag && $val{$i} != $start{$j})
break;
if ($val{$i} == $start{$j})
{
$flag = true;
$j++;
}
}
if ($j == strlen($start))
{
$ret[] = $val;
}
}
return $ret;
}
print_r(StartSearch("th", $str));
?>
I have got a function from Google to clean my paragraph in sentence case.
I want to modify this function such that it converts more than 2 new line character to newline. Else it converts all new line characters in space. So I would have it in paragraph format. Here it's converting all new line character to space.
It's converting in proper sentence case. But, In case If I found single word having first word as capital then I need function to ignore that. As Sometimes, if there would be any noun It needs to be capital. We can't change it small case. Else if noun and it is having more than 2 capital characters other than first character than convert it to lower case.
Like -> Noun => Noun but NoUn => noun. Means I want if other than first character is capital than it convert it two lower case Else it keep it in same format.
function sentence_case($string) {
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
//$new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
$new_string = clean_spaces($new_string);
$new_string = m_r_e_s($new_string);
return trim($new_string);
}
function sentence_case($str) {
$cap = true;
$ret='';
for($x = 0; $x < strlen($str); $x++){
$letter = substr($str, $x, 1);
if($letter == "." || $letter == "!" || $letter == "?"){
$cap = true;
}elseif($letter != " " && $cap == true){
$letter = strtoupper($letter);
$cap = false;
}
$ret .= $letter;
}
return $ret;
}
This will preserve existing proper noun capitals, acronyms and abbreviations.
This should do it:
function sentence_case($string) {
// Protect the paragraphs and the caps
$parDelim = "/(\n+\r?)/";
$string = preg_replace($parDelim, "#PAR#", $string);
$string = preg_replace("/\b([A-Z])/", "#$1#", $string);
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
//$new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
$new_string = clean_spaces($new_string);
$new_string = m_r_e_s($new_string);
// Restore the paragraphs and the caps
$new_string = preg_replace("#PAR#", PHP_EOL, $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
return trim($new_string);
}
It works by identifying the items you want to protect (paragraph & first cap) and marking it with a string that you can then replace back when you are done. The assumption is that you don't already have #PAR# and #A-Z# in the string. You can use whatever you want to use for the paragraph delimiter afterwards if you want to force a certain type of line ending or several lines in between.
Slightly modifying Sylverdrag's function, I got something that is working well for me. This version works for every messed-up sentence I've thrown at it so far :)
function sentence_case($string) {
$string = strtolower($string); // ADDED THIS LINE
// Protect the paragraphs and the caps
$parDelim = "/(\n+\r?)/";
$string = preg_replace($parDelim, "#PAR#", $string);
$string = preg_replace("/\b([A-Z])/", "#$1#", $string);
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
// GOT RID OF THESE LINES
// $new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
// $new_string = clean_spaces($new_string);
// $new_string = m_r_e_s($new_string);
// Restore the paragraphs and the caps
$new_string = preg_replace("#PAR#", PHP_EOL, $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
preg_match('/#(.*?)#/', $new_string, $match); // MODIFIED THIS LINE TO USE (.*?)
return trim($new_string);
}
$string = "that IS it!! YOU and i are Totally DONE hanging out toGether... like FOREveR DUDE! i AM serious. a good FRIEND would NOT treAT me LIKE you dO. it Seems, howEVER, THAT you ARE not ONE of tHe GOOD ONEs.";
echo "<b>String 1:</b> " . $string . "<br><b>String 2:</b> " . sentence_case($string);
PHP Sandbox
:) :)
This question already has answers here:
How to remove text between tags in php?
(6 answers)
Closed 3 years ago.
$string = "<tag>i dont know what is here</tag>"
$string = str_replace("???", "<tag></tag>", $string);
echo $string; // <tag></tag>
So what code am i looking for?
A generic function:
function replace_between($str, $needle_start, $needle_end, $replacement) {
$pos = strpos($str, $needle_start);
$start = $pos === false ? 0 : $pos + strlen($needle_start);
$pos = strpos($str, $needle_end, $start);
$end = $pos === false ? strlen($str) : $pos;
return substr_replace($str, $replacement, $start, $end - $start);
}
DEMO
$search = "/[^<tag>](.*)[^<\/tag>]/";
$replace = "your new inner text";
$string = "<tag>i dont know what is here</tag>";
echo preg_replace($search,$replace,$string);
outputs:
<tag>your new inner text</tag>
$string = "<tag>I do not know what is here</tag>";
$new_text = 'I know now';
echo preg_replace('#(<tag.*?>).*?(</tag>)#', '$1'.$new_text.'$2' , $string); //<tag>I know now</tag>
A generic and non-regex solution:
I've modified #felix-kling's answer. Now it only replaces text if it finds the needles.
Also, I've added parameters for replacing the needles, starting position and replacing all the matches.
I've used the mb_ functions for making the function multi-byte safe.
If you need a case insensitive solution then replace mb_strpos calls with mb_stripos.
function replaceBetween($string, $needleStart, $needleEnd, $replacement,
$replaceNeedles = false, $startPos = 0, $replaceAll = false) {
$posStart = mb_strpos($string, $needleStart, $startPos);
if ($posStart === false) {
return $string;
}
$start = $posStart + ($replaceNeedles ? 0 : mb_strlen($needleStart));
$posEnd = mb_strpos($string, $needleEnd, $start);
if ($posEnd === false) {
return $string;
}
$length = $posEnd - $start + ($replaceNeedles ? mb_strlen($needleEnd) : 0);
$result = substr_replace($string, $replacement, $start, $length);
if ($replaceAll) {
$nextStartPos = $start + mb_strlen($replacement) + mb_strlen($needleEnd);
if ($nextStartPos >= mb_strlen($string)) {
return $result;
}
return replaceBetween($result, $needleStart, $needleEnd, $replacement, $replaceNeedles, $nextStartPos, true);
}
return $result;
}
$string = "{ Some} how it {is} here{";
echo replaceBetween($string, '{', '}', '(hey)', true, 0, true); // (hey) how it (hey) here{
If "tag" changes:
$string = "<tag>i dont know what is here</tag>";
$string = preg_replace('|^<([a-z]*).*|', '<$1></$1>', $string)
echo $string; // <tag></tag>
If you don't know what's inside the <tag> tag, it's possible there is another <tag> tag in there e.g.
<tag>something<tag>something else</tag></tag>
And so a generic string replace function won't do the job.
A more robust solution is to treat the string as XML and manipulate it with DOMDocument. Admittedly this only works if the string is valid as XML, but I still think it's a better solution than a string replace.
$string = "<tag>i don't know what is here</tag>";
$replacement = "replacement";
$doc = new DOMDocument();
$doc->loadXML($str1);
$node = $doc->getElementsByTagName('tag')->item(0);
$newNode = $doc->createElement("tag", $replacement);
$node->parentNode->replaceChild($newNode, $node);
echo $str1 = $doc->saveHTML($node); //output: <tag>replacement</tag>
$string = "<tag>i dont know what is here</tag>"
$string = "<tag></tag>";
echo $string; // <tag></tag>
or just?
$string = str_replace($string, "<tag></tag>", $string);
Sorry, could not resist. Maybe you update your question with a few more details. ;)
If you need to replace the portion too then this function is helpful:
$var = "Nate";
$body = "Hey there {firstName} have you already completed your purchase?";
$newBody = replaceVariable($body,"{","}",$var);
echo $newBody;
function replaceVariable($body,$needleStart,$needleEnd,$replacement){
while(strpos($body,$needleStart){
$start = strpos($body,$needleStart);
$end = strpos($body,$needleEnd);
$body = substr_replace($body,$replacement,$start,$end-$start+1);
}
return $body;
}
I had to replace a variable put into a textarea that was submitted. So I replaced firstName with Nate (including the curly braces).