This is an example of a string: abcde123#ijklmn0pq
In that string I need to print out only the numbers (the 123 sequence), and remove the letters (from both left and right) and the hashtag (#) to be removed as well.
The hashtag (#) is always included in the string.
The hashtag (#) is always positioned to the right of the characters that need to be printed;
The hashtag (#) is always positioned to the left of the characters that need to be removed;
Therefore, the hashtag (#) can be used as a guide to remove the letters from the Right
The number of characters in the beginning is always equal to 5 (constant) (to be removed);
The number of characters in the middle is always different (variable) (to be printed);
The number of characters in the right is always different (variable) (to be removed);
Here's another string example, similar to the first one: !!##$IMPORTANT#=-=whatever
The characters that need to be printed are the word "IMPORTANT"
As with the first example, what's on the left side of the hashtag (#) needs to be printed, but it's important to print only the "IMPORTANT" word, without the special characters "!!##$".
$myString = '!!##$IMPORTANT#=-=whatever';
$result = substr($myString, 5, -1);
$pos = strpos($result, '#');
$result = substr($result, 0, $pos);
echo $result;
You can use regexes with preg_replace();
Assuming that the string you need to process is stored in $string:
preg_replace('^.{5}(.*)#.*$', '$1', $string);
https://www.regex101.com/r/hA8lY7/1
First pattern explanation:
^.{5}: matches any 5 character after the start of $string
(.*): matches any N character after (1) before the first occurence of # (first capturing-group)
#.*$: matches # and any N character after (2) before the end of $string
Second pattern explanation:
$1: replaces $string with the first capturing-group matched in the first pattern
Ill give a stab at this. seems pretty simple.
function choppy($choppy) {
$nstr = substr($choppy, 5,strlen($choppy)); //chop first 5
$pos = strpos($nstr, "#"); //Find the position of the hash tag
return substr($nstr, 0, $pos); //we only need the stuff before it...
}
echo choppy('!!##$IMPORTANT#=-=whatever');
echo "\n";
echo choppy('abcde123#ijklmn0pq');
Result
C:\Users\developer\Desktop>php test.php
IMPORTANT
123
The other answers are good but if you need a one-liner for your homework:
$str = '!!##$IMPORTANT#=-=whatever';
echo substr($str, 5, strpos($str, '#')-5); //IMPORTANT
Related
I am newbie in PHP. I want to replace certain characters in a string. My code is in below:
$str="this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$find = [
'\'',
'"'
];
$replace = [
['^', '*']
['#', '#']
];
$result = null;
$odd = true;
for ($i=0; $i < strlen($str); $i++) {
if (in_array($str[$i], $find)) {
$key = array_search($str[$i], $find);
$result .= $odd ? $replace[$key][0] : $replace[$key][1];
$odd = !$odd;
} else {
$result .= $str[$i];
}
}
echo $result;
the output of the above code is:
this ^is* a new ^string and i wanna* replace #in# #it here#.
but I want the output to be:
this ^is* a new 'string and i wanna' replace #in# "it here".
That means character will replace for both quotation(left quotation and right quotation- condition is for ' and "). for single quotation, string will not be replaced either if have left or right quotation. it will be replaced for left and right quotation.
Ok, I don't know what all that code is trying to accomplish.
But anyway here is my go at it
$str = "this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$str = preg_replace(["/'([^']+)'/",'/"([^"]+)"/'], ["^$1*", "#$1#"], $str, 1);
print_r($str);
You can test it here
Ouptput
this ^is* a new 'string and i wanna' replace #in# "it here"
Using preg_replace and a fairly simple Regular expression, we can replace the quotes. Now the trick here is the fourth parameter of preg_replace is $count And is defined as this:
count If specified, this variable will be filled with the number of replacements done.
Therefore, setting this to 1 limits it to the first match only. In other words it will do $count replacements, or 1 in this case. Now because it's an array of patterns, each pattern is treated separately. So each one is basically treated as a separate operation, and thus each is allowed $count matches, or each get 1 match/replacement.
Now rather or not this fits every use case you have I cannot say, but it's the most straight forward way to do it for the example you provided.
As for the match itself /'([^']+)'/
/ opening and closing "delimiters" for the Expression (its a required thing, although it doesn't have to be /)
' literal match, matches ' one time (the opening quote)
( ... ) capture group (group1) so we can use it in the replacement, as $1
[^']+ character set with a [^ not modifier, match anything not in the set, so anything that is not a ' one or more times, greedy
' literal match, matches ' one time (the ending quote)
The replacement "^$1*"
^ literal, adds this char in
$1 use the contents of the capture group (group1)
* literal, adds the char in
Hope that helps understand how it works.
UPDATE
Ok I think I finally deciphered what you want:
string will be replaced for if any word have left and right quotation. example..'word'..here string will be changed..but 'word...in this case not change or word' also not be changed.
This seems like you are trying to say only "whole" words with no spaces.
So in that case we have to adjust our regular expression like this:
$str = preg_replace(["/'([-\w]+)'/",'/"([-\w]+)"/'], ["^$1*", "#$1#"], $str);
So we removed the limit $count and we changed what is in the character group to be more strict:
[-\w]+ the \w means the working set, or in other words a-zA-Z0-9_ then the - is a literal (it has to/should go first in this case)
What we are saying with this is to match only strings that start and end with a quote(single|double) and only if the string within them match the working set plus the hyphen. This does not include the space. This way in the first case, your example, it produces the same result, but if you were to flip it to
//[ORIGINAL] this 'is' a new 'string and i wanna' replace \"in\" \"it here\"
this a new 'string and i wanna' replace 'is' \"it here\" \"in\"
You would get his output
this a new 'string and i wanna' replace ^is* \"it here\" #in#
Before this change you would have gotten
this a new ^string and i wanna* replace 'is' #it here# "in"
In other words it would have only replaced the first occurrence, now it will replace anything between the quotes if and only if it's a whole word.
As a final note you can be even more strict if you only want alpha characters by changing the character set to this [a-zA-Z]+, then it will match only a to z, upper or lower case. Whereas the example above will match 0 to 9 (or any combination of them) the - hyphen, the _ underline and the previously mentioned alpha sets.
Hope that is what you need.
For example, if I want to get rid of the repeating numeric suffix from the end of an expression like this:
some_text_here_1
Or like this:
some_text_here_1_5
and I want finally receive something like this:
some_text_here
What's the best and flexible solution?
$newString = preg_replace("/_?\d+$/","",$oldString);
It is using regex to match an optional underscore (_?) followed by one or more digits (\d+), but only if they are the last characters in the string ($) and replacing them with the empty string.
To capture unlimited _ numbers, just wrap the whole regex (except the $) in a capture group and put a + after it:
$newString = preg_replace("/(_?\d+)+$/","",$oldString);
If you only want to remove a numberic suffix if it is after an underscore (e.g. you want some_text_here14 to not be changed, but some_text_here_14 to be changed), then it should be:
$newString = preg_replace("/(_\d+)+$/","",$oldString);
Updated to fix more than one suffix
Strrpos is far better than regex on such a simple string problem.
$str = "some_text_here_13_15";
While(is_numeric(substr($str, strrpos($str, "_")+1))){
$str = substr($str,0 , strrpos($str, "_"));
}
Echo $str;
Strrpos finds the last "_" in str and if it's numeric remove it.
https://3v4l.org/OTdb9
Just to give you an idea of what I mean with regex not being a good solution on this here is the performance.
Regex:
https://3v4l.org/Tu8o2/perf#output
0.027 seconds for 100 runs.
My code with added numeric check:
https://3v4l.org/dkAqA/perf#output
0.003 seconds for 100 runs.
This new code performs even better than before oddly enough, regex is very slow. Trust me on that
You be the judge on what is best.
First you'll want to do a preg_replace() in order to remove all digits by using the regex /\d+/. Then you'll also want to trim any underscores from the right using rtrim(), providing _ as the second parameter.
I've combined the two in the following example:
$string = "some_text_here_1";
echo rtrim(preg_replace('/\d+/', '', $string), '_'); // some_text_here
I've also created an example of this at 3v4l here.
Hope this helps! :)
$reg = '#_\d+$#';
$replace = '';
echo preg_replace($reg, $replace, $string);
This would do
abc_def_ghi_123 > abc_def_ghi
abc_def_1 > abc_def
abc_def_ghi > abc_def_ghi
abd_def_ > abc_def_
abc_123_def > abd_123_def
in case of abd_def_123_345 > abc_def
one could change the line
$reg = '#(?:_\d+)+$#';
Considering this input string:
"this is a Test String to get the last index of word with an uppercase letter in PHP"
How can I get the position of the last uppercase letter (in this example the position of the first "P" (not the last one "P") of "PHP" word?
I think this regex works. Give it a try.
https://regex101.com/r/KkJeho/1
$pattern = "/.*\s([A-Z])/";
//$pattern = "/.*\s([A-Z])[A-Z]+/"; pattern to match only all caps word
Edit to solve what Wiktor wrote in comments I think you could str_replace all new lines with space as the input string in the regex.
That should make the regex treat it as a single line regex and still give the correct output.
Not tested though.
To find the position of the letter/word:
$str = "this is a Test String to get the last index of word with an uppercase letter in PHP";
$pattern = "/.*\s([A-Z])(\w+)/";
//$pattern = "/.*\s([A-Z])([A-Z]+)/"; pattern to match only all caps word
preg_match($pattern, $str, $match);
$letter = $match[1];
$word = $match[1] . $match[2];
$position = strrpos($str, $match[1].$match[2]);
echo "Letter to find: " . $letter . "\nWord to find: " . $word . "\nPosition of letter: " . $position;
https://3v4l.org/sJilv
If you also want to consider a non-regex version: You can try splitting the string at the whitespace character, iterating the resulting string array backwards and checking if the current string's first character is an upper case character, something like this (you may want to add index/null checks):
<?php
$str = "this is a Test String to get the last index of word with an uppercase letter in PHP";
$explodeStr = explode(" ",$str);
$i = count($explodeStr) - 1;
$characterCount=0;
while($i >= 0) {
$firstChar = $explodeStr[$i][0];
if($firstChar == strtoupper($firstChar)){
echo $explodeStr[$i]. ' at index: ';
$idx = strlen($str)-strlen($explodeStr[$i] -$characterCount);
echo $idx;
break;
}
$characterCount += strlen($explodeStr[i]) +1; //+1 for whitespace
$i--;
}
This prints 80 which is indeed the index of the first P in PHP (including whitespaces).
Andreas' pattern looks pretty solid, but this will find the position faster...
.* \K[A-Z]{2,}
Pattern Demo
Here is the PHP implementation: Demo
$str='this is a Test String to get the last index of word with an uppercase letter in PHP test';
var_export(preg_match('/.* \K[A-Z]{2,}/',$str,$out,PREG_OFFSET_CAPTURE)?$out[0][1]:'fail');
// 80
If you want to see a condensed non-regex method, this will work:
Code: Demo
$str='this is a Test String to get the last index of word with an uppercase letter in PHP test';
$allcaps=array_filter(explode(' ',$str),'ctype_upper');
echo "Position = ",strrpos($str,end($allcaps));
Output:
Position = 80
This assumes that there is an all caps word in the input string. If there is a possibility of no all-caps words, then a conditional would sort it out.
Edit, after re-reading the question, I am unsure what exactly makes PHP the targeted substring -- whether it is because it is all caps, or just the last word to start with a capitalized letter.
If just the last word starting with an uppercase letter then this pattern will do: /.* \K[A-Z]/
If the word needs to be all caps, then it is possible that /b word boundaries may be necessary.
Some more samples and explanation from the OP would be useful.
Another edit, you can declare a set of characters to exclude and use just two string functions. I am using a-z and a space with rtrim() then finding the right-most space, and adding 1 to it.
$str='this is a Test String to get the last index of word with an uppercase letter in PHP test';
echo strrpos(rtrim($str,'abcdefghijklmnopqrstuvwxyz '),' ')+1;
// 80
I want to get the last 41 letters of a string, but every time its giving me a empty result.
The string is following:
02674bf7c88c9a025029f96d046651cfsingle100OK4917668157533262-07119519DEE0715DD708E6B65BC2412E1A8EE571F
Here is my code:
$urlstring = $_GET["o"];
$password = "bla";
$salt = "bla";
$result = decode($password, $urlstring, $salt);
if (strpos($result,'OK') !== false) {
$uservar = substr($result, -41);
$file = 'file.txt';
file_put_contents($file,$uservar);
}
Actually
$uservar = substr($result, -41);
does that, i.e. it will return last 41 chars. The problem most likely is that your decode function doesn't work and you never enter the if
$result = decode($password, $urlstring, $salt);
if (strpos($result,'OK') !== false) { // check if $result contains OK
$uservar = explode('-', $result);
$file = 'file.txt';
file_put_contents($file, $uservar[1]);
}
Change the folder permission to 777, and test the code again.
There are several ways to get the last part of the $result string provided in the question.
a) substr()
The function substr() is the most straightforward way to do it (as you already did).
$uservar = substr($result, -41);
b) regular expressions: preg_replace()
You can use preg_replace() to match the last 41 characters of the string into a group and replace the entire string with the group:
$uservar = preg_replace('/^.*(.{41})$/', '$1', $result);
The regular expression used for search:
^ is the beginning of the string;
.* is any character (.), zero or more times (*);
(.{41}) is any character (.), 41 times ({41}); the parentheses around the expression make a subpattern that can be used later in the regex or in the replacement string (as $1);
$ is the end of the string.
It matches any string that is at least 41 characters length; its last 41 characters are grouped in the first subpattern.
The replacement string ($1) refers to the 1st subpattern of the regex. It makes preg_replace() replace the matched string (the entire string) with its first subpattern (its last 41 characters). Read more about the PCRE patterns syntax.
c) convert the string to array of characters
Convert the string into an array of characters (str_split()), extract the correct slice of array (array_slice()), join the characters back (implode()).
$uservar = implode('', array_slice(str_split($result), -41));
This solution works the same as substr().
d) split the string into pieces using delimiter
If you are sure that the part of the string you need to extract does not contain any dash (-) and it starts right after the last dash then we don't even need to know its length. Use explode() to split $result into pieces delimited by dash (-) and the last piece is the part you need:
// Split the string into pieces
$pieces = explode('-', $result);
// Remove the last item from $pieces and return it
$uservar = array_pop($pieces);
// Alternatively, without modifying $pieces:
$uservar = end($pieces);
// Or
$uservar = $pieces[count($piece)-1];
e) ...
With little imagination, more complicated ways to extract a part of the string can be produced in a couple of lines of code.
Conclusion
Given $result is a not-empty string whose length is at least 41, all the above should work and produce the same result. The preg_replace() solution won't work for shorter strings (can be easily changed to work), the explode() solution doesn't care about 41 but uses - to separate the pieces.
If none of them works then your problem is somewhere else. Check for file rights, check if the code enters the if branch etc.
I have a string, something like
bbbbabbbbbccccc
Are there any way for me to replace all the letters "b" after the only one letter "a" into "c" without having to split the string, using PHP?
bbbbacccccccccc
odd question.
echo preg_replace('/a(.*)$/e', "'a'.strtr($1, 'b', 'c')", 'bbbabbbbbccccc');
preg_replace matches everything to the right of 'a' with regex. the e modifier in the regex evaluates the replacement string as code. the code in the replacement string uses strtr() to replace 'b's with 'c's.
Here are three options.
First, a split. Yes, I know you want to do it without a split.
$string = 'bbbbabbbbbccccc';
$parts = preg_split('/(a)/', $string, 2, PREG_SPLIT_DELIM_CAPTURE);
// Parts now looks like:
// array('bbb', 'a', 'bbbbcccc');
$parts[2] = str_replace('b', 'c', $parts[2]);
$correct_string = join('', $parts);
Second, a position search and a substring replacement.
$string = 'bbbbabbbbbccccc';
$first_a_index = strpos($string, 'a');
if($first_a_index !== false) {
// Now, grab everything from that first 'a' to the end of the string.
$replaceable = substr($string, $first_a_index);
// Replace it.
$replaced = str_replace('b', 'c', $replaceable );
// Now splice it back in
$string = substr_replace($string, $replaced, $first_a_index);
}
Third, I was going to post a regex, but the one dqhendricks posted is just as good.
These code examples are verbose for clarity, and can be reduced to one-or-two-liners.
$s = 'bbbbabbbbbccccc';
echo preg_replace('/((?:(?!\A)\G|(?<!a)a(?!a))[^b]*)b/', '$1c', $s);
\G matches the position where the previous match ended. On the first match attempt, \G matches the beginning of the string like \A. We don't want that, so we use (?!\A) to prevent it.
(?<!a)a(?!a) matches an a that's neither preceded nor followed by an a. The a is captured in group #1 so we can plug it back into the replacement with $1.
This is a "pure regex" solution, meaning it does the whole job in one call to preg_replace and doesn't rely on embedded code and the /e modifier. It's good to know in case you ever find yourself working within those constraints, but it definitely shouldn't be your first resort.