Pourquoi ce code n'imprime-t-il pas simplement les lettres A à Z?

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

Cet extrait donne la sortie suivante (les retours à la ligne sont remplacés par des espaces):

abcdefghijklmnopqrstu vwxyz 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 par 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 ... on to yz

Milan Babuškov
la source
31
PHP n'est pas C, même si la syntaxe essaie de vous convaincre du contraire.
joni
3
Cela fonctionne pour moi avec un tout petit changement: pour ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Surreal Dreams
2
Le commentaire sur le fait que PHP n'est pas C - était le plus vif, par exemple: dans c: char c = 'a'; n'est pas le même que dans php:, $c = 'a';le fait est qu'en C il y a un type de char (symbole de caractère 1), mais pas en PHP, si U dit à PHP $c = 'a';- signifie que c'est une chaîne avec seulement 1 caractère. C'est pourquoi U ne peut pas boucler correctement 28 caractères en PHP. J'espère que chaque programmeur apprendra les langages de bas niveau et le typage fort avec lui, sans oublier les pratiques mathématiques, qui les aideront à être plus forts.
Arthur Kushman
Wow c'est vraiment cool, mais pourquoi cela ne s'est pas arrêté à "z"
Prasanth Bendra
Pour obtenir un moyen d'obtenir le point final attendu en utilisant l'égalité ( ==ou !=) consultez cette réponse à une question connexe .
IMSoP

Réponses:

342

De la documentation :

PHP suit la convention de Perl lorsqu'il s'agit d'opérations arithmétiques sur des variables de caractère et non de C.

Par exemple, en Perl se 'Z'+1transforme en 'AA', tandis qu'en C 'Z'+1se transforme en '['( ord('Z') == 90, ord('[') == 91).

Notez que les variables de caractères peuvent être incrémentées mais pas décrémentées et même ainsi, seuls les caractères ASCII simples (az et AZ) sont pris en charge.

Des commentaires: -
Il convient également de noter qu'il<=s'agit d'une comparaison lexicographique, donc'z'+1 ≤ 'z'. (Depuis'z'+1 = 'aa' ≤ 'z'. Mais'za' ≤ 'z'c'est la première fois que la comparaison est fausse.) Rompre quand$i == 'z'fonctionnerait, par exemple.

Exemple ici .

CMS
la source
Hah..c'est fou! Je l'ai toujours utilisé ord()donc je ne l'ai jamais remarqué.
mpen
68
Pour être complet, vous devez également ajouter que "<=" est une comparaison lexicographique, donc 'z' + 1 ≤ 'z'. (Puisque 'z' + 1 = 'aa'≤'z'. Mais 'zz'≤'z' est la première fois que la comparaison est fausse.) Briser quand $ i == 'z' fonctionnerait, par exemple.
ShreevatsaR
6
comme le dit ShreevatsaR, c'est le comparateur, pas l'arithmétique qui
pose
10
@ShreevatsaR: en fait, 'yz' + 1 = 'za'. La première comparaison qui échoue est 'za' <= 'z'
Milan Babuškov
2
Merci pour les commentaires, les gens! Oui, le point clé est que lexicographiquement'aa' est plus petit que , c'est pourquoi la boucle continue. Et ça s'arrête parce que c'est plus grand que . Vérifiez cet exemple . 'z''yz''za'z
CMS
123

Parce qu'une fois que «z» est atteint (et que c'est un résultat valide dans votre plage, $ i ++ l'incrémente à la valeur suivante en séquence), la valeur suivante sera «aa»; et par ordre alphabétique, 'aa' est <'z', donc la comparaison n'est jamais rencontrée

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 
Mark Baker
la source
55
Il est étrange que 'z' ++ = 'aa', mais 'aa' <'z'. Cette logique ne coule pas très bien.
Matthew Vines
19
@Matthew: Alphabétisez-les. 'aa' viendrait en premier, c'est donc "moins que" la chaîne 'z'. La boucle se termine à 'zz' car elle est alphabétiquement "supérieure à" (vient après) 'z'. C'est illogique dans le sens où vous pouvez "incrémenter" quelque chose et obtenir une valeur moindre, mais c'est logique dans un sens alphabétique.
eldarerathis
2
L'incrémenteur de caractères est la logique Perl (voir la citation du CMS dans la documentation). La comparaison «aa» <«z» est une logique de comparaison de chaînes standard. Pas étrange, une fois que vous comprenez comment l'utiliser ... d'après les réponses ici, beaucoup de gens ne le savent pas.
Mark Baker
5
@eldarerathis Oh, je comprends vraiment comment cela fonctionne. Je trouve ça bizarre en même temps.
Matthew Vines
2
C'est incroyablement utile pour moi, en jouant avec les colonnes Excel qui suivent la même série logique
Mark Baker
97

D'autres réponses expliquent le comportement observé du code publié. Voici une façon de faire ce que vous voulez (et c'est un code plus propre, IMO):

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

En réponse au commentaire / question de ShreevatsaR sur la fonction de plage : Oui, il produit le «point final droit», c'est-à-dire que les valeurs transmises à la fonction sont dans la plage. Pour illustrer, la sortie du code ci-dessus était:

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
la source
2
Range () inclut-il le bon point de terminaison? De l'expérience avec d'autres langues, c'est aussi inattendu!
ShreevatsaR
1
@ShreevatsaR: Oui, range () donne le "bon" point de terminaison, voir ma réponse modifiée (et suivez le lien vers la fonction) pour plus d'informations.
GreenMatt
1
Que puis-je dire… plus de folie PHP. :-) Je ne connais pas d'autre langue dans laquelle range () fonctionne de cette façon. (Certainement pas, disons, Haskell ou Python.) Dijkstra n'a-t-il pas écrit quelque chose à ce sujet?
ShreevatsaR
10
La folie est dans l'incohérence de PHP. range ('A', 'CZ') fonctionne totalement différemment de l'incrémenteur ++, et le tableau résultant contiendra juste trois valeurs: A, B et C.
Mark Baker
35

D'autres ont déjà expliqué pourquoi PHP ne montre pas ce que vous attendez. Voici comment vous obtenez le résultat souhaité:

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>
Filip Ekberg
la source
2
Inutile. vous n'avez pas du tout besoin de faire l'ord (), juste la comparaison correcte pour terminer la boucle
Mark Baker
2
+1 Beaucoup plus compréhensible lorsqu'il n'est pas familier avec l'une des fonctionnalités les plus excentriques de PHP.
lonesomeday
1
Ceci est un excellent exemple de code auto-documenté. Il est facilement compréhensible avec précision car il utilise des valeurs ordinales et affiche ensuite la variable sous forme de caractère. La boucle for serait plus efficace si le test de la valeur maximale n'est déterminé qu'une seule fois comme suit: "for ($ i = ord ('a'), $ max = ord ('z'); $ i <= $ max; $ i ++) {"
slevy1
22

Pourquoi ne pas simplement utiliser range('a','z')?

bcosca
la source
4

Essayez ce code. Je pense que ce code vous sera utile.

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

Affichez 26 lettres en séquence.

Chinmay235
la source
2
<?php

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

?>
Mr Griever
la source
2

Cela peut également être utilisé:

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

PHP a la fonction de boucler les lettres et peut dépasser les simples caractères; le reste se fera de cette façon: aa ab ac ... zz, etc.

Essaye ça:

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

Bien que les réponses ci-dessus donnent un aperçu de ce qui se passe et soient assez intéressantes (je ne savais pas que cela se comporterait comme ça, et c'est bien de voir pourquoi.

La solution la plus simple (mais peut-être pas la plus significative) serait simplement de changer la condition en $ i! = 'Z'

<?php
for ($i = 'a'; $i != 'z'; $i++)  
    echo "$i\n";
?>
jon_darkstar
la source
4
Notez que cela vous donnera seulement un à y, pas z
Mark Baker
doh! oui, bon point. Je peux voir la logique derrière à la fois l'incrément et la comparaison, mais il est certainement étrange que parfois $ a ++ <$ a
jon_darkstar
0

Le PHP ne considère pas «AA» moins que «Z». La meilleure façon de procéder est:

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

abcdefghijklmnopqrstuvwxyz

Renato Cassino
la source
0

Peut-être que ce code fonctionnera. C'est facile et peut être compris:

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

où 26 est le nombre total de lettres de l'alphabet.

Exception
la source
-3

Wow, je ne savais vraiment pas à ce sujet, mais ce n'est pas un gros code, vous pouvez essayer l'écho "z" après la boucle Mark est tout à fait raison J'utilise sa méthode mais si vous voulez une alternative, cela peut aussi vous pouvez essayer

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