Por que esse código simplesmente não imprime as letras de A a Z?

435
<?php
for ($i = 'a'; $i <= 'z'; $i++)
    echo "$i\n";

Este trecho fornece a seguinte saída (novas linhas são substituídas por espaços):

abcdefghijklmnopqrstu vwxyz aa ab ac ad a ag ah ai aj ak al am an ao ap aq ar como em au av aw ax a az ba bb bc bd ser bf bg bh bi bj bk bl bm bn bb b b b b b b b b b b b b b bw bx por 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 df dg dh di dj dk dl dm dn dp dq dr ds dt du dv dw dx dy dz e eb ec ed ee ef eg eh ei ej ek el em en e ep eq er es et eu ev ew ex ... on to yz

Milan Babuškov
fonte
31
PHP não é C, mesmo que a sintaxe tente convencê-lo do contrário.
Joni
3
Isso funciona para mim com uma alteração muito pequena: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Surreal Dreams
2
O comentário sobre o PHP não é C - foi o exemplo mais aguçado: em c: char c = 'a'; não é o mesmo que em php:, $c = 'a';o ponto é que em C existe um tipo de caractere (símbolo do caractere 1), mas não no PHP, se você informar ao PHP $c = 'a';- significa que esta é uma string com apenas 1 caractere. É por isso que U não pode executar um loop de 28 caracteres adequadamente no PHP. Espero que todos os programadores aprendam linguagens de baixo nível e digitação forte, sem esquecer as práticas de matemática, o que os ajudará a serem mais fortes.
Arthur Kushman
Wow que é muito legal, mas por que ele didnt parou em "z"
Prasanth Bendra
Para obter o ponto final esperado usando igualdade ( ==ou !=), verifique esta resposta a uma pergunta relacionada .
IMSoP 23/09

Respostas:

342

Dos documentos :

O PHP segue a convenção de Perl ao lidar com operações aritméticas em variáveis ​​de caracteres e não em Cs.

Por exemplo, em Perl se 'Z'+1transforma em 'AA', enquanto em C se 'Z'+1transforma em '['( ord('Z') == 90, ord('[') == 91).

Observe que as variáveis ​​de caracteres podem ser incrementadas, mas não decrementadas, e mesmo assim apenas os caracteres ASCII simples (az e AZ) são suportados.

De Comentários: -
Deve-se notar também que<=é uma comparação lexicográfica'z'+1 ≤ 'z'. (Desde então'z'+1 = 'aa' ≤ 'z'. Mas'za' ≤ 'z'é a primeira vez que a comparação é falsa.) Quebrar quando$i == 'z'funcionaria, por exemplo.

Exemplo aqui .

CMS
fonte
Hah ... isso é loucura! Eu sempre usei, ord()então nunca notei isso.
MPEN
68
Para completar, você também deve adicionar que "<=" é uma comparação lexicográfica, então 'z' + 1 ≤ 'z'. (Como 'z' + 1 = 'aa'≤'z'. Mas 'zz'≤'z' é a primeira vez que a comparação é falsa.) Quebrando quando $ i == 'z' funcionaria, por exemplo.
precisa
6
como ShreevatsaR está dizendo, é o comparador, não a aritmética que é o problema, não se concentrar em que o operador ++
SLF
10
@ShreevatsaR: na verdade, 'yz' + 1 = 'za'. A primeira comparação que falha é 'za' <= 'z'
Milan Babuškov 04/11/2010
2
Obrigado pelos comentários pessoal! Sim, o ponto principal é que 'aa'é lexicograficamente menor que 'z', é por isso que o loop continua. E pára 'yz'porque 'za'é maior que z. Veja este exemplo .
CMS
123

Como uma vez que 'z' é atingido (e este é um resultado válido dentro do seu intervalo, o $ i ++ o incrementa para o próximo valor em sequência), o próximo valor será 'aa'; alfabeticamente, 'aa' é <'z'; portanto, a comparação nunca é atendida

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 
Mark Baker
fonte
55
É estranho que 'z' ++ = 'aa', mas 'aa' <'z'. Essa lógica não flui muito bem.
Matthew Vines
19
@ Matthew: Alfabetize-os. 'aa' viria primeiro, portanto é "menor que" a string 'z'. O loop termina em 'zz' porque é alfabeticamente "maior que" (vem depois) 'z'. É ilógico no sentido em que você pode "incrementar" algo e obter um valor menor, mas é lógico no sentido alfabético.
precisa saber é o seguinte
2
O incrementador de caracteres é a lógica Perl (consulte a citação do CMS nos documentos). A comparação 'aa' <'z' é uma lógica de comparação de cadeias padrão. Não é estranho, uma vez que você entende como usá-lo ... pelas respostas aqui, muitas pessoas não.
Mark Baker
5
@eldarerathis Oh, eu definitivamente entendo como isso está funcionando. Eu acho estranho ao mesmo tempo.
Matthew Vines
2
É incrivelmente útil para mim, brincando com colunas do Excel que seguem as mesmas séries lógicas
Mark Baker
97

Outras respostas explicam o comportamento observado do código publicado. Aqui está uma maneira de fazer o que você deseja (e é um código mais limpo, IMO):

foreach (range('a', 'z') as $i)
    echo "$i\n";

Em resposta ao comentário / pergunta de ShreevatsaR sobre a função range : Sim, produz o "ponto final correto", isto é, os valores passados ​​para a função estão no range. Para ilustrar, a saída do código acima foi:

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
GreenMatt
fonte
2
Range () inclui o endpoint correto? Da experiência com outros idiomas, isso é inesperado também!
precisa
1
@ShreevatsaR: Sim, range () fornece o endpoint "correto", veja minha resposta editada (e siga o link para a função) para obter mais informações.
GreenMatt
1
O que posso dizer ... mais loucura em PHP. :-) Não há outro idioma que eu conheça, no qual range () funciona dessa maneira. (Certamente não, digamos, Haskell ou Python.) Dijkstra não escreveu algo sobre isso?
ShreevatsaR
10
Loucura está na inconsistência do PHP. range ('A', 'CZ') funciona de maneira totalmente diferente do incrementador ++, e o array resultante conterá apenas três valores: A, B e C.
Mark Baker
35

Outros já disseram por que o PHP não mostra o que você espera. Veja como você obtém o resultado que deseja:

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>
Filip Ekberg
fonte
2
Desnecessário. você não precisa fazer o ord () em tudo, apenas a comparação correta de encerrar o loop
Mark Baker
2
+1 Muito mais compreensível quando não estiver familiarizado com um dos recursos mais excêntricos do PHP.
Loneomeday
1
Este é um excelente exemplo de código de auto-documentação. É facilmente compreensível precisamente porque usa valores ordinais e exibe a variável como um caractere. O loop for seria mais eficiente se o teste para o valor máximo for determinado apenas uma vez da seguinte maneira: "for ($ i = ord ('a'), $ max = ord ('z'); $ i <= $ max; $ i ++) {"
slevy1
22

Por que não usar apenas range('a','z')?

bcosca
fonte
4

Experimente este código. Eu acho que esse código será útil para você.

$alphas = range('A', 'Z');
foreach($alphas as $value){
    echo $value."<br>";
}

Exiba 26 letras em sequência.

Chinmay235
fonte
2
<?php

$i = 'a';
do {
echo ($j=$i++),"\r\n";
} while (ord($j) < ord($i));

?>
Mr Griever
fonte
2

Também isso pode ser usado:

for ($i = 'a'; $i <= 'z'; $i=chr(ord($i)+1))
    echo "$i\n";
LRA
fonte
2

O PHP tem a função de repetir letras e pode exceder além de caracteres únicos; o resto será feito desta maneira: aa ab ac ... zz e assim por diante.

Tente o seguinte:

<?php
for ($i = 'a'; $i !== 'aa'; $i++)
    echo "$i\n";
?>
James Dantes
fonte
0

Embora as respostas acima sejam esclarecedoras sobre o que está acontecendo, e bastante interessantes (eu não sabia que se comportaria assim, é bom entender o porquê.

A correção mais fácil (embora talvez não seja a mais significativa) seria apenas alterar a condição para $ i! = 'Z'

<?php
for ($i = 'a'; $i != 'z'; $i++)  
    echo "$i\n";
?>
jon_darkstar
fonte
4
Note que isto só irá dar-lhe um de y, não z
Mark Baker
doh! sim, bom ponto. Eu posso ver a lógica por trás tanto o incremento e a comparação, mas com certeza é estranho que às vezes US $ a ++ <$ a
jon_darkstar
0

O PHP não considera 'AA' menor que 'Z'. A melhor maneira de fazer isso é:

for($i = 'a'; $i != 'aa'; $i++) {
  echo $i;
}

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

Renato Cassino
fonte
0

Talvez esse código funcione. É fácil e pode ser entendido:

<?php
$ascii_val = ord("a");
for($i=$ascii_val;$i<$ascii_val+26;$i++){
echo chr($i)."\n";
}
?>

onde 26 é o número total de letras no alfabeto.

Exceção
fonte
-3

Uau, eu realmente não sabia disso, mas não é um código grande, você pode tentar eco "z" após o loop Mark está absolutamente certo Eu uso o método dele, mas se você quiser alternativa, isso também pode ser possível

<?php
for ($i = "a"; $i = "y"; $i++) {
    echo "$i\n";
    if ($i == "z") {}
}
echo "z";
?>
Mohit Bumb
fonte