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 有赏,i卡绘世画不出
  • ¥15 如何用stata画出文献中常见的安慰剂检验图
  • ¥15 c语言链表结构体数据插入
  • ¥40 使用MATLAB解答线性代数问题
  • ¥15 COCOS的问题COCOS的问题
  • ¥15 FPGA-SRIO初始化失败
  • ¥15 MapReduce实现倒排索引失败
  • ¥15 ZABBIX6.0L连接数据库报错,如何解决?(操作系统-centos)
  • ¥15 找一位技术过硬的游戏pj程序员
  • ¥15 matlab生成电测深三层曲线模型代码