Retain case when using str_ireplace? - php

I am building a search that will wrap the searched text with a <span> tag and I have this code working OK:
str_ireplace($q,'<span>'.$q.'</span>',$row[name]);
The problem is, if a user searches for Tom is will show Tom which is cool, but if they put in tom because of the str_ireplace it would show tom, does that make sense? The real issue is if someone entered tOm aRnFeLd although it would search OK, the aesthetics would actually show up on the page tOm aRnFeLd
How can I retain the capital letters and lower case 'ness of both strings? Is there a better way to wrap case insensitive text from a string?

use stristr to get the needle from the haystack, case insensitive
$keyword_caseRetained_all = stristr($excerpt, $keyword);
but that returns the needle and the rest of haystack too, so you have to use substr to only keep the needle portion. start at position 0, get up to the length of keyword
$keyword_caseRetained = substr($keyword_caseRetained_all, 0, strlen($keyword) );
now use that variable inside the str_ireplace function
$excerpt = str_ireplace($keyword, '<em>'.$keyword_caseRetained.'</em>', $excerpt);
once you know this, you can combine lines 1 and 2 in a nice rats nest to shorten your code.
or add this as a method to a string manipulation class.

Get phrase length strlen()
Find occurrence of phrase using stripos()
Insert into text <span> after text's N character (where N is result from point #2)
Insert into text </span> after text's N+M character (where N is result from point #2 and M is result from point #1)
Continue points 2-4 (Using third parameter of strpos() - offset)

Related

How to match all words but "stop" in a string by regex

another regex question. I use PHP, and have a string: fdjkaljfdlstopfjdslafdj. You see there is a stop in the middle. I just want to replace any other words excluding that stop. i try to use [^stop], but it also includes the s at the end of the string.
My Solution
Thanks everyone’s help here.
I also figure out a solution with pure RegEx method(I mean in my knowledge scoop to RegEx. PCRE verbs are too advanced for me). But it needs 2 steps. I don’t want to mix PHP method in, because sometimes the jobs are out of coding area, i.e. multi-renaming filenames in Total Commander.
Let’s see the string: xxxfooeoropwfoo,skfhlk;afoofsjre,jhgfs,vnhufoolsjunegpq. For example, I want to keep all foos in this string, and replace any other non-foo greedily into ---.
First, I need to find all the non-foo between each foo: (?<=foo).+?(?=foo).
The string will turn into xxxfoo---foo---foo---foolsjunegpq, just both sides non-foo words left now.
Then use [^-]+(?=foo)|(?<=foo)[^-]+.
This time: ---foo---foo---foo---foo---. All words but foo have been turned into ---.
i just dont want to include "stop"...
You can skip it by using PCRE verbs (*SKIP)(*F) try like this
stop(*SKIP)(*F)|.
Demo at regex101
or sequence: (stop)(*SKIP)(*F)|(?:(?!(?1)).)+
or for words: stop(*SKIP)(*F)|\w+
[^stop] doesn't means any text that is NOT stop. It just means any character that is not one of the 4 characters inside [...] which is in this case s,t,o,p.
Better to split on the text you don't want to match:
$s = 'fdjkaljfdlstopfjdslafdjstopfoobar';
php> $arr = preg_split('/stop/', $s);
php> print_r($arr);
Array
(
[0] => fdjkaljfdl
[1] => fjdslafdj
[2] => foobar
)
You can generalize this to any pattern:
(?<neg>stop)(*SKIP)(*FAIL)|(?s:.)+?(?=\Z|(?&neg))
Demo
Just put the pattern you don't want in the neg group.
This regex will try to do the following for any character position:
Match the pattern you don't want. If it matches, discard it with (*SKIP)(*FAIL) and restart another match at this position.
If the pattern you don't want doesn't match at a particular position, then match anything, until either:
You reach the end of the input string (\Z)
Or the pattern you don't want immediately follows the current matching position ((?&neg))
This approach is slower than manually tuning the expression, you could get better performance at the cost of repeating yourself, which avoids the recursion:
stop(*SKIP)(*FAIL)|(?s:.)+?(?=\Z|stop)
But of course, the best approach would be to use the features provided by your language: match the string you don't want, then use code to discard it and keep everything else.
In PHP, you can use the PREG_OFFSET_CAPTURE flag to tell the preg_match_all function to provide you the offsets of each match.

Truncate text to a desired end word

So I want to truncate a very long text but the problem is that I don't want x number of word or characters. I want the text truncated when it reaches a special string like ###end### or something similar e.g. I want to set where exactly it ends.
edit: I know how to check the existences of the string I wasn't sure how to make the truncation
Maybe something like:
$pos = strpos($mystring, "###end###");
$finalText = substr ( $mystring , 0 , $pos );
This can be done with a single call. My answer assumes that the targeted substring will exist in the string.
Code: (Demo)
$string='Here is a sample string.###end### I do not want to see any of this';
echo strstr($string,'###end###',true); // 3rd parameter 'true' will extract everything before
Output:
Here is a sample string.
If you are uncertain if the substring will exist (and if it doesn't, you want the fullstring) this is a reliable method:
Code: (Demo)
$string='Here is a sample string.###end### I do not want to see any of this';
echo explode('###end###',$string,2)[0]; // 3rd parameter 2 will limit the number of elements produced to two
Output:
Here is a sample string.

Search a String for Alpha Numeric Characters in a Pattern

I have a string that contains 5 words. In the string one of the words is a Ham Radio Call Sign and can be anyone of the thousands of call signs in the US. In order to extract the Call Sign from the string I need to utilize the below pattern. The Call Sign I need to extract can be in any of the 5 positions in the string. The number is never the first character and the number is never the last character. The string is actually put together from an Array since it is originally read from a text file.
$string = $word[1] $word[2] $word[3] etc....
So the search can be either done on the whole string or each piece of the array.
Patterns:
1 Number and 3 Letters Example: AB4C A4BC
1 Number and 4 Letters Example: A4BCD
1 Number and 5 Letters Example: AB4CDE
I have tried everything I can think of and search till I cant search no more. I am sure I am over thinking this.
A two-step regular expression like this would do it:
$str = "hello A4AB there BC5AD";
$signs = array();
preg_match_all('/[A-Z][A-Z\d]{1,3}[A-Z]/', $str, $possible_signs);
foreach($possible_signs[0] as $possible_sign)
if (preg_match('/^\D+\d\D+$/', $possible_sign))
array_push($signs, $possible_sign);
print_r($signs); //Array ([0] => A4AB [1] => BC5AD)
Explanation
This is a regular expression approach, using two patterns. I don't think it could be done with one and still satisfy the exact requirements of the matching rules.
The first pattern enforces the following requirements:
substring starts and ends with a capital letter
substring contains only other capital letters or numbers between the first and last letter
substring is, overall, not more than 6 characters long
What I can't do in that same pattern, for complex REGEX reasons I won't go into (unless someone knows a way and can correct me), is enforce that only one number is contained.
#jeroen's answer does enforce this in a single pattern, but in turn does not enforce the correct length of the substring. Either way, we need a second pattern.
So after grabbing the initial matches, we loop over the results. We then apply each to a second pattern that enforces simply that there is only one number in the substring.
If so, we green-light the substring and it's added to the $signs array.
Hope this helps.
It depends on what the other words can contain, but you could use a regular expression like:
#\b[a-z]+\d[a-z]+\b#i
^ case insensitive
^^ a word boundary
^^^^^^ One or more letters
^^ One number
You can make it more restrictive by using {1,3} instead of + for the letters so that you have a sequence of 1 to 3 letters.
The complete expression would be something like:
$success = preg_match('#\b[a-z]+\d[a-z]+\b#i', $input_string, $matches);
where $matches[0] will contain the matched value, see the manual.

Parsing plain text that contains custom conditionals

I presume this is a weird sort of thing that I'm looking for.
I have the following text string:
$string = "The compass is pointing <north|south|east|west> towards <London|Paris|Rome>";
Somehow I want to parse this to obtain any of the following outputs:
The compass is pointing north towards Paris
The compass is pointing south towards London
The compass is pointing east towards Rome
The compass is pointing east towards London
Etc.
For each set of < > in the text string I need to convert the contents into an array (using explode("|",$string)?), then run array_rand on that array to get the key for the option we will display, then just read the array and return that value.
The problem is, I have very next to no experience with text parsing, but I'd guess you'd use preg_replace in this type of problem.
I'd appreciate if anyone could help me get started.
You could use preg_replace_callback() to execute a function that chooses a random replacement.
$string = "The compass is pointing <north|south|east|west> towards <London|Paris|Rome>";
$callback = function ($match) {
$opts = explode('|', $match[1]);
return $opts[array_rand($opts)];
};
echo preg_replace_callback('/<(.+?)>/', $callback, $string);
working example
The pattern matches <, any stuff (.+), and >. The "lazy" quantifier ? makes the + stop when it finds the shortest match, rather than being "greedy" and looking for the longest possible match (which is default behavior). Without it, it would match all the way to the last >, which is too far.
The ( ) creates a subpattern, so while $match[0] would be what's matched by the entire pattern (including < >), $match[1] will only contain the subpattern (without < >).
The callback function is called each time a match is found, and it does exactly what you described -- explode() the list of options and return a random one. The return value then replaces the original match.

Rotation in PHP's regex

How can you match the following words by PHP, either by regex/globbing/...?
Examples
INNO, heppeh, isi, pekkep, dadad, mum
My attempt would be to make a regex which has 3 parts:
1st match match [a-zA-Z]*
[a-zA-Z]?
rotation of the 1st match // Problem here!
The part 3 is the problem, since I do not know how to rotate the match.
This suggests me that regex is not the best solution here, since it is too very inefficient for long words.
I think regex are a bad solution. I'd do something with the condition like: ($word == strrev($word)).
Regexs are not suitable for finding palindromes of an arbitrary length.
However, if you are trying to find all of the palindromes in a large set of text, you could use regex to find a list of things that might be palindromes, and then filter that list to find the words that actually are palindromes.
For example, you can use a regex to find all words such that the first X characters are the reverse of the last X characters (from some small fixed value of X, like 2 or 3), and then run a secondary filter against all the matches to see if the whole word is in fact a palindrome.
In PHP once you get the string you want to check (by regex or split or whatever) you can just:
if ($string == strrev($string)) // it's a palindrome!
i think this regexp can work
$re = '~([a-z])(.?|(?R))\1~';

Categories