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

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

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

abcdefghijklmnopqrstu vwxyz аааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааенностьенность в представлении BF BG BH BH B B B B B B B B B B B B B B B B B B B B B B B B B B B B В БВ. bw bx by 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 да db dc dd de df dg dh di dj dk dl dm dn do dp dq dr ds dt du dv dx dy dz ea eb ee ef, например, ej ej ek eme en epo eq es es eu evw eew ew ej

Милан Бабушков
источник
31
PHP - это не C, даже если синтаксис пытается убедить вас в обратном.
Джони
3
Это работает для меня с очень небольшим изменением: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
Surreal Dreams
2
Комментарий о том, что PHP - это не C - был самым ярким примером: in c: char c = 'a'; это не то же самое, что в php:, $c = 'a';дело в том, что в C есть тип char (символ символа 1), но не в PHP, если U говорит PHP $c = 'a';- означает, что это строка с одним символом. Вот почему вы не можете перебрать 28 символов в PHP. Я надеюсь, что каждый программист будет изучать языки низкого уровня и строгую типизацию вместе с ним, не забывая о математических практиках, которые помогут им стать сильнее.
Артур Кушман
Ничего себе, это действительно круто, но почему это не остановилось на "z"
Prasanth Bendra
Чтобы получить ожидаемую конечную точку с помощью равенства ( ==или !=), проверьте этот ответ на связанный вопрос .
IMSoP

Ответы:

342

Из документов :

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

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

Обратите внимание, что символьные переменные можно увеличивать, но не уменьшать, и даже в этом случае поддерживаются только простые символы ASCII (az и AZ).

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

Пример тут .

CMS
источник
Ха ... это безумие! Я всегда использовал, ord()поэтому я никогда не замечал этого.
mpen
68
Для полноты следует также добавить, что «<=» является лексикографическим сравнением, поэтому «z» + 1 ≤ «z». (Так как 'z' + 1 = 'aa'≤'z'. Но 'zz'≤'z' - это первый раз, когда сравнение ложно.) Например, разрыв, когда $ i == 'z' сработает.
ShreevatsaR
6
как говорит ShreevatsaR, проблема в компараторе, а не в арифметике, не сосредотачивайтесь на операторе ++
slf
10
@ShreevatsaR: на самом деле, 'yz' + 1 = 'za'. Первое неудачное сравнение - «za» <= 'z'
Милан Бабушков
2
Спасибо за комментарии, ребята! Да, ключевой момент в том, что 'aa'он лексикографически меньше 'z', поэтому цикл продолжается. И это останавливается, 'yz'потому что 'za'больше, чем z. Проверьте этот пример .
CMS
123

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

for ($i = 'a'; $i != 'aa'; $i++) 
    echo "$i\n"; 
Марк Бейкер
источник
55
Странно, что 'z' ++ = 'aa', но 'aa' <'z'. Эта логика течет не очень хорошо.
Мэтью Вайнс
19
@ Матфея: алфавит их. «aa» будет первым, поэтому «меньше» строки «z». Цикл заканчивается на «zz», потому что в алфавитном порядке «больше чем» (идет после) «z». Это нелогично в том смысле, что вы можете «увеличить» что-то и получить меньшее значение, но это логично в алфавитном смысле.
eldarerathis
2
Инкремент символа - это логика Perl (см. Цитату CMS из документации). Сравнение 'aa' <'z' является стандартной логикой сравнения строк. Не странно, как только вы поймете, как это использовать ... из ответов здесь, многие люди этого не делают.
Марк Бейкер
5
@eldarerathis О, я определенно понимаю, как это работает. Я просто нахожу это странным в то же время.
Мэтью Вайнс
2
Это невероятно полезно для меня, играть с колонками Excel, которые следуют той же логической серии
Марк Бейкер
97

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

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

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

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
источник
2
Включает ли range () правильную конечную точку? Из опыта работы с другими языками это тоже неожиданно!
ShreevatsaR
1
@ShreevatsaR: Да, range () дает «правильную» конечную точку, см. Мой отредактированный ответ (и перейдите по ссылке на функцию) для получения дополнительной информации.
GreenMatt
1
Что я могу сказать ... больше PHP безумие. :-) Я не знаю другого языка, на котором range () работает таким образом. (Конечно, нет, скажем, Haskell или Python.) Разве Дейкстра не написал что-нибудь об этом?
ShreevatsaR
10
Безумие в несостоятельности PHP. range ('A', 'CZ') работает совершенно иначе, чем инкрементатор ++, и результирующий массив будет просто содержать три значения: A, B и C.
Марк Бейкер
35

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

<?php
for ($i = ord('a'); $i <= ord('z'); $i++)
    echo chr($i);
?>
Филип Экберг
источник
2
Ненужные. вам вообще не нужно выполнять ord (), только правильное сравнение, чтобы завершить цикл
Марк Бейкер
2
+1 Гораздо понятнее, когда не знаком с одной из наиболее эксцентричных функций PHP.
одинокий
1
Это отличный пример самодокументируемого кода. Это легко понять точно, потому что он использует порядковые значения и затем отображает переменную как символ. Цикл for был бы более эффективным, если бы тест на максимальное значение определялся только один раз следующим образом: «for ($ i = ord ('a'), $ max = ord ('z'); $ i <= $ max; $ i ++) {"
slevy1
22

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

bcosca
источник
4

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

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

Покажите 26 букв в последовательности.

Chinmay235
источник
2
<?php

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

?>
Мистер гривер
источник
2

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

for ($i = 'a'; $i <= 'z'; $i=chr(ord($i)+1))
    echo "$i\n";
LRA
источник
2

PHP имеет функцию зацикливания букв и может превышать отдельные символы; остальное будет сделано так: аааааааааа ... и т. д.

Попробуй это:

<?php
for ($i = 'a'; $i !== 'aa'; $i++)
    echo "$i\n";
?>
Джеймс Дантес
источник
0

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

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

<?php
for ($i = 'a'; $i != 'z'; $i++)  
    echo "$i\n";
?>
jon_darkstar
источник
4
Обратите внимание, что это даст вам только y, а не z
Марк Бейкер
DOH! да, хорошая мысль. Я вижу логику увеличения и сравнения, но странно, что иногда $ a ++ <$ a
jon_darkstar
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 - общее количество букв в алфавите.

исключение
источник
-3

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

<?php
for ($i = "a"; $i = "y"; $i++) {
    echo "$i\n";
    if ($i == "z") {}
}
echo "z";
?>
Мохит Бумб
источник