Search and replace chars in a substring [closed] - php

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Example:
"Hello iam a [start] string and iam very happy with [end] beeing a string...";
Now lets say i only want to change something in the substring between [start] and [end]. I know how to find out the str_pos and the lenght to the end but how can i search and replace something that only affects this substring?
What i want to do is: (for example)
Replace 'x' with 'y' within str positon 5 and 50
I know that there is substr_replace but thats not exactly what iam looking for.
Any ideas would be great, thanks a lot!

If I understand correctly you want to replace something within a substring while knowing it's position within it's parent string. Using substr() and preg_replace can easily do this:
Code:
$str = 'Hello iam a [start] string and iam very happy with [end] beeing a string...';
$begpos = 12; // begin position of [start]
$endpos = 56; // end position of [end]
$substr = substr($str, $begpos, $endpos-$begpos);
$subtit = preg_replace('/\iam/','I AM', $substr);
$newstr = substr_replace($str,$subtit,$begpos,$endpos-$begpos);
echo $newstr;
Result:
Hello iam a [start] string and I AM very happy with [end] beeing a string...

How about something like...
<?php
$string = 'my first word was first then it was the second word';
echo "$string\n";
echo str_pos_replace($string, 'word', 'second', 'first', 'second') . "\n";
function str_pos_replace($string, $start, $end, $find, $replace)
{
$pos1=strpos($string, $start);
$pos2=strpos($string, $end);
$subject=substr($string, $pos1, ($pos2-$pos1));
$replaced=str_replace($find, $replace, $subject);
return str_replace($subject, $replaced, $string);
}
Will print out something like:
my first word was first then it was the second word
my first word was second then it was the second word

here is an example pattern to find the letter 'a' between [start] and [end]
(.*\[start\]|\[end\].*)(*SKIP)(*F)|a
Demo

if is string
str_repalce(needle, replace, haystack)
if array
json_encode haystack
str_replace needle, replace, haystack)
json_decode haystack
Knowing the str position is noit realy of value to you when if you know what you are looking for you can just replace it with some thing else just remember the rule double quotes to use php vars "$haystack" and single quotes will render exactly as you type '$haystack'
this is by far the easyest way and best way to replace text or values in a string or in a array but please read the documentation of the functions before use so you understand how they work. Json_encode / Decode can be a tricky thing to master but once you understand it you can use it to trasform your arrays to strings and back again reall easy.

You could do it with a callback.
Regex:
"/(?xs)^( . {" . $start_pos . "} ) ( . {" . $end_pos . "} )/"
Inside the callback, run a new regex replacement on group 2 for xyz.
Return Catted original group 1 and and the replaced group 2.
Untested code:
$start_pos = 5;
$end_pos = 50;
$str = preg_replace_callback
(
"/(?xs)^( . {" . $start_pos . "} ) ( . {" . $end_pos . "} )/",
function( $matches )
{
$orig_grp1 = $matches[1];
$substr_replaced = preg_replace( '/xyz/', 'XYZ', $matches[2] );
return $orig_grp1 . $substr_replaced;
},
$str
);

So yeah, I was a bit bored, and this might be an overkill, but it does what you ask:
function replaceBetweenTags($needle, $replacement, $haystack, $keepTags = false, $startTag = "[start]", $endTag = "[end]") {
$startPattern = preg_quote($startTag);
$endPattern = preg_quote($endTag);
$pattern = '/'.$startPattern.'(.+)'.$endPattern.'/m';
if (!preg_match($pattern, $haystack)) return $haystack;
return preg_replace_callback($pattern, function($match) use ($startTag, $endTag, $keepTags, $needle, $replacement) {
$match = str_replace($needle, $replacement, $match[0]);
if ($keepTags) return $match;
return str_replace($startTag, "", str_replace($endTag, "", $match));
}, $haystack);
}
Usage is simple:
echo replaceBetweenTags("happy", "sad", "Hello iam a [start] string and iam very happy with [end] beeing a string..."
// Output: Hello iam a string and iam very sad with beeing a string...
// Unless you set $keepTags = true, in which case it'll preserve the tags.
It handles multiple tag pairs too. Things to note:
it's case sensitive
$keepTags = false might leave double spaces. You might want to str_replace those
Hope it helps.

Related

How to find ALL substrings in string using starting and ending words arrays PHP

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

PHP Regex for a specific numeric value inside a comma-delimited integer number string

I am trying to get the integer on the left and right for an input from the $str variable using REGEX. But I keep getting the commas back along with the integer. I only want integers not the commas. I have also tried replacing the wildcard . with \d but still no resolution.
$str = "1,2,3,4,5,6";
function pagination()
{
global $str;
// Using number 4 as an input from the string
preg_match('/(.{2})(4)(.{2})/', $str, $matches);
echo $matches[0]."\n".$matches[1]."\n".$matches[1]."\n".$matches[1]."\n";
}
pagination();
How about using a CSV parser?
$str = "1,2,3,4,5,6";
$line = str_getcsv($str);
$target = 4;
foreach($line as $key => $value) {
if($value == $target) {
echo $line[($key-1)] . '<--low high-->' . $line[($key+1)];
}
}
Output:
3<--low high-->5
or a regex could be
$str = "1,2,3,4,5,6";
preg_match('/(\d+),4,(\d+)/', $str, $matches);
echo $matches[1]."<--low high->".$matches[2];
Output:
3<--low high->5
The only flaw with these approaches is if the number is the start or end of range. Would that ever be the case?
I believe you're looking for Regex Non Capture Group
Here's what I did:
$regStr = "1,2,3,4,5,6";
$regex = "/(\d)(?:,)(4)(?:,)(\d)/";
preg_match($regex, $regStr, $results);
print_r($results);
Gives me the results:
Array ( [0] => 3,4,5 [1] => 3 [2] => 4 [3] => 5 )
Hope this helps!
Given your function name I am going to assume you need this for pagination.
The following solution might be easier:
$str = "1,2,3,4,5,6,7,8,9,10";
$str_parts = explode(',', $str);
// reset and end return the first and last element of an array respectively
$start = reset($str_parts);
$end = end($str_parts);
This prevents your regex from having to deal with your numbers getting into the double digits.

Make bold specific part of string

I have an array like
$array[]="This is a test";
$array[]="This is a TEST";
$array[]="TeSt this";
I need to make the string 'test' as bold like
$array[]="This is a <b>test</b>";
$array[]="This is a <b>TEST</b>";
$array[]="<b>TeSt</b> this";
I have tried with str_replace() but it is case sensitive,
Note:
I need to make the given string bold and keep as it is.
You can use array_walk PHP function to replace the string value within an array. Check below code
function my_str_replace(&$item){
$item = preg_replace("/test/i", '<b>$0</b>', $item);
}
$array[]="This is a test";
$array[]="This is a TEST";
$array[]="TeSt this";
array_walk($array, 'my_str_replace');
EDIT: Based on John WH Smith's comment
You can simply use $array = preg_replace("/test/i", '<b>$0</b>', $array); which would do the magic
If you're looking for patterns instead of fixed strings like "test", have a look at REGEXes and preg_replace :
$str = preg_replace("#(test|otherword)#i", "<b>$1</b>", $str);
More about REGEXes :
http://en.wikipedia.org/wiki/Regular_expression
http://www.regular-expressions.info/
http://uk.php.net/preg_replace
Edit : added "i" after the REGEX to remove case sensitivity.
You can use a function like the one I wrote below:
function wrap_text_with_tags( $haystack, $needle , $beginning_tag, $end_tag ) {
$needle_start = stripos($haystack, $needle);
$needle_end = $needle_start + strlen($needle);
$return_string = substr($haystack, 0, $needle_start) . $beginning_tag . $needle . $end_tag . substr($haystack, $needle_end);
return $return_string;
}
So you'd be able to call it as follows:
$original_string = 'Writing PHP code can be fun!';
$return_string = wrap_text_with_tags( $original_string , 'PHP' , "<strong>" ,"</strong>");
When returned the strings will look as follows:
Original String
Writing PHP code can be fun!
Modified Result
Writing PHP code can be fun!
This function only works on the FIRST instance of a string.
This is my solution. It also keeps all uppercase letters uppercase and all lowercase letters lowercase.
function wrapTextWithTags( $haystack, $needle , $tag ): string
{
$lowerHaystack = strtolower($haystack);
$lowerNeedle = strtolower($needle);
$start = stripos($lowerHaystack, $lowerNeedle);
$length = strlen($needle);
$textPart = substr($haystack, $start, $length);
$boldPart = "<" . $tag . ">" . $textPart . "</" . $tag . ">";
return str_replace($textPart, $boldPart, $haystack);
}
I find using a preg_replace() call to be the most appropriate tool for this task because:
it can affect all elements in the array without writing a loop,
it can replace more than one substring within a string,
adding a case-insensitive flag (i) is an easy and intuitive adjustment,
adding word boundaries (/b) on either side of the "needle" word will ensure that only whole words are replaced
when replacing the fullstring match, no parentheses / capture groups are necessary.
Code: (Demo)
$array = [
"This is a test",
"This is a TEST",
"Test this testy contest protest test!",
"TeSt this",
];
var_export(
preg_replace('/\btest\b/i', '<b>$0</b>', $array)
);
Output:
array (
0 => 'This is a <b>test</b>',
1 => 'This is a <b>TEST</b>',
2 => '<b>Test</b> this testy contest protest <b>test</b>!',
3 => '<b>TeSt</b> this',
)
Try str_ireplace. Case insensitive version of str_replace
Try this
Using str_ireplace
str_ireplace("test", "<b>test</b>", $array);
str_ireplace("TSET", "<b>TEST</b>", $array);

PHP explode string [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have this string: 0|DY1497ORYOSLDY932OSLCPH|1|0|0
and I need to explode it like that:
0| DY1497 ORY OSL DY932 OSL CPH |1|0|0
$string1 = 'DY1497';
$string2 = 'ORY';
$string3 = 'OSL';
$string4 = 'DY932';
$string5 = 'OSL';
$string6 = 'CPH';
I searched, but all I could find is how to explode when the text is separated with /, -, etc. Any ideas?
The best choice is probably a regex:
if (preg_match('/|(.{6})(.{3})(.{3})(.{5})(.{3})(.{3})|/', $string, $matches)) {
echo $matches[1];
echo $matches[2];
echo $matches[3];
echo $matches[4];
echo $matches[5];
echo $matches[6];
}
This divides the string simply by length in characters. You may need to modify this as needed. See http://regular-expressions.info
I suggest to use substr() if you know the exact position of the characters you need
Son, it looks to me like you searching for some specific tokens up in this here string. What I reckon you can do is, make yerself one array outa little search patterns you might be a looking fer. Something like this here:
$patterns = array('ORY', 'OSL', 'CPH', 'DY[\d]+');
Then you can make yerself a nice big regexp outa that:
$regexp = '/(' . implode('|', $patterns) . ')/';
Then, what you gonna do is, use preg_match_all to find every one of them fellers thisaway:
preg_match_all($regexp, $string, $matches);
Now, you do that and then looka what you got in $matches. I'd wager it has what you need.
Another way of splitting up strings that consists of fixed length fields is with 'unpack' which is very suited to this job.
here is some tested code that demonstrates it:
<?php
$origSource = '0|DY1497ORYOSLDY932OSLCPH|1|0|0';
// expected result
$string1 = 'DY1497';
$string2 = 'ORY';
$string3 = 'OSL';
$string4 = 'DY932';
$string5 = 'OSL';
$string6 = 'CPH';
// get the string we are interested in...
$tempStr = explode('|', $origSource);
$source = $tempStr[1]; // string with fixed length fields
/* debug */ var_dump($source);
// define where the fixed length fields are and the indexes to call them in the output array
$format = 'A6field1/' . 'A3field2/' . 'A3field3/'. 'A5field4/'. 'A3field5/'. 'A*field6/' ; // make it clear where the fields are...
$dest = unpack($format, $source);
/* debug */ var_dump($dest);
?>
firstly you have to concat your string with a special character like -,#,$ etc...
then you can explode it.
after that you may use the following syntax in php to explod string......
<?php
$string= "0|$DY1497$ORY$OSL$DY932$OSL$CPH$|1|0|0";
$pieces = explode("$", $string);
?>
For see your Result:---
<?php
foreach ($pieces as $value)
{
echo "piece: $value<br />";
}
?>
I hope it will help you.

Get the current + the next word in a string

this is what I try to get:
My longest text to test When I search for e.g. My I should get My longest
I tried it with this function to get first the complete length of the input and then I search for the ' ' to cut it.
$length = strripos($text, $input) + strlen($input)+2;
$stringpos = strripos($text, ' ', $length);
$newstring = substr($text, 0, strpos($text, ' ', $length));
But this only works first time and then it cuts after the current input, means
My lon is My longest and not My longest text.
How I must change this to get the right result, always getting the next word. Maybe I need a break, but I cannot find the right solution.
UPDATE
Here is my workaround till I find a better solution. As I said working with array functions does not work, since part words should work. So I extended my previous idea a bit. Basic idea is to differ between first time and the next. I improved the code a bit.
function get_title($input, $text) {
$length = strripos($text, $input) + strlen($input);
$stringpos = stripos($text, ' ', $length);
// Find next ' '
$stringpos2 = stripos($text, ' ', $stringpos+1);
if (!$stringpos) {
$newstring = $text;
} else if ($stringpos2) {
$newstring = substr($text, 0, $stringpos2);
} }
Not pretty, but hey it seems to work ^^. Anyway maybe someone of you have a better solution.
You can try using explode
$string = explode(" ", "My longest text to test");
$key = array_search("My", $string);
echo $string[$key] , " " , $string[$key + 1] ;
You can take i to the next level using case insensitive with preg_match_all
$string = "My longest text to test in my school that is very close to mY village" ;
var_dump(__search("My",$string));
Output
array
0 => string 'My longest' (length=10)
1 => string 'my school' (length=9)
2 => string 'mY village' (length=10)
Function used
function __search($search,$string)
{
$result = array();
preg_match_all('/' . preg_quote($search) . '\s+\w+/i', $string, $result);
return $result[0];
}
There are simpler ways to do that. String functions are useful if you don't want to look for something specific, but cut out a pre-defined length of something. Else use a regular expression:
preg_match('/My\s+\w+/', $string, $result);
print $result[0];
Here the My looks for the literal first word. And \s+ for some spaces. While \w+ matches word characters.
This adds some new syntax to learn. But less brittle than workarounds and lengthier string function code to accomplish the same.
An easy method would be to split it on whitespace and grab the current array index plus the next one:
// Word to search for:
$findme = "text";
// Using preg_split() to split on any amount of whitespace
// lowercasing the words, to make the search case-insensitive
$words = preg_split('/\s+/', "My longest text to test");
// Find the word in the array with array_search()
// calling strtolower() with array_map() to search case-insensitively
$idx = array_search(strtolower($findme), array_map('strtolower', $words));
if ($idx !== FALSE) {
// If found, print the word and the following word from the array
// as long as the following one exists.
echo $words[$idx];
if (isset($words[$idx + 1])) {
echo " " . $words[$idx + 1];
}
}
// Prints:
// "text to"

Categories