Remove first instance of a term in string - case insensitive - php

I have:
$string = 'Hello x World hello';
And I want to remove the first instance of a term that is case insensitive.
For example, I have:
$term = 'hello';
And I want to match it with $string, so we end up with:
$string = ' x World hello';
What I've done so far
I am nearly there! I can replace the first instance of a term with:
function str_replace_once($str_pattern, $str_replacement, $string){
if (strpos($string, $str_pattern) !== false){
$occurrence = strpos($string, $str_pattern);
return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern));
}
return $string;
}
But it is not case insensitive, see ideone. How can I make it case insensitive?

In your example code, just replace strpos with stripos... (with a few minor tweaks)...
function str_replace_once($str_pattern, $str_replacement, $string){
$pos = stripos($string, $str_pattern);
if ($pos !== false){
return substr_replace($string, $str_replacement, $pos, strlen($str_pattern));
}
return $string;
}

I wish str_ireplace had a limit, it would be better. But preg_replace has a limit. Use the i modifier for case-insensitive:
$string = preg_replace("/$term/i", "", $string, 1);
Also note that there is a stripos which is case-insensitive strpos which you can use in your existing code.

Use stripos(case-insensitive) and substr
function str_replace_first($str, $search, $replace)
{
$index = stripos($str, $search);
return $index === false ? $str : substr($str, 0, $index) . $replace . substr($str, $index + strlen($search));
}
Usage:
$string = 'Hello x World hello';
echo str_replace_first($string,'Hello', '');

Related

Processing text in PHP finding a matching character

How can I process text with some codes.
So suppose I have text as below
Hello {::first_name::} {::last_name::},
How are you?
Your organisation is {::organisation::}
For any text between {:: and ::} should be evaluated to get its value.
I tried exploding text to array using space as delimiter and then parsing array items to look for "{::" and if found get string between "{::" and "::}" and calling database to get this field value.
So basically these will be db fields.
Below is the code I have tried
$msg = "Hello {::first_name::} {::last_name::},
How are you?
Your organisation is {::organisation::}";
$msg_array = explode(" ", $msg);
foreach ($msg_array as $str) {
if (strpos($str, "{::") !== false) {
$field_str = get_string_between($str, "{::", "::}");
$field_value = $bean->$field_str; //Logic that gets the value of the field
$msgStr .= $field_value . " ";
} else {
$msgStr .= $str . " ";
}
}
function get_string_between($string, $start, $end)
{
$string = ' ' . $string;
$ini = strpos($string, $start);
if ($ini == 0) return '';
$ini += strlen($start);
$len = strpos($string, $end, $ini) - $ini;
return substr($string, $ini, $len);
}
Your script seems fine. Your script in fiddle
If you are looking for alternative way, you can try using preg_match_all() with str_replace(array, array, source)
<?php
$bean = new stdClass();
$bean->first_name = 'John';
$bean->last_name = 'Doe';
$bean->organisation = 'PHP Company';
$string = "Hello {::first_name::} {::last_name::}, How are you? Your organisation is {::organisation::}";
// find all placeholders
preg_match_all('/{::(.+?)::}/i', $string, $matches);
$placeholders = $matches[0];
//strings inside placeholders
$parts = $matches[1];
// return values from $bean by matching object property with strings inside placeholders
$replacements = array_map(function($value) use ($bean) {
// use trim() to remove unexpected space
return $bean->{trim($value)};
}, $parts);
echo $newstring = str_replace($placeholders, $replacements, $string);
Short format:
$string = "Hello {::first_name::} {::last_name::}, How are you? Your organisation is {::organisation::}";
preg_match_all('/{::(.+?)::}/i', $string, $matches);
$replacements = array_map(function($value) use ($bean) {
return $bean->{trim($value)};
}, $matches[1]);
echo str_replace($matches[0], $replacements, $string);
And if you prefer to use a function:
function holder_replace($string, $source = null) {
if (is_object($source)) {
preg_match_all('/{::(.+?)::}/i', $string, $matches);
$replacements = array_map(function($value) use ($source) {
return (property_exists(trim($value), 'source')) ? $source->{trim($value)} : $value;
}, $matches[1]);
return str_replace($matches[0], $replacements, $string);
}
return $string;
};
echo holder_replace($string, $bean);
OUTPUT:
Hello John Doe, How are you? Your organisation is PHP Company
fiddle
Or you can simply use str_replace function:
$data = "{:: string ::}";
echo str_replace("::}", "",str_replace("{::", "", $data));

preg_match_all spaces with fullstops regex

I am writing some unit tests for some methods I am using, and have found a weird bug and would like some Regex advice.
when doing:-
$needle = ' ';
$haystack = 'hello world. this is a unit test.';
$pattern = '/\b' . $needle . '\b/';
preg_match_all($pattern, $haystack, $matches, PREG_OFFSET_CAPTURE, $offset)
I'm expecting the positions to positions found to be
[5, 12, 17, 20, 22, 27]
The same as if I did this, to get none exact whole word matches
while (($pos = strpos($haystack, $needle, $offset)) !== false) {
$offset = $pos + 1;
$positions[] = $pos;
}
However the preg_match_all does not find the 2nd occurrence (12) the space between
. this
Is this to do with the \b boundary flag? How can I resolve this to make sure it picks up other this?
Thanks
You have to change your $pattern in preg_match_all() like below:-
<?php
$haystack = 'hello world. this is a unit test.';
while (($pos = strpos($haystack, ' ', $offset)) !== false) {
$offset = $pos + 1;
$positions[] = $pos;
}
echo "<pre/>";print_r($positions);
preg_match_all('/\s/', $haystack, $matches,PREG_OFFSET_CAPTURE);
echo "<pre/>";print_r($matches);
Output:- https://eval.in/725574
Note:- you need to use \s for checking white-spaces
You can apply an if-else to change $pattern based on $needle:-
if($needle == ''){
$pattern = '/\s/';
}else{
$pattern = '/\b' . $needle . '\b/';
}

Replace name element using regex

I am trying to replace this "iwdnowfreedom[body_style][var]" with this "iwdnowfreedom_body_style_var" in the name attributes of a variable. There could be several array keys but for my situation stripping them out shouldn't result in any issues.
Here is the code I have so far:
$pattern = '/name\\s*=\\s*["\'](.*?)["\']/i';
$replacement = 'name="$2"';
$fixedOutput = preg_replace($pattern, $replacement, $input);
return $fixedOutput;
How can I fix this to work properly?
You could try using the build in str_replace function to achieve what you are looking for (assuming there are no nested bracked like "test[test[key]]"):
$str = "iwdnowfreedom[body_style][var]";
echo trim( str_replace(array("][", "[", "]"), "_", $str), "_" );
or if you prefer regex (nested brackets work fine with this method):
$input = "iwdnowfreedom[body_style][var]";
$pattern = '/(\[+\]+|\]+\[+|\[+|\]+)/i';
$replacement = '_';
$fixedOutput = trim( preg_replace($pattern, $replacement, $input), "_" );
echo $fixedOutput;
I think you also meant that you might have a string such as
<input id="blah" name="test[hello]" />
and to parse the name attribute you could just do:
function parseNameAttribute($str)
{
$pos = strpos($str, 'name="');
if ($pos !== false)
{
$pos += 6; // move 6 characters forward to remove the 'name="' part
$endPos = strpos($str, '"', $pos); // find the next quote after the name="
if ($endPos !== false)
{
$name = substr($str, $pos, $endPos - $pos); // cut between name=" and the following "
return trim(preg_replace('/(\[+\]+|\]+\[+|\[+|\]+)/i', '_', $name), '_');
}
}
return "";
}
OR
function parseNameAttribute($str)
{
if (preg_match('/name="(.+?)"/', $str, $matches))
{
return trim(preg_replace('/(\[+\]+|\]+\[+|\[+|\]+)/i', '_', $matches[1]), '_');
}
return "";
}

PHP + Modify string

I have got a string and would like to remove everything after a certain "dot"+word combination. For instance:
This.Is.A.Test
=> would become
This.Is.A
Were you looking to remove everything after a specific dot+word, or just remove the last dot+word? If you're looking for a specific word, try this:
$str = "This.Is.A.Test";
$find = ".A";
$index = strpos($str, $find);
if ($index !== false)
$str = substr($str, 0, $index + strlen($find));
echo $str; // "This.Is.A"
In response to #SuperSkunk:
If you wanted to match the whole word, you could do this:
$find = ".A.";
$str = "This.Is.A.Test";
$index = strpos($str, $find);
if ($index !== false)
$str = substr($str, 0, $index + strlen($find) - 1);
echo $str; // "This.Is.A"
$str = "This.Is.AB.Test";
$index = strpos($str, $find);
if ($index !== false)
$str = substr($str, 0, $index + strlen($find) - 1);
echo $str; // "This.Is.AB.Test" (did not match)
$str = "This.Is.A.Test"; $str = substr($str, 0, strrpos($str, "."));
$result = explode('.', $str, 4);
array_pop($result);
implode('.', $result);
I'll do something very simple like :
<?php
$string = 'This.Is.A.Test';
$parts = explode('.', $string);
array_pop($parts); // remove last part
$string = implode('.', $parts);
echo $string;
?>
$pos = strpos($haystack, ".A" );
$result = substr($haystack,0,$pos);
...something like this.

Simple: How to replace "all between" with php? [duplicate]

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).

Categories