Replacing string except certain parts - php

I'm writing a PHP app, and I have an input string in the form
Hello world. Hello [fbes_keep]world[/fbes_keep].
And a new string in the form
Hallo welt. Hello.
What I want it for the input string to be replaced by the new string, except the parts in the [fbes_keep] tags, so the output is
Hallo welt. Hello [fbes_keep]world[/fbes_keep].
My current approach involves using the finediff library but overriding the delete opcodes to look for the fbes tags. I asked a question about this yesterday, but I feel I may have run into the XY problem. Is there a better way?
Edit: Gist containing current (non-functional) code and real-world test case.

Maybe this is not the most elegant way how do I did it, but I've tested it, and it do the job:
$expression = 'world';
$newExpression = 'welt';
$str = 'Hello world. Hello [fbes_keep]world[/fbes_keep]. Here are some other world, and [fbes_keep]other[/fbes_keep] word in fbes.';
$pattern = '/\[fbes_keep\].*?\[\/fbes_keep\]/i';
$fbKepps = [];
preg_match_all($pattern, $str, $fbKepps);
$others = preg_split($pattern, $str);
$result = '';
$i = 0;
foreach ($others as $other) {
$result .= preg_replace('/' . addslashes($expression) . '/', $newExpression, $other);
$i++;
if ($i < count($others)) {
$result .= $fbKepps[0][$i - 1];
}
}
echo $result;
OUTPUT
Hello welt. Hello [fbes_keep]world[/fbes_keep]. Here are some other welt, and [fbes_keep]other[/fbes_keep] word in fbes.
My ideia is to split the string by [fbes_keep]...[/fbes_keep], but before store them in an array. Then iterate through all the rest, change the world to welt then concat the next fbes_keep and so on...
It keeps everything wher [fbes_keep]anything[/fbes_keep] and there are multiple fbes_keep can be in string with other words too.

Related

Php find and replace words in a text from database tables

I'm working on a project. It searches and replaces words from the database in a given text. In the database a have 10k words and replacements. So ı want to search for each word and replace this word's replacement word.
By the way, I'm using laravel. I need only replacement ideas.
I have tried some ways but it replaces only one word.
My database table structure like below;
id word replacement
1 test testing
etc
The text is coming from the input and after the replacement, I wanna show which words are replaced in a different bg color in the result page.
I tried below codes working fine but it only replaces one word.
$article = trim(strip_tags($request->article));
$clean = preg_split('/[\s]+/', $article);
$word_count = count($clean);
$words_from_database_for_search = Words::all();
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\">$word[replacement]
</span>",
$article);
}
$new_content = $content ;
$new_content_clean = preg_split('/[\s]+/', $new_content);
$new_content_word_count= count($new_content_clean);
Edit,
Im using preg_replace instead of str_replace. I get it worked but this time i wanna show how many words changed so i tried to find the number of changed words from the text after replacement. It counts wrong.
Example if there is 6 changes it show 3 or 4
It can be done via preg_replace_callback but i didnt use it before so i dont know how to figure out;
My working codes are below;
$old_article = trim(strip_tags($request->article));
$old_article_word_count = count($old_article );
$words_from_database_array= Words::all();
$article_will_replace = trim(strip_tags($request->article));
$count_the_replaced_words = 0;
foreach($words_from_database_array as $word){
$article_will_replace = preg_replace('/[^a-zA-
ZğüşıöçĞÜŞİÖÇ]\b'.$word['word'].'\b\s/u',
" <b>".$word['spin']."</b> ",
$article_will_replace );
$count_the_replaced_words = preg_match_all('/[^a-zA-
ZğüşıöçĞÜŞİÖÇ]\b'.strip_tags($word['spin']).'\b\s/u',$article_will_replace
);
if($count_the_replaced_words ){
$count_the_replaced_words ++;
}
}
As others have suggested in comments, it seems your value of $content is being overwritten on each run of the foreach loop, with older iterations being ignored. That's because the third argument of your str_replace is $article, the original, unmodified text. Only the last word, therefore, is showing up on the result.
The simplest way to fix this would be to declare $content before the foreach loop, and then make $content the third argument of the foreach loop so that it is continually replaced with a new word on each iteration, like so:
$content = $article;
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\">$word[replacement]</span>",
$content);
}
Im confused, don't you need the <?php ... ?> around the $word[replacement] ?
foreach($words_from_database_for_search as $word){
$content = str_replace($word['word'],
"<span class=\"badge badge-success\"><?PHP $word[replacement] ?>
</span>",
$article);
}
and then move this in to the for-loop and add a dot before the equal-sign:
$new_content .= $content ;

Unspin text in php from spun text on sentence level

I need to neatly output spun text in a php page.
I already have the prespun text in {hi|hello|greetings} format.
I have a php code that i found elsewhere, but it does not output the spun text on sentence level, where two {{ come.
Here is the code that needs fixing.
<?php
function spinText($text){
$test = preg_match_all("#\{(.*?)\}#", $text, $out);
if (!$test) return $text;
$toFind = Array();
$toReplace = Array();
foreach($out[0] AS $id => $match){
$choices = explode("|", $out[1][$id]);
$toFind[]=$match;
$toReplace[]=trim($choices[rand(0, count($choices)-1)]);
}
return str_replace($toFind, $toReplace, $text);
}
echo spinText("{Hello|Hi|Greetings}!");;
?>
The output will be randomly chose word: Hello OR Hi OR Greetings.
However, if there is a sentence level spinning, the output is messed up.
E.g.:
{{hello|hi}.{how're|how are} you|{How's|How is} it going}
The output is
{hello.how're you|How is it going}
As you can see the text has not been spun completely.
Thank you
This is a recursive problem, so regular expressions aren't that great; but recursive patterns can help though:
function bla($s)
{
// first off, find the curly brace patterns (those that are properly balanced)
if (preg_match_all('#\{(((?>[^{}]+)|(?R))*)\}#', $s, $matches, PREG_OFFSET_CAPTURE)) {
// go through the string in reverse order and replace the sections
for ($i = count($matches[0]) - 1; $i >= 0; --$i) {
// we recurse into this function here
$s = substr_replace($s, bla($matches[1][$i][0]), $matches[0][$i][1], strlen($matches[0][$i][0]));
}
}
// once we're done, it should be safe to split on the pipe character
$choices = explode('|', $s);
return $choices[array_rand($choices)];
}
echo bla("{{hello|hi}.{how're|how are} you|{How's|How is} it going}"), "\n";
See also: Recursive patterns

Match words (regex) and create internal links from values stored in Array

What I am trying to achieve is the following:
When I create news items, I want php to check these items for keywords. These keywords are stored in a mysql table (2 fields: search = varchar(255), link = varchar(255)).
I use a query to get the results and store them in an array.
I want to find words in a string and add an anchor to the word. The important bit is (where I have difficulty with) is that the search has to be case insensitive.
For example:
$searchFor = array("sun","sunny","wind","crap");
$linkArray = array("/solar","/solar","/wind-energy","/toilet");
The string:
What do you know about the sun? Sun, what kind of word is that? Is it
something just like wind? Wind, another weird word. This text is
complete crap by the way.
What I want as a result is:
What do you know about the sun? Sun what kind of word is that? Is it something just like wind? Wind another weird word. This text is complete crap by the way.
The code I have is:
$string = 'What do you know about the sun? Sun, what kind of word is that? Is it something just like wind? Wind, another weird word. This text is complete crap by the way.';
$pattern = "/(\w+)/i";
preg_match_all($pattern, $string, $matches);
foreach($matches[0] as $i => $word)
{
$search = strtolower($word);
if(in_array($search,$searchFor))
{
$pos = array_search($search,$searchFor);
$link = $linkArray[$pos];
echo "{$word} ";
}
else
{
echo $word." ";
}
}
But I get stuck using regex (I think this is the right way).
$replacement = '${1}';
Is this possible??
Thank you.
Testet!
<?php
$searchFor = array("sun","sunny","wind","crap");
foreach($searchFor as $iKey => $sVal) {
$searchFor[$iKey] = "/(" . $sVal . ")/i";
}
$linkArray = array("/solar","/solar","/wind-energy","/toilet");
foreach($linkArray as $iKey => $sVal) {
$linkArray[$iKey] = '$1';
}
$string = 'What do you know about the sun? Sun, what kind of word is that? Is it something just like wind? Wind, another weird word. This text is complete crap by the way.';
echo preg_replace($searchFor, $linkArray, $string);

how to CaPiTaLiZe every other character in php?

I want to CaPiTaLiZe $string in php, don't ask why :D
I made some research and found good answers here, they really helped me.
But, in my case I want to start capitalizing every odd character (1,2,3...) in EVERY word.
For example, with my custom function i'm getting this result "TeSt eXaMpLe" and want to getting this "TeSt ExAmPlE".
See that in second example word "example" starts with capital "E"?
So, can anyone help me? : )
Well I would just make it an array and then put it back together again.
<?php
$str = "test example";
$str_implode = str_split($str);
$caps = true;
foreach($str_implode as $key=>$letter){
if($caps){
$out = strtoupper($letter);
if($out <> " ") //not a space character
$caps = false;
}
else{
$out = strtolower($letter);
$caps = true;
}
$str_implode[$key] = $out;
}
$str = implode('',$str_implode);
echo $str;
?>
Demo: http://codepad.org/j8uXM97o
I would use regex to do this, since it is concise and easy to do:
$str = 'I made some research and found good answers here, they really helped me.';
$str = preg_replace_callback('/(\w)(.?)/', 'altcase', $str);
echo $str;
function altcase($m){
return strtoupper($m[1]).$m[2];
}
Outputs: "I MaDe SoMe ReSeArCh AnD FoUnD GoOd AnSwErS HeRe, ThEy ReAlLy HeLpEd Me."
Example
Here's a one liner that should work.
preg_replace('/(\w)(.)?/e', "strtoupper('$1').strtolower('$2')", 'test example');
http://codepad.org/9LC3SzjC
Try:
function capitalize($string){
$return= "";
foreach(explode(" ",$string) as $w){
foreach(str_split($w) as $k=>$v) {
if(($k+1)%2!=0 && ctype_alpha($v)){
$return .= mb_strtoupper($v);
}else{
$return .= $v;
}
}
$return .= " ";
}
return $return;
}
echo capitalize("I want to CaPiTaLiZe string in php, don't ask why :D");
//I WaNt To CaPiTaLiZe StRiNg In PhP, DoN'T AsK WhY :D
Edited: Fixed the lack of special characters in the output.
This task can be performed without using capture groups -- just use ucfirst().
This is not built to process multibyte characters.
Grab a word character then, optionally, the next character. From the fullstring match, only change the case of the first character.
Code: (Demo) (or Demo)
$strings = [
"test string",
"lado lomidze needs a solution",
"I made some research and found 'good' answers here; they really helped me."
]; // if not already all lowercase, use strtolower()
var_export(preg_replace_callback('/\w.?/', function ($m) { return ucfirst($m[0]); }, $strings));
Output:
array (
0 => 'TeSt StRiNg',
1 => 'LaDo LoMiDzE NeEdS A SoLuTiOn',
2 => 'I MaDe SoMe ReSeArCh AnD FoUnD \'GoOd\' AnSwErS HeRe; ThEy ReAlLy HeLpEd Me.',
)
For other researchers, if you (more simply) just want to convert every other character to uppercase, you could use /..?/ in your pattern, but using regex for this case would be overkill. You could more efficiently use a for() loop and double-incrementation.
Code (Demo)
$string = "test string";
for ($i = 0, $len = strlen($string); $i < $len; $i += 2) {
$string[$i] = strtoupper($string[$i]);
}
echo $string;
// TeSt sTrInG
// ^-^-^-^-^-^-- strtoupper() was called here

Cut string into pieces without breaking words.

I have a string:
$str = 'Hello World, Welcome World, Bye World';
I want to cut above string into pieces. Each piece should be of 10 characters. If a word is going to be cut, then move that word to next line.
For Example:
$output = array();
$output[0] = 'Hello ';
$output[1] = 'World, ';
$output[2] = 'Welcome ';
$output[3] = 'World, Bye';
$output[4] = 'World';
Is there a shortest way without so many if else and loops.
Thanks
Use wordwrap. By default it wraps whole words and does not cut them into pieces.
echo wordwrap('Hello World, Welcome World, Bye World', 10);
If you want an array, explode afterwards:
print_r(explode("\n", wordwrap('Hello World, Welcome World, Bye World', 10)));
string test = 'Hello World, Welcome World, Bye World';
string[] splited = test.Split(' ');
foreach (string str in s.Split(splited))
{
Console.WriteLine(str);
}
Note: Its written in C#, I hope it will give you an Idea.
Regards
Although not exactly the answer, some similar problem is like this:
You have a long string, you want to break that string into chunks. You prefer not to break words, but words can be broken if word is very long.
$string = "Hello I am a sentence but I have verylongwordthat I can split";
You will split the words in this sentence if word is very long, like this:
$pieces = explode(" ",$string);
$textArray=array();
foreach ($pieces as $p) {
$textArray= array_merge($textArray, str_split($p, 10));
}
$stringNew=implode(" ",$textArray);
output:
"Hello I am a sentence but I have verylongwo rdthat I can split"

Categories