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


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'Например, когда будет работать.

Пример тут .


Ха ... это безумие! Я всегда использовал, 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

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


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 имеет функцию зацикливания букв и может превышать отдельные символы; остальное будет сделано так: аааааааааа ... и т. д.

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

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

0

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

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

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

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";
?>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.