let's say I want to return all chars after some needle char 'x' from:
$source_str = "Tuex helo babe".
Normally I would do this:
if( ($x_pos = strpos($source_str, 'x')) !== FALSE )
$source_str = substr($source_str, $x_pos + 1);
Do you know a better/smarter (more elegant way) to do this?
Without using regexp that would not make it more elegant and probably also slower.
Unfortunately we can not do:
$source_str = substr(source_str, strpos(source_str, 'x') + 1);
Because when 'x' is not found strpos returns FALSE (and not -1 like in JS).
FALSE would evaluate to zero, and 1st char would be always cut off.
Thanks,
Your first approach is fine: Check whether x is contained with strpos and if so get anything after it with substr.
But you could also use strstr:
strstr($str, 'x')
But as this returns the substring beginning with x, use substr to get the part after x:
if (($tmp = strstr($str, 'x')) !== false) {
$str = substr($tmp, 1);
}
But this is far more complicated. So use your strpos approach instead.
Regexes would make it a lot more elegant:
// helo babe
echo preg_replace('~.*?x~', '', $str);
// Tuex helo babe
echo preg_replace('~.*?y~', '', $str);
But you can always try this:
// helo babe
echo str_replace(substr($str, 0, strpos($str, 'x')) . 'x', '', $str);
// Tuex helo babe
echo str_replace(substr($str, 0, strpos($str, 'y')) . 'y', '', $str);
if(strpos($source_str, 'x') !== FALSE )
$source_str = strstr($source_str, 'x');
Less elegant, but without x in the beginning:
if(strpos($source_str, 'x') !== FALSE )
$source_str = substr(strstr($source_str, 'x'),1);
I needed just this, and striving to keep it on one line for fun came up with this:
ltrim(strstr($source_str, $needle = "x") ?: $source_str, $needle);
The ternary operator was adapted in 5.3 to allow this to work.
Since PHP 5.3, it is possible to leave out the middle part of the ternary operator. Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.
NB. ltrim will trim multiple matching characters at the start of the string.
Append a '-' at the end of $item so it always returns string before '-' even $item doesn't contain '-', because strpos by default returns the position of first occurrence of '-'.
substr($item,0,strpos($item.'-','-'))
Related
Can you think of any regular expression that resolves these similarities in PHP? The idea is to get a match without considering the last letters.
<?php
$word1 = 'happyness';
$word2 = 'happys';
if (substr($word1, 0, -4) == substr($word2, 0, -1))
{
echo 'same word1';
}
$word1 = 'kisses';
$word2 = 'kiss';
if (substr($word1, 0, -2) == $word2)
{
echo 'same word2';
}
$word1 = 'consonant';
$word2 = 'consonan';
if (substr($word1, 0, -1) == $word2)
{
echo 'same word3';
}
By putting the words together like happys happyness and capturing as many word characters from word 1 as word 2 matches. See this demo at regex101. Use it with the i flag for casless matching.
^(\w+)\w* \1
To use this in PHP with preg_match see this PHP demo at tio.run
preg_match('/^(\w+)\w* \1/i', preg_quote($word1,'/')." ".preg_quote($word2,'/'), $out);
where $out[1] holds the captures or $out would be an empty array if there wasn't a match.
You could use a small helper function, the first function just matches up to the length of the second string, so doesn't care how many characters it truncates. The main code works similar to your code except it uses the length of the second value as the length of the substring to take...
function match( string $a, string $b ) {
return substr($a, 0, strlen($b)) === $b;
}
This function is slightly more complicated as it takes into account a maximum gap length...
function match( string $a, string $b, int $length = 3 ) {
$len = max(strlen($a)-$length, strlen($b));
return substr($a, 0, $len) === $b;
}
So call it something along the lines of
$word1 = 'happyness';
$word2 = 'happys';
if (match($word1,$word2))
{
echo 'same word1';
}
You can use preg_match to match these data with regex as /^word2/ against word1. So regex would check if word1 starts with word2 or not, because of ^ symbol at the start.
It's always better to preg_quote() before matching to escape regex meta characters for accurate results.
<?php
$tests = [
[
'happyness',
'happys'
],
[
'kisses',
'kiss'
],
[
'consonant',
'consonan'
]
];
$filtered = array_filter($tests,function($values){
$values[1] = preg_quote($values[1]);
return preg_match("/^$values[1]/",$values[0]) === 1;
});
print_r($filtered);
Demo: https://3v4l.org/SLf15
You could also do a small function to find the similarity between the given 2 words. It could look like:
function similarity($word1, $word2)
{
$splittedWord1 = str_split($word1);
$splittedWord2 = str_split($word2);
$similarChars = array_intersect_assoc($splittedWord1, $splittedWord2);
return count($similarChars) / max(count($splittedWord1), count($splittedWord2));
}
var_dump(similarity('happyness', 'happys'));
var_dump(similarity('happyness', 'testhappys'));
var_dump(similarity('kisses', 'kiss'));
var_dump(similarity('consonant', 'consonan'));
The result would look like:
float(0.55555555555556)
int(0)
float(0.66666666666667)
float(0.88888888888889)
Based on the resulted percentage you could decide if the given words should be considered the same or not.
I'm not sure regex is the answer here.
You could try similar_text(), which returns the number of similar characters (and optionally sets a percentage value to a variable). Maybe if you consider the last two letters as non-important, you can see if the strlen() - $skippedCharacters is the same as what is matched. For example:
$skippedCharacters = 2;
$word1 = 'kisses';
$word2 = 'kiss';
$match = similar_text($word1, $word2);
if ($match + $skippedCharacters >= strlen($word1))
{
echo 'same word2';
}
You could use the PHP levenshtein function.
The levenshtein() function returns the Levenshtein distance between two strings. The Levenshtein distance is the number of characters you have to replace, insert or delete to transform string1 into string2.
$lev = levenshtein($word1, $word2);
The lower the number the bigger the similarity.
I get a string that contains "#string.number (other stuff)".
I want to filter input from start+1 (= ignore the #) until I get something different than alphanumeric or '-', '_', '.'.
Here's my function:
function _isCharAllowed($c)
{
return (ctype_alnum(str_replace(array('-', '_', '.'), '', $c)));
}
$f=1;
while ($this->_isCharAllowed(mb_substr($str, $f, 1)))
$f++;
$key=mb_substr($str, 1, $f-2);
I want two things. First I have a problem with strings containing '-', '_', '.' because it doesn't do want I want: when there's such string, it removes those chars, giving empty string to ctype_alnum() which returns false:
php -r 'echo var_export((ctype_alnum("")), true)."\n";'
And I would like to optimize it.
How would you do?
You can replace them to an allowed character, say a. That way the string will never be empty.
Sidenote: I'm horrified (but not surprised) to hear that ctype_alnum("") returns false. It totally contradicts what the manual says... and the behaviour is even different in some versions: http://3v4l.org/IEtdi
Why not use preg_replace
Example:
$pattern = '/[^a-z0-9\-\_\.]/';
$strs = [
'some_string-with234.a',
'ano^ther-st*ring-with´+º~º'
];
foreach ($strs as $str) {
echo preg_replace($pattern, '', $str) . PHP_EOL;
}
I want to check the first word of some sentences. If the first word are For, And, Nor, But, Or, etc, I want to skip the sentence.
Here's the code :
<?php
$sentence = 'For me more';
$arr = explode(' ',trim($sentence));
if(stripos($arr[0],'for') or stripos($arr[0],'but') or stripos($arr[0],'it')){
//doing something
}
?>
Blank result, Whats wrong ? thank you :)
Here, stripos will return 0 if the word is found (found at position 0).
It returns false if the word is not found.
You should write :
if(stripos($arr[0],'for') !== false or stripos($arr[0],'but') !== false or stripos($arr[0],'it') !== false){
//skip
}
Stripos returns the position on the first occurrence of the needle in the haystack
The first occurrence is at position 0, which evaluates to false.
Try this as an alternative
$sentence = 'For me more';
// make all words lowercase
$arr = explode(' ', strtolower(trim($sentence)));
if(in_array($arr[0], array('for', 'but', 'it'))) {
//doing something
echo "found: $sentence";
} else {
echo 'failed';
}
Perhaps use preg_filter if you are going to know what the string to be evaluated is (i.e. you don't need to parse out sentences).
$filter_array = array(
'/^for\s/i',
'/^and\s/i',
'/^nor\s/i',
// etc.
}
$sentence = 'For me more';
$result = preg_filter(trim($sentence), '', $filter_array);
if ($result === null) {
// this sentence did not match the filters
}
This allows you to determine a set of filter regex patterns to see if you have a match. Note that in this case I just used '' as "replacement" value, as you don't really care about actually making a replacement, this function just gives you a nice way to pas in an array of regular expressions.
I've got a string and I'd like to get everything after a certain value. The string always starts off with a set of numbers and then an underscore. I'd like to get the rest of the string after the underscore. So for example if I have the following strings and what I'd like returned:
"123_String" -> "String"
"233718_This_is_a_string" -> "This_is_a_string"
"83_Another Example" -> "Another Example"
How can I go about doing something like this?
The strpos() finds the offset of the underscore, then substr grabs everything from that index plus 1, onwards.
$data = "123_String";
$whatIWant = substr($data, strpos($data, "_") + 1);
echo $whatIWant;
If you also want to check if the underscore character (_) exists in your string before trying to get it, you can use the following:
if (($pos = strpos($data, "_")) !== FALSE) {
$whatIWant = substr($data, $pos+1);
}
strtok is an overlooked function for this sort of thing. It is meant to be quite fast.
$s = '233718_This_is_a_string';
$firstPart = strtok( $s, '_' );
$allTheRest = strtok( '' );
Empty string like this will force the rest of the string to be returned.
NB if there was nothing at all after the '_' you would get a FALSE value for $allTheRest which, as stated in the documentation, must be tested with ===, to distinguish from other falsy values.
Here is the method by using explode:
$text = explode('_', '233718_This_is_a_string', 2)[1]; // Returns This_is_a_string
or:
$text = end((explode('_', '233718_This_is_a_string', 2)));
By specifying 2 for the limit parameter in explode(), it returns array with 2 maximum elements separated by the string delimiter. Returning 2nd element ([1]), will give the rest of string.
Here is another one-liner by using strpos (as suggested by #flu):
$needle = '233718_This_is_a_string';
$text = substr($needle, (strpos($needle, '_') ?: -1) + 1); // Returns This_is_a_string
I use strrchr(). For instance to find the extension of a file I use this function:
$string = 'filename.jpg';
$extension = strrchr( $string, '.'); //returns "jpg"
Another simple way, using strchr() or strstr():
$str = '233718_This_is_a_string';
echo ltrim(strstr($str, '_'), '_'); // This_is_a_string
In your case maybe ltrim() alone will suffice:
echo ltrim($str, '0..9_'); // This_is_a_string
But only if the right part of the string (after _) does not start with numbers, otherwise it will also be trimmed.
if anyone needs to extract the first part of the string then can try,
Query:
$s = "This_is_a_string_233718";
$text = $s."_".substr($s, 0, strrpos($s, "_"));
Output:
This_is_a_string
$string = "233718_This_is_a_string";
$withCharacter = strstr($string, '_'); // "_This_is_a_string"
echo substr($withCharacter, 1); // "This_is_a_string"
In a single statement it would be.
echo substr(strstr("233718_This_is_a_string", '_'), 1); // "This_is_a_string"
If you want to get everything after certain characters and if those characters are located at the beginning of the string, you can use an easier solution like this:
$value = substr( '123_String', strlen( '123_' ) );
echo $value; // String
Use this line to return the string after the symbol or return the original string if the character does not occur:
$newString = substr($string, (strrpos($string, '_') ?: -1) +1);
I am trying to extract a substring. I need some help with doing it in PHP.
Here are some sample strings I am working with and the results I need:
home/cat1/subcat2 => home
test/cat2 => test
startpage => startpage
I want to get the string till the first /, but if no / is present, get the whole string.
I tried,
substr($mystring, 0, strpos($mystring, '/'))
I think it says - get the position of / and then get the substring from position 0 to that position.
I don't know how to handle the case where there is no /, without making the statement too big.
Is there a way to handle that case also without making the PHP statement too complex?
The most efficient solution is the strtok function:
strtok($mystring, '/')
NOTE: In case of more than one character to split with the results may not meet your expectations e.g. strtok("somethingtosplit", "to") returns s because it is splitting by any single character from the second argument (in this case o is used).
#friek108 thanks for pointing that out in your comment.
For example:
$mystring = 'home/cat1/subcat2/';
$first = strtok($mystring, '/');
echo $first; // home
and
$mystring = 'home';
$first = strtok($mystring, '/');
echo $first; // home
Use explode()
$arr = explode("/", $string, 2);
$first = $arr[0];
In this case, I'm using the limit parameter to explode so that php won't scan the string any more than what's needed.
$first = explode("/", $string)[0];
What about this :
substr($mystring.'/', 0, strpos($mystring, '/'))
Simply add a '/' to the end of mystring so you can be sure there is at least one ;)
Late is better than never. php has a predefined function for that. here is that good way.
strstr
if you want to get the part before match just set before_needle (3rd parameter) to true
http://php.net/manual/en/function.strstr.php
function not_strtok($string, $delimiter)
{
$buffer = strstr($string, $delimiter, true);
if (false === $buffer) {
return $string;
}
return $buffer;
}
var_dump(
not_strtok('st/art/page', '/')
);
One-line version of the accepted answer:
$out=explode("/", $mystring, 2)[0];
Should work in php 5.4+
This is probably the shortest example that came to my mind:
list($first) = explode("/", $mystring);
1) list() will automatically assign string until "/" if delimiter is found
2) if delimiter "/"is not found then the whole string will be assigned
...and if you get really obsessed with performance, you may add extra parameter to explode explode("/", $mystring, 2) which limits maximum of the returned elements.
The function strstr() in PHP 5.3 should do this job.. The third parameter however should be set to true..
But if you're not using 5.3, then the function below should work accurately:
function strbstr( $str, $char, $start=0 ){
if ( isset($str[ $start ]) && $str[$start]!=$char ){
return $str[$start].strbstr( $str, $char, $start+1 );
}
}
I haven't tested it though, but this should work just fine.. And it's pretty fast as well
You can try using a regex like this:
$s = preg_replace('|/.*$|', '', $s);
sometimes, regex are slower though, so if performance is an issue, make sure to benchmark this properly and use an other alternative with substrings if it's more suitable for you.
Using current on explode would ease the process.
$str = current(explode("/", $str, 2));
You could create a helper function to take care of that:
/**
* Return string before needle if it exists.
*
* #param string $str
* #param mixed $needle
* #return string
*/
function str_before($str, $needle)
{
$pos = strpos($str, $needle);
return ($pos !== false) ? substr($str, 0, $pos) : $str;
}
Here's a use case:
$sing = 'My name is Luka. I live on the second floor.';
echo str_before($sing, '.'); // My name is Luka
$arr = explode("/", $string, 2); $first = $arr[0];
This Way is better and more accurate than strtok
because if you wanna get the values before # for example
while the there's no string before # it will give you whats after the sign .
but explode doesnt
$string="kalion/home/public_html";
$newstring=( stristr($string,"/")==FALSE ) ? $string : substr($string,0,stripos($string,"/"));
why not use:
function getwhatiwant($s)
{
$delimiter='/';
$x=strstr($s,$delimiter,true);
return ($x?$x:$s);
}
OR:
function getwhatiwant($s)
{
$delimiter='/';
$t=explode($delimiter, $s);
return ($t[1]?$t[0]:$s);
}