Почему этот код просто не печатает буквы от А до Я?

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

Этот фрагмент дает следующий вывод (новые строки заменяются пробелами):

abcdefghijklmnopqrstu vwxyz aa ab ac ad ae af ag ah ai aj ak al am a a ap 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 c c c c c c c c c c d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d dr ds dt du dv dw dx dy dz e e e e e e e e e e e e e e e e e e e e e e e e e e e e e ev ew ex... on to yz

  • 30
    PHP - это не C, даже если синтаксис пытается убедить вас в обратном.
  • 2
    Это работает для меня с очень небольшим изменением: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Показать ещё 5 комментариев
Теги:

13 ответов

337
Лучший ответ

Из docs:

PHP следует за соглашением Perl при работе с арифметическими операциями над символьными переменными, а не с C.

Например, в Perl 'Z'+1 превращается в 'AA', а в C 'Z'+1 превращается в '[' (ord('Z') == 90, ord('[') == 91).

Обратите внимание, что символьные переменные могут увеличиваться, но не уменьшаться, и даже поэтому поддерживаются только простые символы ASCII (a-z и A-Z).

От комментариев: -
Следует также отметить, что <= является лексикографическим сравнением, поэтому 'z'+1 ≤ 'z'. (Так как 'z'+1 = 'aa' ≤ 'z'. Но 'za' ≤ 'z' - это первый случай, когда сравнение ложно.) Разрыв, если $i == 'z' будет работать, например.

Пример здесь.

  • 0
    Ха ... это безумие! Я всегда использовал ord() поэтому никогда не замечал этого.
  • 67
    Для полноты следует также добавить, что «<=» является лексикографическим сравнением, поэтому «z» + 1 ≤ «z». (Так как 'z' + 1 = 'aa'≤'z'. Но 'zz'≤'z' - это первый раз, когда сравнение ложно.) Например, разрыв, когда $ i == 'z' сработает.
Показать ещё 4 комментария
113

Поскольку после достижения "z" (и это допустимый результат в вашем диапазоне, $i ++ увеличивает его до следующего значения в последовательности), следующее значение будет "aa"; и в алфавитном порядке, 'aa' 'z', поэтому сравнение никогда не выполняется

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 
  • 55
    Странно, что 'z' ++ = 'aa', но 'aa' <'z'. Эта логика течет не очень хорошо.
  • 19
    @ Матфея: алфавит их. «aa» будет первым, поэтому «меньше» строки «z». Цикл заканчивается на «zz», потому что в алфавитном порядке «больше, чем» (идет после) «z». Это нелогично в том смысле, что вы можете «увеличить» что-то и получить меньшее значение, но это логично в алфавитном смысле.
Показать ещё 11 комментариев
101

Другие ответы объясняют наблюдаемое поведение опубликованного кода. Вот один из способов сделать то, что вы хотите (и это более чистый код, IMO):

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

В ответ на комментарий/вопрос ShreevatsaR о функции range: Да, он создает "правую конечную точку", то есть пройденные значения к функции находятся в диапазоне. Чтобы проиллюстрировать, вывод из вышеуказанного кода был:

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 () включает в себя правильную конечную точку? Из опыта работы с другими языками это тоже неожиданно!
  • 1
    @ShreevatsaR: Да, range () дает «правильную» конечную точку, см. Мой отредактированный ответ (и перейдите по ссылке на функцию) для получения дополнительной информации.
Показать ещё 2 комментария
35

Другие уже сказали, почему PHP не показывает, чего вы ожидаете. Вот как вы получите результат, который вам может понадобиться:

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>
  • 2
    Ненужные. вам вообще не нужно выполнять ord (), только правильное сравнение для завершения цикла
  • 18
    @ Марк, я предпочитаю чистый и понятный код.
Показать ещё 2 комментария
22

Почему бы просто не использовать range('a','z')?

4

Попробуйте этот код. Я думаю, этот код будет вам полезен.

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

Отобразить 26 букв в последовательности.

2

Также это можно использовать:

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

PHP имеет функцию циклических букв и может превышать одиночные символы; остальное будет сделано следующим образом: aa ab ac... zz и т.д.

Попробуйте следующее:

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

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

?>
0

PHP не считает "AA" меньше, чем "Z". Лучший способ сделать это:

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

АБВГДЕЖЗИКЛМНОПРСТУФХЧШЭЮЯ

0

Возможно, этот код будет работать. Его легко понять и понять:

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

где 26 - общее количество букв в алфавите.

0

В то время как вышеупомянутые ответы проницательны в том, что происходит, и довольно интересны (я не знал, что это будет вести себя так, и это хорошо, чтобы понять, почему.

Самое простое исправить (хотя, возможно, и не самое значимое) было бы просто изменить условие на $i!= 'z'

<?php
for ($i = 'a'; $i != 'z'; $i++)  
    echo "$i\n";
?>
  • 4
    Обратите внимание, что это даст вам только Y, а не Z
  • 0
    DOH! да, хорошая мысль. Я вижу логику как приращения, так и сравнения, но странно, что иногда $ a ++ <$ a
-4

Ничего себе, я действительно не знал об этом, но его не большой код, который вы можете попробовать echo "z" после цикла. Марк абсолютно прав. Я использую его метод, но если вам нужна альтернатива, тогда вы также можете попробовать

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню