php str_replace issue or bug? - php

I have the following issue;
Here is my string I'm trying to remove javascript:l(" from the string below:
javascript:l("Bayou-La-Batre");
My code is;
$q_string = str_replace('javascript:l(" ','',$row['1']);
But it's failing.
This is quicker than a regex replace and quicker.
Any ideas?

You left a space
$q_string = str_replace('javascript:l("','',$row['1']);

Change
$q_string = str_replace('javascript:l(" ','',$row['1']);
to
$q_string = str_replace('javascript:l("','',$row['1']);

Whenever I'm having this kind of problem, I try formatting my search/replace call in a monospaced editor to see if anything pops out
$q_string = str_replace('javascript:l(" ', '',
'javascript:l("Bayou-La-Batre")';
Formated like that, it becomes obvious that the 15th character of the search string does not match the 15th characters of the string that's being searched ([ ] vs. [B]).
Try removing that whitespace and you should be happy.

You can use
$q_string = substr($row['1'], 14);
to get the same results with some speed gain. I have tested speeds of three function so you can see how they compare with speed.
$string = 'javascript:l("Bayou-La-Batre")';
$str_replace = function($string) {
return str_replace('javascript:l("', '', $string);
};
print $str_replace($string) . "\n";
$substr = function($string) {
return substr($string, 14);
};
print $substr($string) . "\n";
$preg_replace = function($string) {
return preg_replace('/^[a-z:\(]+"/', '', $string);
};
print $preg_replace($string) . "\n";
function measure($function, $string) {
$start = microtime(true);
for($i = 0; $i < 1000000; $i++) {
$function($string);
}
return microtime(true) - $start;
}
print 'Substr: ' . measure($substr, $string) . "\n";
print 'Str replace:' . measure($str_replace, $string) . "\n";
print 'Preg replace:' . measure($preg_replace, $string);
The output of this on my machine
Bayou-La-Batre")
Bayou-La-Batre")
Bayou-La-Batre")
Substr: 3.7492098808289
Str replace:4.5258920192719
Preg replace:5.8815109729767

Related

How to limit word count instead of character count on product short description in woocommerce? [duplicate]

How can I truncate a string after 20 words in PHP?
function limit_text($text, $limit) {
if (str_word_count($text, 0) > $limit) {
$words = str_word_count($text, 2);
$pos = array_keys($words);
$text = substr($text, 0, $pos[$limit]) . '...';
}
return $text;
}
echo limit_text('Hello here is a long sentence that will be truncated by the', 5);
Outputs:
Hello here is a long ...
Change the number 3 to the number 20 below to get the first 20 words, or pass it as parameter. The following demonstrates how to get the first 3 words: (so change the 3 to 20 to change the default value):
function first3words($s, $limit=3) {
return preg_replace('/((\w+\W*){'.($limit-1).'}(\w+))(.*)/', '${1}', $s);
}
var_dump(first3words("hello yes, world wah ha ha")); # => "hello yes, world"
var_dump(first3words("hello yes,world wah ha ha")); # => "hello yes,world"
var_dump(first3words("hello yes world wah ha ha")); # => "hello yes world"
var_dump(first3words("hello yes world")); # => "hello yes world"
var_dump(first3words("hello yes world.")); # => "hello yes world"
var_dump(first3words("hello yes")); # => "hello yes"
var_dump(first3words("hello")); # => "hello"
var_dump(first3words("a")); # => "a"
var_dump(first3words("")); # => ""
To Nearest Space
Truncates to nearest preceding space of target character. Demo
$str The string to be truncated
$chars The amount of characters to be stripped, can be overridden by $to_space
$to_space boolean for whether or not to truncate from space near $chars limit
Function
function truncateString($str, $chars, $to_space, $replacement="...") {
if($chars > strlen($str)) return $str;
$str = substr($str, 0, $chars);
$space_pos = strrpos($str, " ");
if($to_space && $space_pos >= 0)
$str = substr($str, 0, strrpos($str, " "));
return($str . $replacement);
}
Sample
<?php
$str = "this is a string that is just some text for you to test with";
print(truncateString($str, 20, false) . "\n");
print(truncateString($str, 22, false) . "\n");
print(truncateString($str, 24, true) . "\n");
print(truncateString($str, 26, true, " :)") . "\n");
print(truncateString($str, 28, true, "--") . "\n");
?>
Output
this is a string tha...
this is a string that ...
this is a string that...
this is a string that is :)
this is a string that is--
use explode() .
Example from the docs.
// Example 1
$pizza = "piece1 piece2 piece3 piece4 piece5 piece6";
$pieces = explode(" ", $pizza);
echo $pieces[0]; // piece1
echo $pieces[1]; // piece2
note that explode has a limit function. So you could do something like
$message = implode(" ", explode(" ", $long_message, 20));
Try regex.
You need something that would match 20 words (or 20 word boundaries).
So (my regex is terrible so correct me if this isn't accurate):
/(\w+\b){20}/
And here are some examples of regex in php.
Simple and fully equiped truncate() method:
function truncate($string, $width, $etc = ' ..')
{
$wrapped = explode('$trun$', wordwrap($string, $width, '$trun$', false), 2);
return $wrapped[0] . (isset($wrapped[1]) ? $etc : '');
}
Its not my own creation, its a modification of previous posts. credits goes to karim79.
function limit_text($text, $limit) {
$strings = $text;
if (strlen($text) > $limit) {
$words = str_word_count($text, 2);
$pos = array_keys($words);
if(sizeof($pos) >$limit)
{
$text = substr($text, 0, $pos[$limit]) . '...';
}
return $text;
}
return $text;
}
If you code on Laravel just use Illuminate\Support\Str
here is example
Str::words($category->publication->title, env('WORDS_COUNT_HOME'), '...')
Hope this was helpful.
Split the string (into an array) by <space>, and then take the first 20 elements of that array.
With triple dots:
function limitWords($text, $limit) {
$word_arr = explode(" ", $text);
if (count($word_arr) > $limit) {
$words = implode(" ", array_slice($word_arr , 0, $limit) ) . ' ...';
return $words;
}
return $text;
}
Try below code,
$text = implode(' ', array_slice(explode(' ', $text), 0, 32))
echo $text;
Something like this could probably do the trick:
<?php
$words = implode(' ', array_slice(split($input, ' ', 21), 0, 20));
use PHP tokenizer function strtok() in a loop.
$token = strtok($string, " "); // we assume that words are separated by sapce or tab
$i = 0;
$first20Words = '';
while ($token !== false && $i < 20) {
$first20Words .= $token;
$token = strtok(" ");
$i++;
}
echo $first20Words;
based on 動靜能量's answer:
function truncate_words($string,$words=20) {
return preg_replace('/((\w+\W*){'.($words-1).'}(\w+))(.*)/', '${1}', $string);
}
or
function truncate_words_with_ellipsis($string,$words=20,$ellipsis=' ...') {
$new = preg_replace('/((\w+\W*){'.($words-1).'}(\w+))(.*)/', '${1}', $string);
if($new != $string){
return $new.$ellipsis;
}else{
return $string;
}
}
This worked me for UNICODE (UTF8) sentences too:
function myUTF8truncate($string, $width){
if (mb_str_word_count($string) > $width) {
$string= preg_replace('/((\w+\W*|| [\p{L}]+\W*){'.($width-1).'}(\w+))(.*)/', '${1}', $string);
}
return $string;
}
Here is what I have implemented.
function summaryMode($text, $limit, $link) {
if (str_word_count($text, 0) > $limit) {
$numwords = str_word_count($text, 2);
$pos = array_keys($numwords);
$text = substr($text, 0, $pos[$limit]).'... Read More';
}
return $text;
}
As you can see it is based off karim79's answer, all that needed changing was that the if statement also needed to check against words not characters.
I also added a link to main function for convenience. So far it hsa worked flawlessly. Thanks to the original solution provider.
Here's one I use:
$truncate = function( $str, $length ) {
if( strlen( $str ) > $length && false !== strpos( $str, ' ' ) ) {
$str = preg_split( '/ [^ ]*$/', substr( $str, 0, $length ));
return htmlspecialchars($str[0]) . '…';
} else {
return htmlspecialchars($str);
}
};
return $truncate( $myStr, 50 );
Another solution :)
$aContent = explode(' ', $cContent);
$cContent = '';
$nCount = count($aContent);
for($nI = 0; ($nI < 20 && $nI < $nCount); $nI++) {
$cContent .= $aContent[$nI] . ' ';
}
trim($cContent, ' ');
echo '<p>' . $cContent . '</p>';
To limit words, am using the following little code :
$string = "hello world ! I love chocolate.";
$explode = array_slice(explode(' ', $string), 0, 4);
$implode = implode(" ",$explode);
echo $implode;
$implot will give : hello world ! I
function getShortString($string,$wordCount,$etc = true)
{
$expString = explode(' ',$string);
$wordsInString = count($expString);
if($wordsInString >= $wordCount )
{
$shortText = '';
for($i=0; $i < $wordCount-1; $i++)
{
$shortText .= $expString[$i].' ';
}
return $etc ? $shortText.='...' : $shortText;
}
else return $string;
}
Simpler than all previously posted regex techniques, just match the first n sequences of non-word followed by sequences of word characters. Making the non-word characters optional allows matching of word characters from the start of the string. Greedy word character matching ensures that consecutive word characters are never treated as individual words.
By writing \K in the pattern after matching n substrings, then matching the rest of the string (add the s pattern modifier if you need dots to match newlines), the replacement can be an empty string.
Code: (Demo)
function firstNWords(string $string, int $limit = 3) {
return preg_replace("/(?:\W*\w+){{$limit}}\K.*/", '', $string);
}
Lets assume we have the string variables $string, $start, and $limit we can borrow 3 or 4 functions from PHP to achieve this. They are:
script_tags() PHP function to remove the unnecessary HTML and PHP
tags (if there are any). This wont be necessary, if there are no HTML or PHP tags.
explode() to split the $string into an array
array_splice() to specify the number of words and where it'll start
from. It'll be controlled by vallues assigned to our $start and $limit variables.
and finally, implode() to join the array elements into your truncated
string..
function truncateString($string, $start, $limit){
$stripped_string =strip_tags($string); // if there are HTML or PHP tags
$string_array =explode(' ',$stripped_string);
$truncated_array = array_splice($string_array,$start,$limit);
$truncated_string=implode(' ',$truncated_array);
return $truncated_string;
}
It's that simple..
I hope this was helpful.
I made my function:
function summery($text, $limit) {
$words=preg_split('/\s+/', $text);
$count=count(preg_split('/\s+/', $text));
if ($count > $limit) {
$text=NULL;
for($i=0;$i<$limit;$i++)
$text.=$words[$i].' ';
$text.='...';
}
return $text;
}
function limitText($string,$limit){
if(strlen($string) > $limit){
$string = substr($string, 0,$limit) . "...";
}
return $string;
}
this will return 20 words. I hope it will help
$text='some text';
$len=strlen($text);
$limit=500;
// char
if($len>$limit){
$text=substr($text,0,$limit);
$words=explode(" ", $text);
$wcount=count($words);
$ll=strlen($words[$wcount]);
$text=substr($text,0,($limit-$ll+1)).'...';
}
function wordLimit($str, $limit) {
$arr = explode(' ', $str);
if(count($arr) <= $limit){
return $str;
}
$result = '';
for($i = 0; $i < $limit; $i++){
$result .= $arr[$i].' ';
}
return trim($result);
}
echo wordLimit('Hello Word', 1); // Hello
echo wordLimit('Hello Word', 2); // Hello Word
echo wordLimit('Hello Word', 3); // Hello Word
echo wordLimit('Hello Word', 0); // ''
I would go with explode() , array_pop() and implode(), eg.:
$long_message = "I like summer, also I like winter and cats, btw dogs too!";
$trimmed_message = explode(" ", $long_message, 5); // <-- '5' means 4 words to be returned
array_pop($trimmed_message); //removing last element from exploded array
$trimmed_message = implode(" ", $trimmed_message) . '...';
Result:
I like summer, also...
what about
chunk_split($str,20);
Entry in the PHP Manual
function limit_word($start,$limit,$text){
$limit=$limit-1;
$stripped_string =strip_tags($text);
$string_array =explode(' ',$stripped_string);
if(count($string_array)>$limit){
$truncated_array = array_splice($string_array,$start,$limit);
$text=implode(' ',$truncated_array).'...';
return($text);
}
else{return($text);}
}

delete the repetetion letters in a string php

I'm trying to parse a string and delete the adjacent letters that are same. I want to return the count of number of deletions and output the resulted string after the deletions are made. Say I have
$str = "aaabbbcc";
As you can see, you need to do 5 deletions to make the adjacent letters not same. The $output string is "abc" and the number of deletions is five.
function str_deletions ($str)
{
$prev = $str[0];
$length = strlen($str);
$deletions = 0;
$output = "";
for ($i=1 ; $i < $length; $i++)
{
if ($str[$i]== $prev)
{
$deletions++;
$prev = $str[$i]; // not sure here ?
}
}
echo $output; // ?
return $deletions;
}
$str = "aabbcc";
echo str_deletions ($str);
EDIT
This is an interview question, I'm not supposed to use any built-in functions like regex or array_count_values
Thanks for your help !
Here is another regex solution. I use a regex to only match a word character that is repeated, and then remove each consecutive repeating character one by one, which allows me to use &$count argument with preg_replace:
count
If specified, this variable will be filled with the number of replacements done.
The regex is
(\w)(?=\1)
See demo. Note you can replace \w with . to match any character but a newline. OR if you need to match only letters, I suggest using '/(\p{L})(?=\1)/u'
See IDEONE demo:
$str = "aaabbbcc";
$cnt = -1;
$result = preg_replace('/(\w)(?=\1)/', "", $str, -1, $cnt);
echo "Result: " . $result . PHP_EOL . "Deletions: " . $cnt;
Output:
Result: abc
Deletions: 5
Regex solution
This is a much simpler way of doing what you're after using preg_replace():
<?php
function str_deletions($str){
$replaced = preg_replace("/(.)\\1+/", "", $str);
$length = strlen($str) - strlen($replaced);
return array("new_word" => $replaced, "chars_replaced" => $length);
}
$str = "aabbcc";
$string_deletions = str_deletions($str);
echo "New String: " . $string_deletions['new_word'] . "\n";
echo "Chars deleted: " . $string_deletions['chars_replaced'] . "\n";
?>
No inbuilt functions
For the purposes of completion (and since you updated your question with more information to say that we can't use regexes because it's an interview question), here's what I'd do:
Using count_chars():
function str_deletions($str){
$string_data['new_word'] = count_chars($str,3);
$string_data['chars_replaced'] = strlen($str) - strlen($string_data['new_word']);
return $string_data;
}
$str = "aabbcc";
echo str_deletions($str);
Note: in this example count_chars(); will return unique chars in a string, not quite remove duplicates (i.e. "aabbccaa" would still yield "abc" as an output) but your question wasn't clear what the interviewer wanted - whether it was truly a remove duplicate question or a unique char question.
Using array_unique():
Slightly slower and a bit more heavy handed:
function str_deletions($str){
$string_array = array_unique(str_split($str));
foreach($string_array as $string_cur){
$string_data['new_word'] .= $string_cur;
}
$string_data['chars_replaced'] = strlen($str) - strlen($string_data['new_word']);
return $string_data;
}
$str = "aabbcc";
echo str_deletions($str);
Note: It's worth pointing out that if I realised it was an interview question, I wouldn't have provided an answer as doing it for you kind of defeats the purpose. Still, with the amount of answers here now and the fact that I've seen something similar to this in an interview, my hope is someone will learn from these.
The basic algorithm (indeed $prev = $str[$i]; isn't at the good place but you wasn't far):
function str_deletion($str) {
$del = 0;
if (1 < $length = strlen($str)) { // $str has more than 1 char
$prev = $str[0];
$output = $prev;
for ($i=1; $i<$length; $i++) {
if ($prev == $str[$i]) {
$del++;
} else {
$prev = $str[$i]; // when different, change the previous character
$output .= $prev; // and append it to the output
}
}
} else {
$output = $str;
}
echo $output;
return $del;
}
I have changed your function
this is not returning both the output string and number of deletions
function str_deletions ($str)
{
$prev = NULL;
$deletions = 0;
$output = "";
$i=0;
while ($i < strlen($str))
{
if (substr($str,$i,1) == $prev)
{
$deletions++;
//$prev = substr($str,$i,1);/*remove this line, no need here as the same stmnt is there after ifelse*/
}else{
$output.=substr($str,$i,1);
}
$prev = substr($str,$i,1);
$i++;
}
$arr = array(
'output'=>$output,
'deletions'=>$deletions
);
return $arr;
}
$str = "aaabbcc";
print_r(str_deletions ($str));
output for above function call is
Array ( [output] => abc [deletions] => 4 )
Solved with no external function except count;
$str="aaavvvffccca";
$count = strlen($str);
for($i=0;$i<$count;$i++){
$array[]=$str[$i];
}
$del =0;
for($i=0;$i<$count;$i++){
$next=isset($array[$i+1])?$array[$i+1]:null;
if($array[$i]==$next)
{
$del++;
}
else
{
$newarray[]=$array[$i];
}
}
echo "Filter Text:". implode('',$newarray);
echo"Total Deleted:".$del;
The straight forward solution to find out the number of deletions can be
If there are N consecutive same characters delete N-1 out of those N characters.
function str_likes($str)
{
$length = strlen($str);
$del = 0;
for ($i=0 ; $i < $length ; $i++)
{
if ($str[$i] == $str[$i+1])
{
$del++;
}
}
return $del;
}
$str = "aabbccaaa";
echo str_likes($str); //4

Why do some characters lose when I use str_shuffle() in PHP?

This is the code in lib.php:
<?php
class table {
function __construct($string, $time) {
$out = '<table cellpadding="5">';
$out .= $this->getRow('th', 'Nom., Shuffled String, Lenght');
for ($x = 1; $x <= $time; $x++) {
$shuffledStr = str_shuffle($string); //Maybe this causes the problem
$shuffledStr_len = strlen($shuffledStr);
$out .= $this->getRow('td', $x . ', ' . $shuffledStr . ', ' . $shuffledStr_len);
}
$out .= '</table>';
echo $out;
}
public function getRow($tagName, $contents_list) {
//Variables:
$out = '';
$contents_array = explode(', ', $contents_list);
$contents_number = count($contents_array);
$start_tag = '<' . $tagName . '>';
$end_tag = '</' . $tagName . '>';
// Build
$out .= '<tr>';
for ($i = 0; $i < $contents_number; $i++) {
$out .= $start_tag . $contents_array[$i] . $end_tag;
}
$out .= '</tr>';
return $out;
}
}
?>
And here is index.php:
<?php
require_once 'lib.php';
$string = ''; //My string
$shuffleTimes = 100;
$table = new table($string, $shuffleTimes);
?>
This program gets the a string and the number that you wanna shuffle,
then create a table and returns the number, shuffled string and the length of the shuffle string in each row.
If I set the variable $string to 'Stack Overflow' for instance it'll work correctly (It shuffles this word 100 times randomly, returns all lengths 14 and the length of the ALL shuffled strings are really 14.)
But...
If I add some special character to the variable $string (for example Stack Overflow+_)(*&^%$#{}[]<>#!~./=-) it won't work correctly. That means it returns the lengths 37 But they doesn't have 37 characters!(For example it printed nothing and printed it's lenght 38.
I think it's a bit strange. :(
Why is that?! Which character causes that and how to fix it?
There are multiple issues with your code.
1. getRow() issue :
The problem is in getRow(), where you concat parameters into one string with ,, and then explode by ,. If your string has , inside it, then you will have problems, example: Stack ,test.
2. multibyte issue :
This code doesn't work for multibyte characters. To accomplish that you will need to change function str_shuffle() with function bellow mb_str_shuffle(), and strlen() with mb_strlen().
function mb_str_shuffle($str) {
$tmp = preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
shuffle($tmp);
return join("", $tmp);
}
Or some other unicode function that you find in comments on http://php.net/manual/en/function.str-shuffle.php
3. length is ok, but string is missing issue :
This is because you have HTML special chars in your string, like < and >. If string Stack Overflow+_)(*&^%$#{}[]<>#!~./=- is shuffled, and you get something like a#^&/c-_O. instead of a#^&/c-_O.< ~*>)$wevS+{(%}klr[]f=to!#. You should escape special chars with htmlspecialchars() when you output the string.
Sounds like a problem with Encoding.
Have you tried using a function, that handles encoding right?
try this: (copied from PHP Manual)
function unicode_shuffle($string, $chars, $format = 'UTF-8')
{
for($i=0; $i<$chars; $i++)
$rands[$i] = rand(0, mb_strlen($string, $format));
$s = NULL;
foreach($rands as $r)
$s.= mb_substr($string, $r, 1, $format);
return $s;
}

How to split a string based on position

I want to split a variable based on the position of characters. The resulting first string should have the previous position before specified position and the other string should contain the other portions.
Suppose if I have a variable $var = "2013AD"; I want
$var1 = 2013 and var2 = 'AD'.
How can I achieve this?
Uhm... Gonna go occam's razor here, but substr ?
$var1 = substr($var, 0, 4);
$var2 = substr($var, 4);
You can simply use sscanf
$var = "2013AD";
list($var1, $var2) = sscanf($var, "%4d%2s");
echo $var1, ":", $var2;
Output
2013:AD
And if you are working with date treat it as such :
$var = "2013AD";
$date = DateTime::createFromFormat("Y\A\D",$var);
echo $date->format("Y");
you can use the substr function
$var1 = substr($var, 0, 4);
$var2 = substr($var, 4);
<?php
function py_slice($input, $slice) {
$arg = explode(':', $slice);
$start = intval($arg[0]);
if ($start < 0) {
$start += strlen($input);
}
if (count($arg) === 1) {
return substr($input, $start, 1);
}
if (trim($arg[1]) === '') {
return substr($input, $start);
}
$end = intval($arg[1]);
if ($end < 0) {
$end += strlen($input);
}
return substr($input, $start, $end - $start);
}
print py_slice('abcdefg', '2') . "\n";
print py_slice('abcdefg', '2:4') . "\n";
print py_slice('abcdefg', '2:') . "\n";
print py_slice('abcdefg', ':4') . "\n";
print py_slice('abcdefg', ':-3') . "\n";
print py_slice('abcdefg', '-3:') . "\n";
?>
The output from the examples:
c
cd
cdefg
abcd
abcd
efg
You can also use preg_split() with \K to explode on a zero-width position in your string so that no characters are lost while splitting. \K tells the regex engine to forget the previously matched one-or-more digits. 2 acts to limit the number of elements in the output to a maximum of 2.
Code: (Demo)
$var = "2013AD";
[$year, $jesusStatus] = preg_split('~\d+\K~', $var, 2);
var_export($year);
echo "\n";
var_export($jesusStatus);
Output:
'2013'
'AD'

string to float and vice versa

how can i convert it into float and then increment it and then convert back to string.
if($set==$Data_Id)
{
$rel='1.1.1.2';
}
after increment it should be like 1.1.1.3.
Please any help.
so crazy, it may work
$rel='1.1.1.2';
echo substr($rel, 0, -1). (substr($rel,-1)+1); //1.1.1.3
the big question is what do you want to happen if the string ends in 9 ??
Here's a slightly different approach.
<?php
function increment_revision($version) {
return preg_replace_callback('~[0-9]+$~', function($match) {
return ++$match[0];
}, $version);
}
echo increment_revision('1.2.3.4'); //1.2.3.5
Anthony.
"1.1.1.2" is not a valid number. So you'll have to do something like this:
$rel = '1.1.1.2';
$relPlusOne = increment($rel);
function increment($number) {
$parts = explode('.', $number);
$parts[count($parts) - 1]++;
return implode('.', $parts);
}
If this is exactly the case you need to solve, you could do it with intval(), strval(), str_replace(), substr() and strlen().
$rel = '1.1.1.2'; // '1.1.1.2'
// replace dots with empty strings
$rel = str_replace('.', '', $rel); // '1112'
// get the integer value
$num = intval($rel); // 1112
// add 1
$num += 1; // 1113
// convert it back to a string
$str = strval($num); // '1113'
// initialize the return value
$ret = '';
// for each letter in $str
for ($i=0; $i<strlen($str); $i++) {
echo "Current ret: $ret<br>";
$ret .= $str[$i] . '.'; // append the current letter, then append a dot
}
$ret = substr($ret, 0, -1); // remove the last dot
echo "Incremented value: " . $ret;
This method will change 1.1.1.9 to 1.1.2.0, however. If that's what you want, then this will be fine.

Categories