Warum druckt dieser Code nicht einfach die Buchstaben A bis Z?

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

Dieses Snippet gibt die folgende Ausgabe aus (Zeilenumbrüche werden durch Leerzeichen ersetzt):

abcdefghijklmnopqrstu vwxyz aa ab ac ad ae af ag ah ai aj ak al am ao ap aq ar wie bei au av aw ax ay az ba bb bc bd bf bg bh bi bj bk bl bm bn bo bp bq b bs bu bv bw bx von 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 dj dk dl dm dn dp dq dr ds dt du dv dw dx dy dz ea eb ec ed ee ef zB eh ei ej ek el em en eo ep eq er es eu ev ew ex ... on to yz

Milan Babuškov
quelle
31
PHP ist nicht C, auch wenn die Syntax versucht, Sie vom Gegenteil zu überzeugen.
Joni
3
Dies funktioniert bei mir mit einer sehr kleinen Änderung: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Surreal Dreams
2
Der Kommentar zu diesem PHP ist nicht C - war der schärfste, Beispiel: in c: char c = 'a'; ist nicht dasselbe wie in php : $c = 'a';, der Punkt ist, dass es in C einen Char-Typ (Zeichen 1-Symbol) gibt, aber nicht in PHP, wenn Sie PHP mitteilen $c = 'a';- bedeutet, dass dies eine Zeichenfolge mit nur 1 Zeichen ist. Aus diesem Grund kann U 28 Zeichen in PHP nicht ausreichend durchlaufen. Ich hoffe, dass jeder Programmierer Low-Level-Sprachen und starkes Tippen lernen wird, ohne dabei die mathematischen Praktiken zu vergessen, die ihm helfen, stärker zu werden.
Arthur Kushman
Wow das ist wirklich cool, aber warum hat es nicht bei "z" aufgehört
Prasanth Bendra
Um den erwarteten Endpunkt mithilfe von Gleichheit ( ==oder !=) zu ermitteln, lesen Sie diese Antwort auf eine verwandte Frage .
IMSoP

Antworten:

342

Aus den Dokumenten :

PHP folgt der Perl-Konvention, wenn es um arithmetische Operationen mit Zeichenvariablen und nicht mit C geht.

Zum Beispiel wird in Perl 'Z'+1zu 'AA', während in C 'Z'+1zu '['( ord('Z') == 90, ord('[') == 91) wird.

Beachten Sie, dass Zeichenvariablen inkrementiert, aber nicht dekrementiert werden können und trotzdem nur einfache ASCII-Zeichen (az und AZ) unterstützt werden.

Aus Kommentaren: -
Es sollte auch beachtet werden, dass<=es sich um einen lexikografischen Vergleich handelt'z'+1 ≤ 'z'. (Seit'z'+1 = 'aa' ≤ 'z'. Aber'za' ≤ 'z'ist das erste Mal, dass der Vergleich falsch ist.) Brechen, wann$i == 'z'zum Beispiel funktionieren würde.

Beispiel hier .

CMS
quelle
Hah ... das ist verrückt! Ich habe es immer benutzt, ord()also habe ich es nie bemerkt.
Mpen
68
Der Vollständigkeit halber sollten Sie auch hinzufügen, dass "<=" ein lexikographischer Vergleich ist, also 'z' + 1 ≤ 'z'. (Da 'z' + 1 = 'aa'≤'z'. Aber 'zz'≤'z' ist das erste Mal, dass der Vergleich falsch ist.) Unterbrechen, wenn beispielsweise $ i == 'z' funktionieren würde.
ShreevatsaR
6
Wie ShreevatsaR sagt, ist es der Komparator, nicht die Arithmetik, die das Problem ist. Konzentrieren Sie sich nicht auf den ++
slf
10
@ShreevatsaR: Eigentlich 'yz' + 1 = 'za'. Der erste Vergleich, der fehlschlägt, ist 'za' <= 'z'
Milan Babuškov
2
Danke für die Kommentare Jungs! Ja, der entscheidende Punkt ist , dass 'aa'ist lexikographisch kleiner als 'z'das ist , warum die Schleife wird fortgesetzt. Und es hört auf, 'yz'weil 'za'größer als ist z. Überprüfen Sie dieses Beispiel .
CMS
123

Sobald 'z' erreicht ist (und dies ein gültiges Ergebnis in Ihrem Bereich ist, erhöht $ i ++ es auf den nächsten Wert in Folge), ist der nächste Wert 'aa'; und alphabetisch ist 'aa' <'z', so dass der Vergleich nie erfüllt wird

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 
Mark Baker
quelle
55
Es ist seltsam, dass 'z' ++ = 'aa', aber 'aa' <'z'. Diese Logik fließt nicht sehr gut.
Matthew Vines
19
@ Matthew: Alphabetisiere sie. 'aa' würde an erster Stelle stehen, daher ist es "kleiner als" die Zeichenfolge 'z'. Die Schleife endet bei 'zz', weil sie alphabetisch "größer als" (kommt nach) 'z' ist. Es ist unlogisch in dem Sinne, dass man etwas "inkrementieren" und einen geringeren Wert erhalten kann, aber es ist in alphabetischer Hinsicht logisch.
Eldarerathis
2
Der Zeicheninkrementor ist die Perl-Logik (siehe CMS-Zitat aus den Dokumenten). Der Vergleich 'aa' <'z' ist eine Standard-String-Vergleichslogik. Nicht seltsam, wenn Sie erst einmal verstanden haben, wie man es benutzt ... aus den Antworten hier geht hervor, dass viele Leute es nicht tun.
Mark Baker
5
@eldarerathis Oh, ich verstehe definitiv, wie es funktioniert. Ich finde es einfach seltsam zur gleichen Zeit.
Matthew Vines
2
Es ist unglaublich nützlich für mich, mit Excel-Spalten herumzuspielen, die der gleichen logischen Reihe folgen
Mark Baker
97

Andere Antworten erklären das beobachtete Verhalten des veröffentlichten Codes. Hier ist eine Möglichkeit, das zu tun, was Sie wollen (und es ist sauberer Code, IMO):

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

Antwort auf ShreevatsaRs Kommentar / Frage zur Bereichsfunktion : Ja, es wird der "richtige Endpunkt" erzeugt, dh die an die Funktion übergebenen Werte liegen im Bereich. Zur Veranschaulichung lautete die Ausgabe des obigen Codes:

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
quelle
2
Enthält range () den richtigen Endpunkt? Aus Erfahrung mit anderen Sprachen ist das auch unerwartet!
ShreevatsaR
1
@ShreevatsaR: Ja, range () gibt den "richtigen" Endpunkt an. Weitere Informationen finden Sie in meiner bearbeiteten Antwort (und folgen Sie dem Link zur Funktion).
GreenMatt
1
Was soll ich sagen ... mehr PHP-Wahnsinn. :-) Ich kenne keine andere Sprache, in der range () so funktioniert. (Sicher nicht, sagen wir, Haskell oder Python.) Hat Dijkstra nicht etwas darüber geschrieben?
ShreevatsaR
10
Wahnsinn liegt in der Inkonsistenz von PHP. Der Bereich ('A', 'CZ') funktioniert völlig anders als der ++ - Inkrementor, und das resultierende Array enthält nur drei Werte: A, B und C.
Mark Baker
35

Andere haben bereits gesagt, warum PHP nicht zeigt, was Sie erwarten. So erhalten Sie das gewünschte Ergebnis:

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>
Filip Ekberg
quelle
2
Nicht notwendig. Sie müssen das ord () überhaupt nicht ausführen, nur den richtigen Vergleich, um die Schleife zu beenden
Mark Baker
2
+1 Viel verständlicher, wenn Sie mit einer der exzentrischeren Funktionen von PHP nicht vertraut sind.
einsamer
1
Dies ist ein hervorragendes Beispiel für selbstdokumentierenden Code. Es ist leicht verständlich, genau weil es Ordnungswerte verwendet und dann die Variable als Zeichen anzeigt. Die for-Schleife wäre effizienter, wenn der Test für den Maximalwert nur einmal wie folgt bestimmt würde: "für ($ i = ord ('a'), $ max = ord ('z'); $ i <= $ max; $ i ++) {"
slevy1
22

Warum nicht einfach benutzen range('a','z')?

bcosca
quelle
4

Versuchen Sie diesen Code. Ich denke, dieser Code wird Ihnen hilfreich sein.

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

26 Buchstaben nacheinander anzeigen.

Chinmay235
quelle
2
<?php

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

?>
Herr Griever
quelle
2

Auch dies kann verwendet werden:

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

PHP hat die Funktion, Buchstaben zu schleifen und kann über einzelne Zeichen hinausgehen. Der Rest wird auf diese Weise erledigt: aa ab ac ... zz und so weiter.

Versuche dies:

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

Die obigen Antworten sind zwar aufschlussreich und ziemlich interessant (ich wusste nicht, dass es sich so verhalten würde, und es ist gut zu sehen, warum.

Die einfachste Lösung (obwohl vielleicht nicht die sinnvollste) wäre, die Bedingung in $ i! = 'Z' zu ändern.

<?php
for ($i = 'a'; $i != 'z'; $i++)  
    echo "$i\n";
?>
jon_darkstar
quelle
4
Beachten Sie, dass dies nur a bis y gibt, nicht z
Mark Baker
doh! Ja, guter Punkt. Ich kann die Logik sowohl hinter dem Inkrement als auch dem Vergleich sehen, aber es ist sicher seltsam, dass manchmal $ a ++ <$ a
jon_darkstar
0

Das PHP betrachtet 'AA' nicht als kleiner als 'Z'. Der beste Weg, dies zu machen, ist:

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

abcdefghijklmnopqrstuvwxyz

Renato Cassino
quelle
0

Vielleicht funktioniert dieser Code. Es ist einfach und kann verstanden werden:

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

Dabei ist 26 die Gesamtzahl der Buchstaben im Alphabet.

Ausnahme
quelle
-3

Wow, ich wusste wirklich nichts darüber, aber es ist kein großer Code, den Sie versuchen können. Echo "z" nach Schleife Mark ist absolut richtig. Ich verwende seine Methode, aber wenn Sie eine Alternative wollen, können Sie dies auch versuchen

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