Reputation: 7277
$str = 'a';
echo ++$str; // prints 'b'
$str = 'z';
echo ++$str; // prints 'aa'
Its very useful to get next column name in an excel file.
But if I use similar code using -- operator to get the previous letter then its not working:
$str = 'b';
echo --$str; // prints 'b' but I need 'a'
$str = 'aa';
echo --$str; // prints 'aa' but I need 'z'
What can be the solution to get the previous letter similarly? And what can be the reason as its not working?
Upvotes: 12
Views: 4401
Reputation: 1
str_prev.php:
<?php
function str_prev($str) {
$chars = str_split($str);
$nb_chars = strlen($str);
$ret = true;
for ($i = $nb_chars-1; $i >= 0; --$i) {
if ($chars[$i] === 'a') {
$chars[$i] = 'z';
} else {
$chars[$i] = chr(ord($chars[$i]) - 1);
$ret = false;
break;
}
}
if ($ret)
$chars[$nb_chars-1] = '';
return implode('', $chars);
}
$tests = array(
[ 'a', '' ],
[ 'b', 'a' ],
[ 'z', 'y' ],
[ 'aa', 'z' ],
[ 'ab', 'aa' ],
[ 'az', 'ay' ],
[ 'ba', 'az' ],
[ 'ca', 'bz' ],
[ 'aaa', 'zz' ],
[ 'aba', 'aaz' ],
[ 'abb', 'aba' ],
[ 'cha', 'cgz' ],
[ 'zhuwncha', 'zhuwncgz' ],
);
foreach ($tests as $t) {
$prev = str_prev($t[0]);
if ($prev === $t[1]) {
print "str_prev('$t[0]') -> '$prev' : correct\n";
} else {
print "str_prev('$t[0]') -> '$prev' : wrong, should have been $t[1]\n";
}
}
?>
$ php str_prev.php
str_prev('a') -> '' : correct
str_prev('b') -> 'a' : correct
str_prev('z') -> 'y' : correct
str_prev('aa') -> 'z' : correct
str_prev('ab') -> 'aa' : correct
str_prev('az') -> 'ay' : correct
str_prev('ba') -> 'az' : correct
str_prev('ca') -> 'bz' : correct
str_prev('aaa') -> 'zz' : correct
str_prev('aba') -> 'aaz' : correct
str_prev('abb') -> 'aba' : correct
str_prev('cha') -> 'cgz' : correct
str_prev('zhuwncha') -> 'zhuwncgz' : correct
Upvotes: 0
Reputation: 46900
$str='z';
echo chr(ord($str)-1); //y
Note: This isn't circular for a-z
. Need to add rules for that
Edit This edit covers for your special requirement from excel example. Although its a little longer piece of code.
//Step 1: Build your range; We cant just go about every character in every language.
$x='a';
while($x!='zz') // of course you can take that to zzz or beyond etc
{
$values[]=$x++; // A simple range() call will not work for multiple characters
}
$values[]=$x; // Now this array contains range `a - zz`
//Step 2: Provide reference
$str='ab';
//Step 3: Move next or back
echo $values[array_search(strtolower($str),$values)-1]; // Previous = aa
echo $values[array_search(strtolower($str),$values)+1]; // Next = ac
Upvotes: 9
Reputation: 7277
I could solve in this way. How is it? The cons is that it only can handle uppercase right now. Some more work can also fix that.
<?php
function get_previous_letter($string){
$last = substr($string, -1);
$part=substr($string, 0, -1);
if(strtoupper($last)=='A'){
$l = substr($part, -1);
if($l=='A'){
return substr($part, 0, -1)."Z";
}
return $part.chr(ord($l)-1);
}else{
return $part.chr(ord($last)-1);
}
}
echo get_previous_letter("AAAAAA");
?>
Upvotes: -1
Reputation: 20058
Using array:
$cla=array('A', 'B', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'R', 'S', 'Š', 'Z', 'Ž', 'T', 'U', 'V', 'Õ', 'Ä', 'Ö', 'Ü');
$direction = -1;
$element = 'Ü';
$element2 = $cla[((array_search($element,$cla)+count($cla)+$direction)%count($cla))];
Upvotes: 0