Related
I'm trying to do some sort of translator which would be able to keep text uppercase/lowercase.
I need to replace it in PHP string and MySQL query too.
Example:
Potato is jumping all over the PLACE.
Potato is jumping all over the pLAcE. (optional)
Potato is jumping all over the place.
Potato is jumping all over the Place.
I want to replace word 'place' with 'garden'.
Potato is jumping all over the GARDEN.
Potato is jumping all over the gARdEe. (optional)
Potato is jumping all over the garden.
Potato is jumping all over the Garden.
It should also work with phrases.
I've created a function that will replace the word for you and keep the cases.
function replaceWithCase($source, $replacement, $string) {
// Does the string contain the source word?
if (strpos($string, $source) === false) {
return false;
}
// If everything is uppercase, return the replacement fully uppercase
if (ctype_upper($source)) {
return str_replace($source, strtoupper($replacement));
}
// Set an array to work with
$characters = array();
// Split the source into characters
$sourceParts = explode('', $source);
// Loop throug the characters and set the case
foreach ($sourceParts as $k => $sp) {
if (ctype_upper($sp)) {
$characters[$k] = true;
} else {
$characters[$k] = false;
}
}
// Split the replacement into characters
$replacementParts = explode('', $replacement);
// Loop through characters and compare their case type
foreach ($replacementParts as $k => $rp) {
if (array_key_exists($k, $characters) && $characters[$k] === true) {
$newWord[] = strtoupper($rp);
} else {
$newWord[] = strtolower($rp);
}
}
return substr_replace($source, implode('', $newWord), $string);
}
// usage
echo replaceWithCase('AppLes', 'bananas', 'Comparing AppLes to pears');
Note: it is untested and might need some tweaking
function stringReplace($findStr, $replaceStr, $str)
{
$isLowerStr = true;
for($i=0; $i<strlen($findStr); $i++){
if(ord($findStr[$i]) >= 97 && ord($findStr[$i])<=122){
if(ord($replaceStr[$i]) >= 65 && ord($replaceStr[$i])<=96){
$replaceStr[$i] = strtolower($replaceStr[$i]);
}else{
$replaceStr[$i] = $replaceStr[$i];
}
}else{
$isLowerStr = false;
$replaceStr[$i] = strtoupper($replaceStr[$i]);
}
}
if($isLowerStr == false){
if(strlen($replaceStr) > strlen($findStr)){
for($i=0;$i<(strlen($replaceStr)-strlen($findStr));$i++){
if(strtoupper($findStr) == $findStr){
$replaceStr[strlen($findStr)+$i] = strtoupper($replaceStr[strlen($findStr)+$i]);
}else{
$replaceStr[strlen($findStr)+$i] = strtolower($replaceStr[strlen($findStr)+$i]);
}
}
}
}
echo str_replace($findStr, $replaceStr, $str);die;
}
$findStr = 'Place';
$replaceStr = 'garden';
echo stringReplace($findStr, $replaceStr, 'Potato is jumping all over the '.$findStr.'.');
So I managed to create my own function in the end. Thanks for help and inspiration though.
function replaceWithCase($source, $replacement, $string, $pos = 0) {
while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {
$substr = mb_substr($string, $pos, strlen($source));
$remaining = mb_substr($string, $pos + strlen($source));
if (ctype_upper($substr)) {
$string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
continue;
}
$substrParts = preg_split('//u', $substr, null, PREG_SPLIT_NO_EMPTY);
$replaceParts = preg_split('//u', $replacement, null, PREG_SPLIT_NO_EMPTY);
$newWord = '';
foreach ($replaceParts as $k => $rp) {
if (array_key_exists($k,$substrParts))
$newWord .= ctype_upper($substrParts[$k]) ? mb_strtoupper($rp) : mb_strtolower($rp);
else
$newWord .= $rp;
}
$string = substr_replace($string,$newWord,$pos,strlen($source));
$pos = $pos + strlen($source);
}
return $string;
}
echo replaceWithCase("place", "garden", "Potato is jumping all over the PLACE");
echo "<br>";
echo replaceWithCase("jumping", "running", "Potato is jumping all over the pLAcE");
echo "<br>";
echo replaceWithCase("jumping", "cry", "Potato is jumping all over the place");
echo "<br>";
echo replaceWithCase("all", "", "Potato is jumping all over the Place");
echo "<br>";
echo replaceWithCase(" ", ";", "Potato is jumping all over the Place", 10);
echo "<br>";
Output:
Potato is jumping all over the GARDEN
Potato is running all over the pLAcE
Potato is cry all over the place
Potato is jumping over the Place
Potato is jumping;all;over;the;Place
Thanks #LadaB - that's a really helpful function but it also replaces partial word matches. Sometimes you might want this, but in others cases you won't, for example if you have:
$source = 'mom';
$replacement = 'mum'; // british spelling of "mom"
$string = 'Be in the moment with your Mom.';
You get: "Be in the mument with your Mum."
So, I have added an option to make the match "whole word only".
I found another issue where multibyte characters would shift where the capitalization ended up, which seems to be fixed by changing. mb_substr to substr.
I also removed the unused:
$remaining = substr($string, $pos + strlen($source));
My latest (I think fully working) version is:
function replaceWithCase($source, $replacement, $string, $wholeWordOnly = false) {
$pos = 0;
while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {
if($wholeWordOnly) {
preg_match("/\b".$string[$pos]."/", $string[($pos-1)] . $string[$pos], $start);
preg_match("/".$string[($pos+strlen($source)-1)]."\b/", $source . $string[($pos+strlen($source))], $end);
}
if(($wholeWordOnly && $start && $end) || !$wholeWordOnly) {
$substr = substr($string, $pos, strlen($source));
if (ctype_upper($substr)) {
$string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
continue;
}
$substrParts = preg_split('//u', $substr, -1, PREG_SPLIT_NO_EMPTY);
$replaceParts = preg_split('//u', $replacement, -1, PREG_SPLIT_NO_EMPTY);
$newWord = '';
foreach ($replaceParts as $k => $rp) {
if (array_key_exists($k,$substrParts))
$newWord .= ctype_upper($substrParts[$k]) ? mb_strtoupper($rp) : mb_strtolower($rp);
else
$newWord .= $rp;
}
$string = substr_replace($string,$newWord,$pos,strlen($source));
}
$pos = $pos + strlen($source);
}
return $string;
}
Hope that helps you or someone else.
Use "stripos" php function
$str = 'Potato is jumping all over the pLAcEs.';
$str_new = "garden";
$str1 = str_split($str_new);
$pos = stripos($str,'places');
$string = substr($str,$pos,6);
$extrct = str_split($string);
$var = '';
foreach ($extrct as $key => $value) {
if(ctype_upper($value))
{
$var .= strtoupper($str1[$key]);
}else{
$var .= strtolower($str1[$key]);
}
}
$new_string = str_replace($string, $var, $str);
echo $new_string; //Potato is jumping all over the gARdEn.
I'm trying to do some sort of translator which would be able to keep text uppercase/lowercase.
I need to replace it in PHP string and MySQL query too.
Example:
Potato is jumping all over the PLACE.
Potato is jumping all over the pLAcE. (optional)
Potato is jumping all over the place.
Potato is jumping all over the Place.
I want to replace word 'place' with 'garden'.
Potato is jumping all over the GARDEN.
Potato is jumping all over the gARdEe. (optional)
Potato is jumping all over the garden.
Potato is jumping all over the Garden.
It should also work with phrases.
I've created a function that will replace the word for you and keep the cases.
function replaceWithCase($source, $replacement, $string) {
// Does the string contain the source word?
if (strpos($string, $source) === false) {
return false;
}
// If everything is uppercase, return the replacement fully uppercase
if (ctype_upper($source)) {
return str_replace($source, strtoupper($replacement));
}
// Set an array to work with
$characters = array();
// Split the source into characters
$sourceParts = explode('', $source);
// Loop throug the characters and set the case
foreach ($sourceParts as $k => $sp) {
if (ctype_upper($sp)) {
$characters[$k] = true;
} else {
$characters[$k] = false;
}
}
// Split the replacement into characters
$replacementParts = explode('', $replacement);
// Loop through characters and compare their case type
foreach ($replacementParts as $k => $rp) {
if (array_key_exists($k, $characters) && $characters[$k] === true) {
$newWord[] = strtoupper($rp);
} else {
$newWord[] = strtolower($rp);
}
}
return substr_replace($source, implode('', $newWord), $string);
}
// usage
echo replaceWithCase('AppLes', 'bananas', 'Comparing AppLes to pears');
Note: it is untested and might need some tweaking
function stringReplace($findStr, $replaceStr, $str)
{
$isLowerStr = true;
for($i=0; $i<strlen($findStr); $i++){
if(ord($findStr[$i]) >= 97 && ord($findStr[$i])<=122){
if(ord($replaceStr[$i]) >= 65 && ord($replaceStr[$i])<=96){
$replaceStr[$i] = strtolower($replaceStr[$i]);
}else{
$replaceStr[$i] = $replaceStr[$i];
}
}else{
$isLowerStr = false;
$replaceStr[$i] = strtoupper($replaceStr[$i]);
}
}
if($isLowerStr == false){
if(strlen($replaceStr) > strlen($findStr)){
for($i=0;$i<(strlen($replaceStr)-strlen($findStr));$i++){
if(strtoupper($findStr) == $findStr){
$replaceStr[strlen($findStr)+$i] = strtoupper($replaceStr[strlen($findStr)+$i]);
}else{
$replaceStr[strlen($findStr)+$i] = strtolower($replaceStr[strlen($findStr)+$i]);
}
}
}
}
echo str_replace($findStr, $replaceStr, $str);die;
}
$findStr = 'Place';
$replaceStr = 'garden';
echo stringReplace($findStr, $replaceStr, 'Potato is jumping all over the '.$findStr.'.');
So I managed to create my own function in the end. Thanks for help and inspiration though.
function replaceWithCase($source, $replacement, $string, $pos = 0) {
while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {
$substr = mb_substr($string, $pos, strlen($source));
$remaining = mb_substr($string, $pos + strlen($source));
if (ctype_upper($substr)) {
$string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
continue;
}
$substrParts = preg_split('//u', $substr, null, PREG_SPLIT_NO_EMPTY);
$replaceParts = preg_split('//u', $replacement, null, PREG_SPLIT_NO_EMPTY);
$newWord = '';
foreach ($replaceParts as $k => $rp) {
if (array_key_exists($k,$substrParts))
$newWord .= ctype_upper($substrParts[$k]) ? mb_strtoupper($rp) : mb_strtolower($rp);
else
$newWord .= $rp;
}
$string = substr_replace($string,$newWord,$pos,strlen($source));
$pos = $pos + strlen($source);
}
return $string;
}
echo replaceWithCase("place", "garden", "Potato is jumping all over the PLACE");
echo "<br>";
echo replaceWithCase("jumping", "running", "Potato is jumping all over the pLAcE");
echo "<br>";
echo replaceWithCase("jumping", "cry", "Potato is jumping all over the place");
echo "<br>";
echo replaceWithCase("all", "", "Potato is jumping all over the Place");
echo "<br>";
echo replaceWithCase(" ", ";", "Potato is jumping all over the Place", 10);
echo "<br>";
Output:
Potato is jumping all over the GARDEN
Potato is running all over the pLAcE
Potato is cry all over the place
Potato is jumping over the Place
Potato is jumping;all;over;the;Place
Thanks #LadaB - that's a really helpful function but it also replaces partial word matches. Sometimes you might want this, but in others cases you won't, for example if you have:
$source = 'mom';
$replacement = 'mum'; // british spelling of "mom"
$string = 'Be in the moment with your Mom.';
You get: "Be in the mument with your Mum."
So, I have added an option to make the match "whole word only".
I found another issue where multibyte characters would shift where the capitalization ended up, which seems to be fixed by changing. mb_substr to substr.
I also removed the unused:
$remaining = substr($string, $pos + strlen($source));
My latest (I think fully working) version is:
function replaceWithCase($source, $replacement, $string, $wholeWordOnly = false) {
$pos = 0;
while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {
if($wholeWordOnly) {
preg_match("/\b".$string[$pos]."/", $string[($pos-1)] . $string[$pos], $start);
preg_match("/".$string[($pos+strlen($source)-1)]."\b/", $source . $string[($pos+strlen($source))], $end);
}
if(($wholeWordOnly && $start && $end) || !$wholeWordOnly) {
$substr = substr($string, $pos, strlen($source));
if (ctype_upper($substr)) {
$string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
continue;
}
$substrParts = preg_split('//u', $substr, -1, PREG_SPLIT_NO_EMPTY);
$replaceParts = preg_split('//u', $replacement, -1, PREG_SPLIT_NO_EMPTY);
$newWord = '';
foreach ($replaceParts as $k => $rp) {
if (array_key_exists($k,$substrParts))
$newWord .= ctype_upper($substrParts[$k]) ? mb_strtoupper($rp) : mb_strtolower($rp);
else
$newWord .= $rp;
}
$string = substr_replace($string,$newWord,$pos,strlen($source));
}
$pos = $pos + strlen($source);
}
return $string;
}
Hope that helps you or someone else.
Use "stripos" php function
$str = 'Potato is jumping all over the pLAcEs.';
$str_new = "garden";
$str1 = str_split($str_new);
$pos = stripos($str,'places');
$string = substr($str,$pos,6);
$extrct = str_split($string);
$var = '';
foreach ($extrct as $key => $value) {
if(ctype_upper($value))
{
$var .= strtoupper($str1[$key]);
}else{
$var .= strtolower($str1[$key]);
}
}
$new_string = str_replace($string, $var, $str);
echo $new_string; //Potato is jumping all over the gARdEn.
I am trying to remove all leading and trailing <br> in a string using PHP.
Here is an example
<br><br>
Hello<br>
World<br>
<p>This is a message<br>...</p>
<br><br><br><br>
I want to return
Hello<br>
World<br>
<p>This is a message<br>...</p>
I tried to do the following
echo trim($str, '<br>');
But it does not remove them. How can I remove the new line html code?
Use preg_replace with the beginning ^ and end $ anchors:
$string = preg_replace('/^(<br>){0,}|(<br>){0,}$/', '', $string);
Or for multiple lines:
$string = preg_replace('/^(<br>){0,}|(<br>){0,}$/m', '', $string);
You could also trim() it multiple times:
while($string !== ($string = trim($string, '<br>'))){}
This function does the job. Also applicable to anything else really.
//remove all leading and trailing occurences of needle ($n) from haystack ($h)
function trimAll($h, $n){
if(!$h = trim($h,$n)){
trimAll($h, $n);
}
return $h;
}
I wrote this function that will do the job a little better as it gives me more flexibility on what characters to remove and when this function by default will first remove the leading/trailing characters in order:
any tabs
any new lines
any
any
any tabs
any new lines
function trimString($str, $myList = array("\t","\n", "<br>","<br />", "\t","\n") ){
if( ! is_array($myList) ){
$charsToTrim[] = $chr;
} else {
$charsToTrim = $myList;
}
foreach($charsToTrim as $chr){
$len = strlen($chr);
$nlen = $len * -1;
while( substr($str, 0, $len) == $chr){
$str = trim(substr($str, $len));
}
while( substr($str, $nlen) == $chr){
$str = trim(substr($str, 0, $nlen));
}
}
return $str;
}
to use
// default use case
echo trimString($message);
or
//remove only one string
echo trimString($message, '<br>'); // remove only the leading training '<br>'
or
//remove more than 1 string in order
echo trimString($message, array('<br>'<br />') );
I hope this helps someone out there :)
$p=array(
'<br><br>',
'Hello<br>',
'World<br>',
'<p>This is a message<br>...</p>',
'<br><br><br><br>'
);
function trimdeluxe($str, $sub)
{
$parts=explode($sub, $str);
for ($x=0; $x<2; $x++) {
foreach ($parts as $i=>$v) {
if (!strlen($v)) {
unset($parts[$i]);
} else {
break;
}
}
$parts=array_reverse($parts);
}
return implode($sub,$parts);
}
foreach ($p as $str) {
print $str . ' -> ' . trimdeluxe($str, '<br>') . "\n";
}
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));
?>
Well I know obfuscation is a bad idea. But I want all of my html code to come in one long single line. All the html tags are generated through PHP, so I think its possible. I knew replacing \n\r from regular expression, but have no idea how to do this one. In case I am unclear here is an example
$output = '<p>
<div class="title">Hello</div>
</p>';
echo $output;
To be view in the source viewer as <p><div class="title">Hello</div></p>
Maybe this?
$output = str_replace(array("\r\n", "\r"), "\n", $output);
$lines = explode("\n", $output);
$new_lines = array();
foreach ($lines as $i => $line) {
if(!empty($line))
$new_lines[] = trim($line);
}
echo implode($new_lines);
You can try this perhaps.
// Before any output
ob_start();
// End of file
$output = ob_get_clean();
echo preg_replace('/^\s+|\n|\r|\s+$/m', '', $output);
This should, unless I messed up the regex, catch all output, and then replace all new line characters as well as all whitespace at the end and beginning of lines.
If you already have all output collected in a variable, you can of course just use the last line directly and skip the output buffering stuff :)
Worked for me:
$output = str_replace(array("\r\n", "\r", "\n"), "", $output);
You can do :
$output = '<p>'.
'<div class="title">Hello</div>'.
'</p>';
This way, $output won't contain any line jump.
This should also work :
$output = preg_replace(array('/\r/', '/\n/'), '', $output);
$output = preg_replace('!\s+!m', ' ', $output);
This is already well answered, but you may be able to do more than just trim spaces at both ends of each line:
First extract all text within quotes (you don't want to touch those), replace with a marker with a sequence number, store the sequence number with the text
Extract all text within <script></script> tags and do the same as step #1
Replace all white-space (including \n, \r) with spaces
Replace all >1 space sequences with 1 space
Replace all >_< with >< (_ = space)
Replace all _>, <_ and </_ with >, < and </ (_ = space)
Replace markers with the actual texts
This procedure can potentially compact the entire HTML file. This takes advantage of the fact that multiple white-space text inside HTML tags are intepreted as one single space.
This is a (as far as I have tested) working implementation of Stephen Chung's instructions. I'm not entirely convinced by number five, but have included it anyway.
Put the things you want to protect in the protected_parts array. Do it in order that you want them protected. If the starting and ending bits are different (as they would be in HTML tags), separate them by using a comma.
Also, I've no idea if this is the most optimised way of doing this, but it works for me and seems reasonably fast. Feel free to improve, etc. (Let me know if you do too!)
function MinifyHTML($str) {
$protected_parts = array("<pre>,</pre>", "\"", "'");
$extracted_values = array();
$i = 0;
foreach ($protected_parts as $part) {
$finished = false;
$search_offset = 0;
$first_offset = 0;
$startend = explode(",", $part);
if (count($startend) == 1) { $startend[1] = $startend[0]; }
while (!$finished) {
$first_offset = strpos($str, $startend[0], $search_offset);
if ($first_offset === false) { $finished = true; }
else {
$search_offset = strpos($str, $startend[1], $first_offset + strlen($startend[0]));
$extracted_values[$i] = substr($str, $first_offset + strlen($startend[0]), $search_offset - $first_offset - strlen($startend[0]));
$str = substr($str, 0, $first_offset + strlen($startend[0]))."$#".$i."$".substr($str, $search_offset);
$search_offset += strlen($startend[1]) + strlen((string)$i) + 3 - strlen($extracted_values[$i]);
$i++;
}
}
}
$str = preg_replace("/\s/", " ", $str);
$str = preg_replace("/\s{2,}/", " ", $str);
$str = str_replace("> <", "><", $str);
$str = str_replace(" >", ">", $str);
$str = str_replace("< ", "<", $str);
$str = str_replace("</ ", "</", $str);
for ($i = count($extracted_values); $i >= 0; $i--) {
$str = str_replace("$#".$i."$", $extracted_values[$i], $str);
}
return $str;
}
This is an improved function of the above. It adds text area protection and also anything that is a tag remains untouched.
I also removed strlen in the loop (its static).
This might run faster as a one pass filter to check for any of the protected parts. For such a small protected_parts array it's going to be more efficient than looping through the $str four times.
Also this doesn't fix: class = " " (the extra spaces between = and ") as its stuff inside the tags.
function MinifyHTML($str) {
$protected_parts = array('<pre>,</pre>','<textarea>,</textarea>', '<,>');
$extracted_values = array();
$i = 0;
foreach ($protected_parts as $part) {
$finished = false;
$search_offset = $first_offset = 0;
$end_offset = 1;
$startend = explode(',', $part);
if (count($startend) === 1) $startend[1] = $startend[0];
$len0 = strlen($startend[0]); $len1 = strlen($startend[1]);
while ($finished === false) {
$first_offset = strpos($str, $startend[0], $search_offset);
if ($first_offset === false) $finished = true;
else {
$search_offset = strpos($str, $startend[1], $first_offset + $len0);
$extracted_values[$i] = substr($str, $first_offset + $len0, $search_offset - $first_offset - $len0);
$str = substr($str, 0, $first_offset + $len0).'$$#'.$i.'$$'.substr($str, $search_offset);
$search_offset += $len1 + strlen((string)$i) + 5 - strlen($extracted_values[$i]);
++$i;
}
}
}
$str = preg_replace("/\s/", " ", $str);
$str = preg_replace("/\s{2,}/", " ", $str);
$replace = array('> <'=>'><', ' >'=>'>','< '=>'<','</ '=>'</');
$str = str_replace(array_keys($replace), array_values($replace), $str);
for ($d = 0; $d < $i; ++$d)
$str = str_replace('$$#'.$d.'$$', $extracted_values[$d], $str);
return $str;
}
You can't have <div> inside <p> - it is not spec-valid.
If you don't need to store it in a variable you can use this:
?><div><?php
?><div class="title">Hello</div><?php
?></div><?php