php trim a string - php

I'm trying to build a function to trim a string is it's too long per my specifications.
Here's what I have:
function trim_me($s,$max)
{
if (strlen($s) > $max)
{
$s = substr($s, 0, $max - 3) . '...';
}
return $s;
}
The above will trim a string if it's longer than the $max and will add a continuation...
I want to expand that function to handle multiple words. Currently it does what it does, but if I have a string say: How are you today? which is 18 characters long. If I run trim_me($s,10) it will show as How are yo..., which is not aesthetically pleasing. How can I make it so it adds a ... after the whole word. Say if I run trim_me($s,10) I want it to display How are you... adding the continuation AFTER the word. Any ideas?
I pretty much don't want to add a continuation in the middle of a word. But if the string has only one word, then the continuation can break the word then only.

So, here's what you want:
<?php
// Original PHP code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
function myTruncate($string, $limit, $break=".", $pad="...") {
// is $break present between $limit and the end of the string?
if(false !== ($breakpoint = strpos($string, $break, $limit))) {
if($breakpoint < strlen($string) - 1) {
$string = substr($string, 0, $breakpoint) . $pad;
}
}
return $string;
}
?>
Also, you can read more at http://www.the-art-of-web.com/php/truncate/

function trim_me($s,$max) {
if( strlen($s) <= $max) return $s;
return substr($s,0,strrpos($s," ",$max-3))."...";
}
strrpos is the function that does the magic.

I've named the function str_trunc. You can specify strict being TRUE, in which case it will only allow a string of the maximum size and no more, otherwise it will search for the shortest string fitting in the word it was about to finish.
var_dump(str_trunc('How are you today?', 10)); // string(10) "How are..."
var_dump(str_trunc('How are you today? ', 10, FALSE)); // string(14) "How are you..."
// Returns a trunctated version of $str up to $max chars, excluding $trunc.
// $strict = FALSE will allow longer strings to fit the last word.
function str_trunc($str, $max, $strict = TRUE, $trunc = '...') {
if ( strlen($str) <= $max ) {
return $str;
} else {
if ($strict) {
return substr( $str, 0, strrposlimit($str, ' ', 0, $max + 1) ) . $trunc;
} else {
return substr( $str, 0, strpos($str, ' ', $max) ) . $trunc;
}
}
}
// Works like strrpos, but allows a limit
function strrposlimit($haystack, $needle, $offset = 0, $limit = NULL) {
if ($limit === NULL) {
return strrpos($haystack, $needle, $offset);
} else {
$search = substr($haystack, $offset, $limit);
return strrpos($search, $needle, 0);
}
}

It's actually somehow simple and I add this answer because the suggested duplicate does not match your needs (but it does give some pointers).
What you want is to cut a string a maximum length but preserve the last word. So you need to find out the position where to cut the string (and if it's actually necessary to cut it at all).
As getting the length (strlen) and cutting a string (substr) is not your problem (you already make use of it), the problem to solve is how to obtain the position of the last word that is within the limit.
This involves to analyze the string and find out about the offsets of each word. String processing can be done with regular expressions. While writing this, it reminds me on some actually more similar question where this has been already solved:
Extract a fixed number of chars from an array, just full words (with regex)
How to get first x chars from a string, without cutting off the last word? (with wordwrap)
It does exactly this: Obtaining the "full words" string by using a regular expression. The only difference is, that it removes the last word (instead of extending it). As you want to extend the last word instead, this needs a different regular expression pattern.
In a regular expression \b matches a word-boundary. That is before or after a word. You now want to pick at least $length characters until the next word boundary.
As this could contain spaces before the next word, you might want to trim the result to remove these spaces at the end.
You could extend your function like the following then with the regular expression pattern (preg_replace) and the trim:
/**
* Cut a string at length while preserving the last word.
*
* #param string $str
* #param int $length
* #param string $suffix (optional)
*/
function trim_word($str, $length, $suffix = '...')
{
$len = strlen($str);
if ($len < $length) return $str;
$pattern = sprintf('/^(.{%d,}?)\b.*$/', $length);
$str = preg_replace($pattern, '$1', $str);
$str = trim($str);
$str .= $suffix;
return $str;
}
Usage:
$str = 'How are you today?';
echo trim_word($str, 10); # How are you...
You can further on extend this by reducing the minimum length in the pattern by the length of the suffix (as it's somehow suggested in your question, however the results you gave in your question did not match with your code).
I hope this is helpful. Also please use the search function on this site, it's not perfect but many gems are hidden in existing questions for alternative approaches.

Related

remove part of string after substring

This may be a dupe, but I cannot seem to find a thread which matches this issue. I want to remove all chars from a string after a given sub-string - but the chars and the number of chars after the sub-string is unknown. Most solutions I have found seem to only work for removing the given sub-string itself or a fixed length after a given sub-string.
I have
$str = preg_replace('(.gif*)','.gif$',$str);
Which locates 'blahblah.gif?12345' ok, but I cannot seem to remove the chars after the sub-string '.gif'. I read that $ denotes EOS so I thought this would work, but apparently not. I also tried
'.gif$/'
and simply
'.gif'
It can be done without regex:
echo substr('blahblah.gif?12345', strpos('blahblah.gif?12345', '.gif') + 4);
// returns ?12345 this is the length of the substring ^
So the code is:
$str = 'original string';
$match = 'matching string';
$output = substr($str, strpos($str, $match) + strlen($match));
Ok, now I'm not sure if you want to keep the first or the second part of the string. Anyway, here's the code for keeping the first part:
echo substr('blahblah.gif?12345', 0, strpos('blahblah.gif?12345', '.gif') + 4);
// returns blahblah.gif ^ this is the key
And the full code:
$str = 'original string';
$match = 'matching string';
$output = substr($str, 0, strpos($str, $match) + strlen($match));
See the both examples work here: http://ideone.com/Ge30rY
Assuming (from OP's comment) that you are working with actual URLs as your source string, I believe that the best course of action here would be to use PHP's built-in functionality for working with and parsing URLs. You do this by using the parse_url() function:
(PHP 4, PHP 5)
parse_url — Parse a URL and return its components
This function parses a URL and returns an associative array containing any of the various components of the URL that are present.
This function is not meant to validate the given URL, it only breaks it up into the above listed parts. Partial URLs are also accepted, parse_url() tries its best to parse them correctly.
From your example: www.page.com/image.gif?123 (or even just image.gif?123) using parse_url() will look something like this:
var_dump( parse_url( "www.page.com/image.gif?123" ) );
array(2) {
["path"]=>
string(22) "www.page.com/image.gif"
["query"]=>
string(3) "123"
}
As you can see, without the need for regular expressions or string manipulations we have broken up the URL into it's separate components. No need to re-invent the wheel. Nice and clean :)
You could do this:
$str = "somecontent.gif?anddata";
$pattern = ".gif";
echo strstr($str,$pattern,true).$pattern;
// Set up string to search through
$haystack = "blahblah.gif?12345";
// Determine substring and length of it
$needle = ".gif";
$length = strlen($needle);
// Find position of last substring
$location = strrpos($haystack, $needle);
// Use location of last occurence + it's length to get new string
$newtext = substr($haystack, 0, $location+$length);

Extract substring from a certain indexposition of (huge) string

Let say I have a huge string where I want to extract e certain value belonging to a name, for example the stockprice of Apple.
Let say say the string look like this (in reality its html but that does not matter here)
$output = "nsdfsdnfsnfdnsdfnueruherdfndsdndnjsdnasdnn Apple dndfjnfjdf647tgtgtgeq";
I want to extract the value 647.
The real string is maybe some hundred thousand characters.
I can reveal the position of Apple by:
$str = "Apple";
$pos = strpos($output, $str);
let say the function returns 87310 which is the indexposition of the first letter in Apple.
Here comes my question? Is there an easy way to extract the value when I know the startposition of Apple? I have looked for such a function but can right now not find it.
I could solve this easily by just looping ahead of the name Apple and then extract the relevant characters? But it would at the least save keystrokes to use a function for this instead.
Thanks!!!
To just pull out the stock price, you would want to do something like this:
Search your string for "Apple" and save $position + 5 (length of Apple). Search directly after $position, one character at a time, for the first character that is_numeric and add that to a string, $stock_val. Continue adding all subsequent characters until you find one that !is_numeric. Here is my clunky code:
$position = strpos(strtolower($str), "apple") + strlen("apple");
$temp_str = substr($str, $position);
$stock_val = "";
do {
$char = substr($temp_str, 0, 1); //Take first char of $temp_str
$temp_str = substr($temp_str, 1); //Remove that char from $temp_str
$is_acceptable = (is_numeric($char) || $char == "." || $char == ",");
if($is_acceptable) { //If the char is_numeric, add it to $stock_val
$stock_val .= $char;
}
if(!$is_acceptable && $stock_val != "") {
break; //If the char is NOT numeric AND $stock_val
} //already has characters, break.
} while(strlen($temp_str) > 0); //Repeat while there are still characters
you know the start position so calculate the end position by doing strlen($str) then use substr to cut away the unwanted string
something like this using substr
$portion = substr(substr($string, 0, -(strlen($string) - $end)), $start);

PHP -- How do I extract a substring + X number of characters before it?

I asked a question yesterday that was superbly answered by several people (thank you).
New question :)
I want to extract a unique substring within a string, but also capture X number of characters before it. Is there any function that allows this?
I just found strrpos() -- this might do it.
I don't think there's a built in to do this, but this should do the trick:
function subbef($str, $sub, $bef)
{
$pos = strpos($str, $sub);
if ($pos === false || $pos < $bef) {
return false;
}
return substr($str, $pos - $bef, strlen($sub) + $bef);
}
Usage is like:
subbef('test string here', 'string', 3); //"st string"
you can also do this via regular expression:
<?php
function get($needle, $haystack, $before){
preg_match($v="/.{".$before."}$needle/", $haystack, $matches);
return $matches[0];
}
echo get("hello", "I just want to say hello bobby!", 3);

How to use str_replace() to remove text a certain number of times only in PHP?

I am trying to remove the word "John" a certain number of times from a string. I read on the php manual that str_replace excepts a 4th parameter called "count". So I figured that can be used to specify how many instances of the search should be removed. But that doesn't seem to be the case since the following:
$string = 'Hello John, how are you John. John are you happy with your life John?';
$numberOfInstances = 2;
echo str_replace('John', 'dude', $string, $numberOfInstances);
replaces all instances of the word "John" with "dude" instead of doing it just twice and leaving the other two Johns alone.
For my purposes it doesn't matter which order the replacement happens in, for example the first 2 instances can be replaced, or the last two or a combination, the order of the replacement doesn't matter.
So is there a way to use str_replace() in this way or is there another built in (non-regex) function that can achieve what I'm looking for?
As Artelius explains, the last parameter to str_replace() is set by the function. There's no parameter that allows you to limit the number of replacements.
Only preg_replace() features such a parameter:
echo preg_replace('/John/', 'dude', $string, $numberOfInstances);
That is as simple as it gets, and I suggest using it because its performance hit is way too tiny compared to the tedium of the following non-regex solution:
$len = strlen('John');
while ($numberOfInstances-- > 0 && ($pos = strpos($string, 'John')) !== false)
$string = substr_replace($string, 'dude', $pos, $len);
echo $string;
You can choose either solution though, both work as you intend.
You've misunderstood the wording of the manual.
If passed, this will be set to the number of replacements performed.
The parameter is passed by reference and its value is changed by the function to indicate how many times the string was found and replaced. Its initial value is discarded.
There are a few things you could do to achieve this, but I can't think of one specific php function that will easily let you do this.
One option is to create your own replace function and utilize strripos and substr to do the replaces.
Another thing you can do is use preg_replace_callback and count the number of replacements you have done in the callback.
There's probably more ways but that's all I can think of on the fly. If performance is an issue I suggest you give both a try and do some simple benchmarks.
The cleanest, most-direct, single function call is to use preg_replace(). Its replacement limiting parameter makes the task intuitive and readable.
$string = preg_replace('/John/', 'dude', $string, $numberOfInstances);
The function is also attractive because making the search case-insensitive is as simple as adding the i pattern modifier to the end of the pattern. I won't delve into the usefulness of word boundaries (\b).
If a search string might contain characters with special meaning to the regex engine, then preg_quote() will be necessary -- this diminishes the beauty of the technique but not prohibitively so.
$search = '$5.99';
$pattern = '/' . preg_quote($search, '/') . '/';
$string = preg_replace($pattern, 'free', $string, $numberOfInstances);
For anyone who has an unnatural bias against regex functions, this can be done without regex and without looping -- it will be case-sensitive though.
Limited Explode & Implode: (Demo)
$numberOfInstances = 2;
$string = 'Hello John, how are you John. John are you happy with your life John?';
// explode here -^^^^ and ---------^^^^ only to create the following array:
// 0 => 'Hello ',
// 1 => ', how are you ',
// 2 => '. John are you happy with your life John?'
echo implode('dude', explode('John', $string, $numberOfInstances + 1));
Output:
Hello dude, how are you dude. John are you happy with your life John?
Notice the explode's limiting parameter dictates how many elements are generated, not how many explosions are executed on the string.
function str_replace_occurrences($find, $replace, $string, $count = -1) {
// current occrurence
$current = 0;
// while any occurrence
while (($pos = strpos($string, $find)) != false) {
// update length of str (size of string is changing)
$len = strlen($find);
// found next one
$current++;
// check if we've reached our target
// -1 is used to replace all occurrence
if($current <= $count || $count == -1) {
// do replacement
$string = substr_replace($string, $replace, $pos, $len);
} else {
// we've reached our
break;
}
}
return $string;
}
Artelius has already described how the function works, ill just show you how to do this via the manual methods:
function str_replace_occurrences($find,$replace,$string,$count = 0)
{
if($count == 0)
{
return str_replace($find,$replace,$string);
}
$pos = 0;
$len = strlen($find);
while($pos < $count && false !== ($pos = strpos($string,$find,$pos)))
{
$string = substr_replace($string,$replace,$pos,$len);
}
return $string;
}
This is untested but should work.

Finding string and replacing with same case string

I need help while trying to spin articles. I want to find text and replace synonymous text while keeping the case the same.
For example, I have a dictionary like:
hello|hi|howdy|howd'y
I need to find all hello and replace with any one of hi, howdy, or howd'y.
Assume I have a sentence:
Hello, guys! Shouldn't you say hello me when I say you HELLO?
After my operation it will be something like:
hi, guys! Shouldn't you say howd'y to me when I say howdy?
Here, I lost the case. I want to maintain it! It should actually be:
Hi, guys! Shouldn't you say howd'y to me when I say HOWDY?
My dictionary size is about 5000 lines
hello|hi|howdy|howd'y go|come
salaries|earnings|wages
shouldn't|should not
...
I'd suggest using preg_replace_callback with a callback function that examines the matched word to see if (a) the first letter is not capitalized, or (b) the first letter is the only capitalized letter, or (c) the first letter is not the only capitalized letter, and then replace with the properly modified replacement word as desired.
You can find your string and do two tests:
$outputString = 'hi';
if ( $foundString == ucfirst($foundString) ) {
$outputString = ucfirst($outputString);
} else if ( $foundString == strtoupper($foundString) ) {
$outputString = strtoupper($outputString);
} else {
// do not modify string's case
}
Here's a solution for retaining the case (upper, lower or capitalized):
// Assumes $replace is already lowercase
function convertCase($find, $replace) {
if (ctype_upper($find) === true)
return strtoupper($replace);
else if (ctype_upper($find[0]) === true)
return ucfirst($replace);
else
return $replace;
}
$find = 'hello';
$replace = 'hi';
// Find the word in all cases that it occurs in
while (($pos = stripos($input, $find)) !== false) {
// Extract the word in its current case
$found = substr($input, $pos, strlen($find));
// Replace all occurrences of this case
$input = str_replace($found, convertCase($found, $replace), $input);
}
You could try the following function. Be aware that it will only work with ASCII strings, as it uses some of the useful properties of ASCII upper and lower case letters. However, it should be extremely fast:
function preserve_case($old, $new) {
$mask = strtoupper($old) ^ $old;
return strtoupper($new) | $mask .
str_repeat(substr($mask, -1), strlen($new) - strlen($old) );
}
echo preserve_case('Upper', 'lowercase');
// Lowercase
echo preserve_case('HELLO', 'howdy');
// HOWDY
echo preserve_case('lower case', 'UPPER CASE');
// upper case
echo preserve_case('HELLO', "howd'y");
// HOWD'Y
This is my PHP version of the clever little perl function:
How do I substitute case insensitively on the LHS while preserving case on the RHS?

Categories