I have a string formed up by numbers and sometimes by letters.
Example AF-1234 or 345ww.
I have to get the numeric part and increment it by one.
how can I do that? maybe with regex?
You can use preg_replace_callback as:
function inc($matches) {
return ++$matches[1];
}
$input = preg_replace_callback("|(\d+)|", "inc", $input);
Basically you match the numeric part of the string using the regex \d+ and replace it with the value returned by the callback function which returns the incremented value.
Ideone link
Alternatively this can be done using preg_replace() with the e modifier as:
$input = preg_replace("|(\d+)|e", "$1+1", $input);
Ideone link
If the string ends with numeric characters it is this simple...
$str = 'AF-1234';
echo $str++; //AF-1235
That works the same way with '345ww' though the result may not be what you expect.
$str = '345ww';
echo $str++; //345wx
#tampe125
This example is probably the best method for your needs if incrementing string that end with numbers.
$str = 'XXX-342';
echo $str++; //XXX-343
Here is an example that worked for me by doing a pre increment on the value
$admNo = HF0001;
$newAdmNo = ++$admNo;
The above code will output HF0002
If you are dealing with strings that have multiple number parts then it's not so easy to solve with regex, since you might have numbers overflowing from one numeric part to another.
For example if you have a number INV00-10-99 which should increment to INV00-11-00.
I ended up with the following:
for ($i = strlen($string) - 1; $i >= 0; $i--) {
if (is_numeric($string[$i])) {
$most_significant_number = $i;
if ($string[$i] < 9) {
$string[$i] = $string[$i] + 1;
break;
}
// The number was a 9, set it to zero and continue.
$string[$i] = 0;
}
}
// If the most significant number was set to a zero it has overflowed so we
// need to prefix it with a '1'.
if ($string[$most_significant_number] === '0') {
$string = substr_replace($string, '1', $most_significant_number, 0);
}
Here's some Python code that does what you ask. Not too great on my PHP, but I'll see if I can convert it for you.
>>> import re
>>> match = re.match(r'(\D*)(\d+)(\D*)', 'AF-1234')
>>> match.group(1) + str(int(match.group(2))+1) + match.group(3)
'AF-1235'
This is similar to the answer above, but contains the code inline and does a full check for the last character.
function replace_title($title) {
$pattern = '/(\d+)(?!.*\d)+/';
return preg_replace_callback($pattern, function($m) { return ++$m[0]; }, $title);
}
echo replace_title('test 123'); // test 124
echo replace_title('test 12 3'); // test 12 4
echo replace_title('test 123 - 2'); // test 123 - 3
echo replace_title('test 123 - 3 - 5'); // test 123 - 3 - 6
echo replace_title('123test'); // 124test
Related
The goal is to get from string $a="NewYork" new string without lowercase that stands before uppercase.
In this example, we should get output "NeYork"
I tried to do this through positions of small and big letters in ASCII table, but it doesn't work. I'm not sure is it possible to to do this in similar way, through positions in ASCII table.
function delete_char($a)
{
global $b;
$a = 'NewYork';
for($i =0; $i<strlen($a); $i++)
{
if( ord($a[$i])< ord($a[$i+1])){//this solves only part of a problem
chop($a,'$a[$i]');
}
else{
$b.=$a[$i];
}
}
return $b;
}
This is something a regular expression handles with ease
<?php
$a ="NewYorkNewYork";
$reg="/[a-z]([A-Z])/";
echo preg_replace($reg, "$1", $a); // NeYorNeYork
The regular expression searches for a lower case letter followed by an upper case letter, and captures the upper case one. preg_replace() then replace that combination with just the captured letter ($1).
See https://3v4l.org/o43bO
You don't need to capture the uppercase letter and use a backreference in the replacement string.
More simply, match the lowercase letter then use a lookahead for an uppercase letter -- this way you only replace the lowercase character with an empty string. (Demo)
echo preg_replace('~[a-z](?=[A-Z])~', '', 'NewYork');
// NeYork
As for a review of your code, there are multiple issues.
global $b doesn't make sense to me. You need the variable to be instantiated as an empty string within the scope of the custom function only. It more simply should be $b = '';.
The variable and function naming is unhelpful. A function's name should specifically describe the function's action. A variable should intuitively describe the data that it contains. Generally speaking, don't sacrifice clarity for brevity.
As a matter of best practice, you should not repeatedly call a function when you know that the value has not changed. Calling strlen() on each iteration of the loop is not beneficial. Declare $length = strlen($input) and use $length over and over.
$a[$i+1] is going to generate an undefined offset warning on the last iteration of the loop because there cannot possibly be a character at that offset when you already know the length of the string has been fully processed. In other words, the last character of a string will have an offset of "length - 1". There is more than one way to address this, but I'll use the null coalescing operator to set a fallback character that will not qualify the previous letter for removal.
Most importantly, you cannot just check that the current ord value is less than the next ord value. See here that lowercase letters have an ordinal range of 97 through 122 and uppercase letters have an ordinal range of 65 through 90. You will need to check that both letters meet the qualifying criteria for the current letter to be included in the result string.
Rewrite: (Demo)
function removeLowerCharBeforeUpperChar(string $input): string
{
$output = '';
$length = strlen($input);
for ($offset = 0; $offset < $length; ++$offset) {
$currentOrd = ord($input[$offset]);
$nextOrd = ord($input[$offset + 1] ?? '_');
if ($currentOrd < 97
|| $currentOrd > 122
|| $nextOrd < 65
|| $nextOrd > 90
){
$output .= $input[$offset];
}
}
return $output;
}
echo removeLowerCharBeforeUpperChar('MickMacKusa');
// MicMaKusa
Or with ctype_ functions: (Demo)
function removeLowerCharBeforeUpperChar(string $input): string
{
$output = '';
$length = strlen($input);
for ($offset = 0; $offset < $length; ++$offset) {
$nextLetter = $input[$offset + 1] ?? '';
if (ctype_lower($input[$offset]) && ctype_upper($nextLetter)) {
$output .= $nextLetter; // omit current letter, save next
++$offset; // double iterate
} else {
$output .= $input[$offset]; // save current letter
}
}
return $output;
}
To clarify, I would not use the above custom function in a professional script and both snippets are not built to process strings containing multibyte characters.
Simply, I create new variable $s used for store new string to be returned and a make loop iterate over $a string, I used ctype_upper to check if next character not uppercase append it to $s. at the end i return $s concatenate with last char of string.
function delete_char(string $a): string
{
if(!strlen($a))
{
return '';
}
$s='';
for($i = 0; $i < strlen($a)-1; $i++)
{
if(!ctype_upper($a[$i+1])){
$s.=$a[$i];
}
}
return $s.$a[-1];
}
echo delete_char("NewYork");//NeYork
Something like this maybe?
<?php
$word = 'NewYork';
preg_match('/.[A-Z].*/', $word, $match);
if($match){
$rlen = strlen($match[0]); //length from character before capital letter
$start = strlen($word)-$rlen; //first lower case before the capital
$edited_word = substr_replace($word, '', $start, 1); //removes character
echo $edited_word; //prints NeYork
}
?>
I have a string formed up by numbers and sometimes by letters.
Example AF-1234 or 345ww.
I have to get the numeric part and increment it by one.
how can I do that? maybe with regex?
You can use preg_replace_callback as:
function inc($matches) {
return ++$matches[1];
}
$input = preg_replace_callback("|(\d+)|", "inc", $input);
Basically you match the numeric part of the string using the regex \d+ and replace it with the value returned by the callback function which returns the incremented value.
Ideone link
Alternatively this can be done using preg_replace() with the e modifier as:
$input = preg_replace("|(\d+)|e", "$1+1", $input);
Ideone link
If the string ends with numeric characters it is this simple...
$str = 'AF-1234';
echo $str++; //AF-1235
That works the same way with '345ww' though the result may not be what you expect.
$str = '345ww';
echo $str++; //345wx
#tampe125
This example is probably the best method for your needs if incrementing string that end with numbers.
$str = 'XXX-342';
echo $str++; //XXX-343
Here is an example that worked for me by doing a pre increment on the value
$admNo = HF0001;
$newAdmNo = ++$admNo;
The above code will output HF0002
If you are dealing with strings that have multiple number parts then it's not so easy to solve with regex, since you might have numbers overflowing from one numeric part to another.
For example if you have a number INV00-10-99 which should increment to INV00-11-00.
I ended up with the following:
for ($i = strlen($string) - 1; $i >= 0; $i--) {
if (is_numeric($string[$i])) {
$most_significant_number = $i;
if ($string[$i] < 9) {
$string[$i] = $string[$i] + 1;
break;
}
// The number was a 9, set it to zero and continue.
$string[$i] = 0;
}
}
// If the most significant number was set to a zero it has overflowed so we
// need to prefix it with a '1'.
if ($string[$most_significant_number] === '0') {
$string = substr_replace($string, '1', $most_significant_number, 0);
}
Here's some Python code that does what you ask. Not too great on my PHP, but I'll see if I can convert it for you.
>>> import re
>>> match = re.match(r'(\D*)(\d+)(\D*)', 'AF-1234')
>>> match.group(1) + str(int(match.group(2))+1) + match.group(3)
'AF-1235'
This is similar to the answer above, but contains the code inline and does a full check for the last character.
function replace_title($title) {
$pattern = '/(\d+)(?!.*\d)+/';
return preg_replace_callback($pattern, function($m) { return ++$m[0]; }, $title);
}
echo replace_title('test 123'); // test 124
echo replace_title('test 12 3'); // test 12 4
echo replace_title('test 123 - 2'); // test 123 - 3
echo replace_title('test 123 - 3 - 5'); // test 123 - 3 - 6
echo replace_title('123test'); // 124test
Given a string such as:
$a = '00023407283';
$b = 'f045602345';
Is there a built in function that can count the number of occurrences of a specific character starting at the beginning and continuing until it finds a different character that is not specified?
Given the above, and specifying zero (0) as the character, the expected result would be:
$a = '00023407283'; // 3 (the other zeros don't count)
$b = 'f0045602345'; // 0 (It does not start with zero)
This should do the trick:
function count_leading($haystack,$value) {
$i = 0;
$mislead = false;
while($i < strlen($haystack) && !$mislead) {
if($haystack[$i] == $value) {
$i += 1;
} else {
$mislead = true;
}
}
return $i;
}
//examples
echo count_leading('aaldfkjlk','a'); //returns 2
echo count_leading('dskjheelk','c'); //returns 0
I don't think there's any built-in functions that could do that (it's too specific) but you could write a method to do that
function repeatChar($string, $char) {
$pos = 0;
while($string{$pos} == $char) $pos++;
return $pos;
}
Yes, you want strspn, which counts the number of characters from the second argument at the beginning of the first argument:
echo strspn($a, '0'); // === 3
echo strspn($b, '0'); // === 0
See it live at 3v4l.org. Besides being a built-in (read "fast"), this also accepts any number of single characters to look at the beginning. However, note that the function is byte-oriented, so it will not work as expected for multi-byte characters.
Since I am still new to PHP, I am looking for a way to find out how to get a specific character from a string.
Example:
$word = "master";
$length = strlen($word);
$random = rand(1,$length);
So let's say the $random value is 3, then I would like to find out what character the third one is, so in this case the character "s". If $random was 2 I would like to know that it's a "a".
I am sure this is really easy, but I tried some substr ideas for nearly an hour now and it always fails.
Your help would be greatly appreciated.
You can use substr() to grab a portion of a string starting from a point and going length. so example would be:
substr('abcde', 1, 1); //returns b
In your case:
$word = "master";
$length = strlen($word) - 1;
$random = rand(0,$length);
echo substr($word, $random, 1);//echos single char at random pos
See it in action here
You can use your string the same like 0-based index array:
$some_string = "apple";
echo $some_string[2];
It'll print 'p'.
or, in your case:
$word = "master";
$length = strlen($word);
$random = rand(0,$length-1);
echo $word[$random];
Try this simply:
$word = "master";
$length = strlen($word);
$random = rand(0,$length-1);
if($word[$random] == 's'){
echo $word[$random];
}
Here I used 0 because $word[0] is m so that we need to subtract one from strlen($word) for getting last character r
Use substr
$GetThis = substr($myStr, 5, 5);
Just use the same values for the same or different if you want multiple characters
$word = "master";
$length = strlen($word);
$random = rand(0,$length-1);
$GetThis = substr($word, $random, $random);
As noted in my comment (I overlooked as well) be sure to start your rand at 0 to include the beginning of your string since the m is at place 0. If we all overlooked that it wouldn't be random (as random?) now would it :)
You can simply use $myStr{$random} to obtain the nth character of the string.
Pattern search within a string.
for eg.
$string = "111111110000";
FindOut($string);
Function should return 0
function FindOut($str){
$items = str_split($str, 3);
print_r($items);
}
If I understand you correctly, your problem comes down to finding out whether a substring of 3 characters occurs in a string twice without overlapping. This will get you the first occurence's position if it does:
function findPattern($string, $minlen=3) {
$max = strlen($string)-$minlen;
for($i=0;$i<=$max;$i++) {
$pattern = substr($string,$i,$minlen);
if(substr_count($string,$pattern)>1)
return $i;
}
return false;
}
Or am I missing something here?
What you have here can conceptually be solved with a sliding window. For your example, you have a sliding window of size 3.
For each character in the string, you take the substring of the current character and the next two characters as the current pattern. You then slide the window up one position, and check if the remainder of the string has what the current pattern contains. If it does, you return the current index. If not, you repeat.
Example:
1010101101
|-|
So, pattern = 101. Now, we advance the sliding window by one character:
1010101101
|-|
And see if the rest of the string has 101, checking every combination of 3 characters.
Conceptually, this should be all you need to solve this problem.
Edit: I really don't like when people just ask for code, but since this seemed to be an interesting problem, here is my implementation of the above algorithm, which allows for the window size to vary (instead of being fixed at 3, the function is only briefly tested and omits obvious error checking):
function findPattern( $str, $window_size = 3) {
// Start the index at 0 (beginning of the string)
$i = 0;
// while( (the current pattern in the window) is not empty / false)
while( ($current_pattern = substr( $str, $i, $window_size)) != false) {
$possible_matches = array();
// Get the combination of all possible matches from the remainder of the string
for( $j = 0; $j < $window_size; $j++) {
$possible_matches = array_merge( $possible_matches, str_split( substr( $str, $i + 1 + $j), $window_size));
}
// If the current pattern is in the possible matches, we found a duplicate, return the index of the first occurrence
if( in_array( $current_pattern, $possible_matches)) {
return $i;
}
// Otherwise, increment $i and grab a new window
$i++;
}
// No duplicates were found, return -1
return -1;
}
It should be noted that this certainly isn't the most efficient algorithm or implementation, but it should help clarify the problem and give a straightforward example on how to solve it.
Looks like you more want to use a sub-string function to walk along and check every three characters and not just break it into 3
function fp($s, $len = 3){
$max = strlen($s) - $len; //borrowed from lafor as it was a terrible oversight by me
$parts = array();
for($i=0; $i < $max; $i++){
$three = substr($s, $i, $len);
if(array_key_exists("$three",$parts)){
return $parts["$three"];
//if we've already seen it before then this is the first duplicate, we can return it
}
else{
$parts["$three"] = i; //save the index of the starting position.
}
}
return false; //if we get this far then we didn't find any duplicate strings
}
Based on the str_split documentation, calling str_split on "1010101101" will result in:
Array(
[0] => 101
[1] => 010
[2] => 110
[3] => 1
}
None of these will match each other.
You need to look at each 3-long slice of the string (starting at index 0, then index 1, and so on).
I suggest looking at substr, which you can use like this:
substr($input_string, $index, $length)
And it will get you the section of $input_string starting at $index of length $length.
quick and dirty implementation of such pattern search:
function findPattern($string){
$matches = 0;
$substrStart = 0;
while($matches < 2 && $substrStart+ 3 < strlen($string) && $pattern = substr($string, $substrStart++, 3)){
$matches = substr_count($string,$pattern);
}
if($matches < 2){
return null;
}
return $substrStart-1;