itsazzad
itsazzad

Reputation: 7277

Most efficient way to get previous letter in the alphabet using PHP

Its working nicely:

$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

Answers (4)

Oranbe
Oranbe

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

Hanky Panky
Hanky Panky

Reputation: 46900

$str='z';
echo chr(ord($str)-1);   //y

Note: This isn't circular for a-z. Need to add rules for that

Fiddle

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

Fiddle

Upvotes: 9

itsazzad
itsazzad

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");
?>

CODEPAD

Upvotes: -1

Margus
Margus

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

Related Questions