dounao2829 2016-03-16 18:58
浏览 422
已采纳

如何在php下使用ord()和chr()实现char

In the php wild wild west, given that Most efficient way to get next letter in the alphabet using PHP is made by the pre increment ++ operator applied to a char (i.e. one sized string):

$str = 'a';
echo ++$str; // prints 'b'

$str = 'z';
echo ++$str; // prints 'aa' 

And that there is this crazyness in

  for ($char='A'; $char<='Z'; $char++) {
    echo $char;
  }

that will print out

ABCDEFGHIJKLMNOPQRSTUVWXYZAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARASATAUAVAWAXAYAZBABBBCBDBEBFBGBHBIBJBKBLBMBNBOBPBQBRBSBTBUBVBWBXBYBZCACBCCCDCECFCGCHCICJCKCLCMCNCOCPCQCRCSCTCUCVCWCXCYCZDADBDCDDDEDFDGDHDIDJDKDLDMDNDODPDQDRDSDTDUDVDWDXDYDZEAEBECEDEEEFEGEHEIEJEKELEMENEOEPEQERESETEUEVEWEXEYEZFAFBFCFDFEFFFGFHFIFJFKFLFMFNFOFPFQFRFSFTFUFVFWFXFYFZGAGBGCGDGEGFGGGHGIGJGKGLGMGNGOGPGQGRGSGTGUGVGWGXGYGZHAHBHCHDHEHFHGHHHIHJHKHLHMHNHOHPHQHRHSHTHUHVHWHXHYHZIAIBICIDIEIFIGIHIIIJIKILIMINIOIPIQIRISITIUIVIWIXIYIZJAJBJCJDJEJFJGJHJIJJJKJLJMJNJOJPJQJRJSJTJUJVJWJXJYJZKAKBKCKDKEKFKGKHKIKJKKKLKMKNKOKPKQKRKSKTKUKVKWKXKYKZLALBLCLDLELFLGLHLILJLKLLLMLNLOLPLQLRLSLTLULVLWLXLYLZMAMBMCMDMEMFMGMHMIMJMKMLMMMNMOMPMQMRMSMTMUMVMWMXMYMZNANBNCNDNENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZOAOBOCODOEOFOGOHOIOJOKOLOMONOOOPOQOROSOTOUOVOWOXOYOZPAPBPCPDPEPFPGPHPIPJPKPLPMPNPOPPPQPRPSPTPUPVPWPXPYPZQAQBQCQDQEQFQGQHQIQJQKQLQMQNQOQPQQQRQSQTQUQVQWQXQYQZRARBRCRDRERFRGRHRIRJRKRLRMRNRORPRQRRRSRTRURVRWRXRYRZSASBSCSDSESFSGSHSISJSKSLSMSNSOSPSQSRSSSTSUSVSWSXSYSZTATBTCTDTETFTGTHTITJTKTLTMTNTOTPTQTRTSTTTUTVTWTXTYTZUAUBUCUDUEUFUGUHUIUJUKULUMUNUOUPUQURUSUTUUUVUWUXUYUZVAVBVCVDVEVFVGVHVIVJVKVLVMVNVOVPVQVRVSVTVUVVVWVXVYVZWAWBWCWDWEWFWGWHWIWJWKWLWMWNWOWPWQWRWSWTWUWVWWWXWYWZXAXBXCXDXEXFXGXHXIXJXKXLXMXNXOXPXQXRXSXTXUXVXWXXXYXZYAYBYCYDYEYFYGYHYIYJYKYLYMYNYOYPYQYRYSYTYUYVYWYXYYYZ

due to the fact that after 'Z' comes 'AA', and 'AA' is smaller than 'Z'.

and so the correct way is print the next char will be

foreach (range('A', 'Z') as $char) {
    echo $char;
  }

that will print out

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Assumed that we can get the next char with modulo operator and chr(ord())

$next=chr((((ord($c) - ord('A')) + 1) % 26) + ord('A'));

I need a way to do the ++$char using ord() and chr() functions, and so doing

  $cmax=ord('A');
  $char='A';
  foreach (range('A', 'z') as $c) {
    ++$char;
    $next=chr((((ord($c) - $cmax) + 1) % 26) + $cmax);
    echo ord($c)." ".$c." ".$next." ".$char."
";
  }

it will print out:

65 A B B
66 B C C
67 C D D
68 D E E
69 E F F
70 F G G
71 G H H
72 H I I
73 I J J
74 J K K
75 K L L
76 L M M
77 M N N
78 N O O
79 O P P
80 P Q Q
81 Q R R
82 R S S
83 S T T
84 T U U
85 U V V
86 V W W
87 W X X
88 X Y Y
89 Y Z Z
90 Z A AA
91 [ B AB
92 \ C AC
93 ] D AD
94 ^ E AE
95 _ F AF
96 ` G AG
97 a H AH
98 b I AI
99 c J AJ

since in $next char are not being accumulated, just getting the next one. So how to get the same value in the 3rd and 4th columns using only chr( ord() )?

[EDIT]

I'm going to clarify that I need the same output of this for loop

for ($char='A'; $char<='Z'; $char++) {
    echo $char."
";
}

that is like

A
B
C
...
Y
Z
AA
AB
AC
AD
AE
AF
...
YW
YX
YY
YZ

but only using ord() and chr() and a modulo operator. Now the last byte (first byte) is simply obtained by modulo %26:

$byte_two=chr( ( ((ord($code) - ord('A')) + 1) % 26) + ord('A') );

that in a foreach on the given range('A', 'z'):

foreach (range('A', 'z') as $code) {
    $byte_one=chr( ( ((ord($code) - ord('A')) + 1) % 26) + ord('A') );
    echo ord($code)."\t".$byte_one."
";
}

will print outs exactly the last byte there as the same byte position in ++$char. So I think I'm missing the $byte_two, the first byte here.

[SUGGESTED IMPLEMENTATION]

This is one of the suggested implementation, and the most simple I was able to come out using a lookup table as suggested:

function lookupNextChar($c)
  {
    static $lookup_table=null;
    if ($lookup_table === null) {
      $lookup_table=explode(",","A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA,CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK,CL,CM,CN,CO,CP,CQ,CR,CS,CT,CU,CV,CW,CX,CY,CZ,DA,DB,DC,DD,DE,DF,DG,DH,DI,DJ,DK,DL,DM,DN,DO,DP,DQ,DR,DS,DT,DU,DV,DW,DX,DY,DZ,EA,EB,EC,ED,EE,EF,EG,EH,EI,EJ,EK,EL,EM,EN,EO,EP,EQ,ER,ES,ET,EU,EV,EW,EX,EY,EZ,FA,FB,FC,FD,FE,FF,FG,FH,FI,FJ,FK,FL,FM,FN,FO,FP,FQ,FR,FS,FT,FU,FV,FW,FX,FY,FZ,GA,GB,GC,GD,GE,GF,GG,GH,GI,GJ,GK,GL,GM,GN,GO,GP,GQ,GR,GS,GT,GU,GV,GW,GX,GY,GZ,HA,HB,HC,HD,HE,HF,HG,HH,HI,HJ,HK,HL,HM,HN,HO,HP,HQ,HR,HS,HT,HU,HV,HW,HX,HY,HZ,IA,IB,IC,ID,IE,IF,IG,IH,II,IJ,IK,IL,IM,IN,IO,IP,IQ,IR,IS,IT,IU,IV,IW,IX,IY,IZ,JA,JB,JC,JD,JE,JF,JG,JH,JI,JJ,JK,JL,JM,JN,JO,JP,JQ,JR,JS,JT,JU,JV,JW,JX,JY,JZ,KA,KB,KC,KD,KE,KF,KG,KH,KI,KJ,KK,KL,KM,KN,KO,KP,KQ,KR,KS,KT,KU,KV,KW,KX,KY,KZ,LA,LB,LC,LD,LE,LF,LG,LH,LI,LJ,LK,LL,LM,LN,LO,LP,LQ,LR,LS,LT,LU,LV,LW,LX,LY,LZ,MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NB,NC,ND,NE,NF,NG,NH,NI,NJ,NK,NL,NM,NN,NO,NP,NQ,NR,NS,NT,NU,NV,NW,NX,NY,NZ,OA,OB,OC,OD,OE,OF,OG,OH,OI,OJ,OK,OL,OM,ON,OO,OP,OQ,OR,OS,OT,OU,OV,OW,OX,OY,OZ,PA,PB,PC,PD,PE,PF,PG,PH,PI,PJ,PK,PL,PM,PN,PO,PP,PQ,PR,PS,PT,PU,PV,PW,PX,PY,PZ,QA,QB,QC,QD,QE,QF,QG,QH,QI,QJ,QK,QL,QM,QN,QO,QP,QQ,QR,QS,QT,QU,QV,QW,QX,QY,QZ,RA,RB,RC,RD,RE,RF,RG,RH,RI,RJ,RK,RL,RM,RN,RO,RP,RQ,RR,RS,RT,RU,RV,RW,RX,RY,RZ,SA,SB,SC,SD,SE,SF,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SP,SQ,SR,SS,ST,SU,SV,SW,SX,SY,SZ,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,TS,TT,TU,TV,TW,TX,TY,TZ,UA,UB,UC,UD,UE,UF,UG,UH,UI,UJ,UK,UL,UM,UN,UO,UP,UQ,UR,US,UT,UU,UV,UW,UX,UY,UZ,VA,VB,VC,VD,VE,VF,VG,VH,VI,VJ,VK,VL,VM,VN,VO,VP,VQ,VR,VS,VT,VU,VV,VW,VX,VY,VZ,WA,WB,WC,WD,WE,WF,WG,WH,WI,WJ,WK,WL,WM,WN,WO,WP,WQ,WR,WS,WT,WU,WV,WW,WX,WY,WZ,XA,XB,XC,XD,XE,XF,XG,XH,XI,XJ,XK,XL,XM,XN,XO,XP,XQ,XR,XS,XT,XU,XV,XW,XX,XY,XZ,YA,YB,YC,YD,YE,YF,YG,YH,YI,YJ,YK,YL,YM,YN,YO,YP,YQ,YR,YS,YT,YU,YV,YW,YX,YY,YZ");
      echo implode($lookup_table,',')."
";
      echo count($lookup_table)."
";
    }
    $idx=( ((ord($c) - ord('A')) + 1 ) % count($lookup_table));
    return $lookup_table[ $idx ];
  }

To prove it, just get the next $char from the range('A','z'):

  $sum=$n='A';
  foreach (range('A','z') as $c) {

    $n=lookupNextChar($c,$lookup_table);
    ++$sum;
    echo "$c\t$n\t$sum
";
  }

and then I get

A   B   B
B   C   C
C   D   D
D   E   E
E   F   F
F   G   G
.. .. ..
X   Y   Y
Y   Z   Z
Z   AA  AA
[   AB  AB
\   AC  AC
]   AD  AD
^   AE  AE
.. ..  ..
x   CD  BD
y   DE  BE
z   EF  BF

that is want I wanted to achieve as output, even if using a different way.

NOTE. Of course, the lookup table was generated using the ++ operator then:

$lookup_table=array();
for ($char='A'; $char<='Z'; $char++) {
 array_push($lookup_table,$char);
}

that does not imply to be used programmatically in the javascript porting (see comments).

  • 写回答

2条回答 默认 最新

  • doukong9982 2016-03-18 14:28
    关注

    Requirements: Allow increment of a string in the same manner as PHP (please see links in the question). At first I thought: How unusual? I still think that.

    Ok, We need to produce something that will do that without using the PHP routines.

    Ok, what do have?

    I thought of it as a 'base26' number. I chose to implement it as:

    • using an array for each digit that had a range of 1 .. 26.
    • convert the numerical digit in the array to display characters using an array lookup.

    Working demonstration at eval.in

    For convenience, I put it in PHP class:

    I try and make the code understandable...

    The base26 class:

    class base26 { // it only does increment / addition 
    
        const
            numberBase = 26; 
    
        // These are characters used where A => 1 and Z is 26
        // These can be changed as you wish. They could be multibyte?
    
        //                              0        1         2     2
        //                              12345678901234567890123456
        public static $displayChars  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    
    
        /**
        * current number -  least significant digit is digit[0]      
        * 
        * @var array $digit - integer with range 1 .. 26 
        */ 
        public $digit = array();
    
    
        // initialize if nothing provided
        public function __construct($letters = 'A') 
        {
            $this->init($letters);
        }
    
        /**
        * Convert letters to base26 and store in the $digit array
        * 
        * @param string $letters
        * @return void
        */
        public function init($letters = 'A')
        {
            $this->digit = array();
            $lsd =  strlen($letters) - 1;
    
            for ($idx = $lsd; $idx >= 0; $idx--) {
                $this->digit[] = $this->charValue($letters[$idx]);
            }
        }
    
        /**
        * Increment the 'least significant digit' and then propagate the `carry`
        * when it exceeds the number base limit. 
        * 
        * @param integer $int -- default to 1
        * @return void
        */
        public function inc($int = 1) // addition with carry - easy to understand
        {
            $curDigit = 0; // add to least significant digit
            $carry    = 0; 
    
            $this->digit[$curDigit] += $int; 
    
            while ($this->digit[$curDigit] > self::numberBase) {
    
                $carry = 1; // next carry
                $this->digit[$curDigit] %= self::numberBase;          // reset digit 
    
                $curDigit++; // check next digit...
    
                if (isset($this->digit[$curDigit])) {
                    $this->digit[$curDigit] += $carry;
                }
                else {
                    $this->digit[$curDigit] = $carry;   
                }
            }
        }
    
        /**
        * Convert a number to a character to display 
        * 
        * @param intger $int
        * 
        * @return char
        */
        public function toChar($int) 
        {
            return self::$displayChars[$int - 1];
        }
    
        /**
        * The value of the character in the number base range
        * 
        * @param undefined $letter
        * @return integer 
        */
        public function charValue($letter) 
        {
            return stripos(self::$displayChars, $letter) + 1;
        }
    
        /**
        * return the current number values as a string using the display characters
        * 
        * @return string 
        */ 
        public function current() 
        {
            $digitCount = count($this->digit);
            $outStr = str_pad('A', count($this->digit));
            $outIdx = $digitCount - 1;
            for ($idx = 0;  $idx < $digitCount; $idx++, $outIdx-- ) {
                $outStr[$outIdx] = $this->toChar($this->digit[$idx]);    
            }
    
            return $outStr;
        }
    }
    

    Examples:

    // ---------------------------------------------
    // show increment from Z -> AA
    echo PHP_EOL;
    $b26 = new base26('Z');
    echo $b26->current() .'|';
    $b26->inc();
    echo $b26->current() .'|';
    
    Output: Z|AA|
    
    // ---------------------------------------------
    // show increment from 'FY' -> FZ -> GA
    echo PHP_EOL;
    $b26->init('FY');
    echo $b26->current() .'|';
    $b26->inc();
    echo $b26->current() .'|';
    $b26->inc();
    echo $b26->current() .'|';
    
    Output: FY|FZ|GA|
    
    // ---------------------------------------------
    // Show it does what PHP does...
    echo PHP_EOL;
    $b26 = new base26();
    while ($b26->current() <= 'Z') {
        echo $b26->current() .'|';
        $b26->inc();
    }
    
    Output: A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|AA|AB|AC|AD|AE|AF|AG|AH|AI|AJ|AK|AL|AM|AN|AO ...
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler