Perché questo codice non stampa semplicemente le lettere dalla A alla Z?


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

Questo frammento fornisce il seguente output (le nuove righe sono sostituite da spazi):

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 di 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 es. eh ei ej ek el em en eo ep eq er es et eu ev ew ex ... on to yz


31
PHP non è C, anche se la sintassi cerca di convincerti del contrario.
joni,

3
Questo funziona per me con una piccola modifica: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Surreal Dreams il

2
Il commento a proposito del fatto che PHP non è C - era l'esempio più acuto: in c: char c = 'a'; non è lo stesso di php: $c = 'a';il punto è che in C c'è un tipo di carattere (simbolo del carattere 1), ma non in PHP, se U dice a PHP $c = 'a';- significa che questa è una stringa con solo 1 carattere. Ecco perché U non è in grado di riprodurre in modo adeguato 28 caratteri in PHP. Spero che ogni programmatore imparerà lingue di basso livello e digitazione forte insieme ad esso, senza dimenticare le pratiche matematiche, che li aiuteranno a essere più forti.
Arthur Kushman,

Wow, è davvero bello, ma perché non si è fermato a "z"
Prasanth Bendra,

Per un modo per ottenere l'end-point previsto usando l'uguaglianza ( ==o !=) controlla questa risposta a una domanda correlata .
IMSoP,

Risposte:


342

Dai documenti :

PHP segue la convenzione di Perl quando si tratta di operazioni aritmetiche su variabili di carattere e non di C.

Ad esempio, in Perl 'Z'+1si trasforma in 'AA', mentre in C 'Z'+1si trasforma in '['( ord('Z') == 90, ord('[') == 91).

Si noti che le variabili di carattere possono essere incrementate ma non decrementate e anche così sono supportati solo caratteri ASCII semplici (az e AZ).

Dai commenti: -
Va anche notato che<=è un confronto lessicografico, quindi'z'+1 ≤ 'z'. (Da allora'z'+1 = 'aa' ≤ 'z'. Ma'za' ≤ 'z'è la prima volta che il confronto è falso.) Rompere quando$i == 'z'funzionerebbe, per esempio.

Esempio qui .


Hah ... è pazzesco! L'ho sempre usato, ord()quindi non l'ho mai notato.
Aprire il

68
Per completezza, dovresti anche aggiungere che "<=" è un confronto lessicografico, quindi 'z' + 1 ≤ 'z'. (Dato che 'z' + 1 = 'aa'≤'z'. Ma 'zz'≤'z' è la prima volta che il confronto è falso.) Rompere quando $ i == 'z' funzionerebbe, per esempio.
ShreevatsaR,

6
come dice ShreevatsaR, è il comparatore, non l'aritmetica che è il problema, non concentrarti sull'operatore ++
slf

10
@ShreevatsaR: in realtà, 'yz' + 1 = 'za'. Il primo confronto che fallisce è 'za' <= 'z'
Milan Babuškov

2
Grazie per i commenti ragazzi! Sì, il punto chiave è che 'aa'è lessicograficamente più piccolo di 'z', ecco perché il ciclo continua. E si ferma 'yz'perché 'za'è maggiore di z. Guarda questo esempio .
CMS

123

Perché una volta che 'z' viene raggiunto (e questo è un risultato valido all'interno dell'intervallo, $ i ++ lo incrementa al valore successivo in sequenza), il valore successivo sarà 'aa'; e in ordine alfabetico, 'aa' è <'z', quindi il confronto non è mai soddisfatto

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 

55
È strano che 'z' ++ = 'aa', ma 'aa' <'z'. Questa logica non scorre molto bene.
Matthew Vines,

19
@Matthew: alfabetizzali. 'aa' verrebbe per primo, quindi è "meno di" la stringa "z". Il ciclo termina in 'zz' perché è alfabeticamente "maggiore di" (segue) 'z'. È illogico nel senso che puoi "incrementare" qualcosa e ottenere un valore minore, ma è logico in senso alfabetico.
eldarerathis,

2
L'incremento del carattere è la logica Perl (vedere la citazione di CMS dalla documentazione). Il confronto 'aa' <'z' è una logica di confronto delle stringhe standard. Non strano, una volta capito come usarlo ... dalle risposte qui, molte persone non lo fanno.
Mark Baker,

5
@eldarerathis Oh, ho capito bene come funziona. Lo trovo strano allo stesso tempo.
Matthew Vines,

2
È incredibilmente utile per me, giocare con le colonne di Excel che seguono la stessa serie logica
Mark Baker

97

Altre risposte spiegano il comportamento osservato del codice pubblicato. Ecco un modo per fare quello che vuoi (ed è un codice più pulito, IMO):

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

In risposta al commento / domanda di ShreevatsaR sulla funzione intervallo : Sì, produce "endpoint corretto", ovvero i valori passati alla funzione sono compresi nell'intervallo. Per illustrare, l'output del codice precedente era:

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

2
Range () include l'endpoint giusto? Dall'esperienza con altre lingue, anche questo è inaspettato!
ShreevatsaR,

1
@ShreevatsaR: Sì, range () fornisce l'endpoint "giusto", vedere la mia risposta modificata (e seguire il collegamento alla funzione) per ulteriori informazioni.
GreenMatt

1
Cosa posso dire ... più follia PHP. :-) Non c'è altra lingua che conosca in quale range () funziona in questo modo. (Certamente no, diciamo, Haskell o Python.) Dijkstra non ha scritto qualcosa al riguardo?
ShreevatsaR,

10
La follia è nell'incongruenza di PHP. range ('A', 'CZ') funziona in modo totalmente diverso dall'incremento ++ e l'array risultante conterrà solo tre valori: A, B e C.
Mark Baker,

35

Altri hanno già detto perché PHP non mostra ciò che ti aspetti. Ecco come ottieni il risultato che potresti desiderare:

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>

2
Non necessario. non è necessario eseguire ord (), solo il confronto corretto per terminare il ciclo
Mark Baker

2
+1 Molto più comprensibile quando non si ha familiarità con una delle caratteristiche più eccentriche di PHP.
lunedì

1
Questo è un eccellente esempio di codice auto-documentante. È facilmente comprensibile proprio perché usa valori ordinali e quindi visualizza la variabile come carattere. Il ciclo for sarebbe più efficiente se il test per il valore massimo viene determinato una sola volta come segue: "per ($ i = ord ('a'), $ max = ord ('z'); $ i <= $ max; $ i ++) {"
slevy1


4

Prova questo codice. Penso che questo codice ti sarà utile.

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

Visualizza 26 lettere in sequenza.


2
<?php

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

?>

2

Anche questo può essere usato:

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

2

PHP ha la funzione di eseguire il loop di lettere e può superare i singoli caratteri; il resto sarà fatto in questo modo: aa ab ac ... zz e così via.

Prova questo:

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

0

Mentre le risposte di cui sopra sono approfondite su ciò che sta succedendo e piuttosto interessanti (non sapevo che si sarebbe comportato in questo modo, ed è bello vedere perché.

La soluzione più semplice (anche se forse non la più significativa) sarebbe solo quella di cambiare la condizione in $ i! = 'Z'

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

4
Nota che questo ti darà solo un a y, non z
Mark Baker

doh! sì, buon punto. Riesco a vedere la logica dietro sia l'incremento che il confronto, ma è certo strano che a volte $ a ++ <$ a
jon_darkstar

0

Il PHP non considera "AA" inferiore a "Z". Il modo migliore per farlo è:

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

abcdefghijklmnopqrstuvwxyz


0

Forse questo codice funzionerà. È facile e può essere compreso:

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

dove 26 è il numero totale di lettere dell'alfabeto.


-3

Wow, davvero non lo sapevo, ma non è un grosso codice, puoi provare echo "z" dopo che il ciclo Mark è assolutamente giusto, uso il suo metodo, ma se vuoi un'alternativa, puoi provare anche questo

<?php
for ($i = "a"; $i = "y"; $i++) {
    echo "$i\n";
    if ($i == "z") {}
}
echo "z";
?>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.