Чому цей код не просто друкує букви від А до Я?


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

Цей фрагмент дає такий результат (нові рядки замінюються пробілами):

abcdefghijklmnopqrstu vwxyz aa ab ac ad ae af ag ах ai aj ak al am 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 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 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 eg eh ei ej ek el em en eo ep eq er es et eu ev ew ex ... on to yz


31
PHP не є C, навіть якщо синтаксис намагається переконати вас у зворотному.
joni

3
Це працює для мене з дуже невеликою зміною: for ($ i = 'a'; $ i! = 'Aa'; $ i ++) {echo "$ i \ n"; }
сюрреалістичні мрії

2
Коментар про те, що PHP - це не C - був самим гострим, наприклад: in c: char c = 'a'; не те саме, що в php:, $c = 'a';справа в тому, що в C є тип char (символ 1 символу), але не в PHP, якщо U сказати PHP $c = 'a';- це означає, що це рядок всього з 1 символом. Ось чому U не може пройти цикл через 28 символів адекватно в PHP. Я сподіваюся, що кожен програміст вивчить мови низького рівня та сильно набирає текст разом із ним, не забуваючи про методи математики, які допоможуть їм стати сильнішими.
Артур Кушман

Вау, це дійсно круто, але чому він не зупинився на "z"
Прасант Бендра

Для способу отримання очікуваної кінцевої точки за допомогою рівності ( ==або !=) ознайомтеся з цією відповіддю на відповідне запитання .
IMSoP

Відповіді:


342

З документів :

PHP дотримується конвенції Perl, коли має справу з арифметичними операціями на змінних символів, а не на C.

Наприклад, у 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()тому цього ніколи не помічав.
квітня

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
@Matthew: Алфавітуйте їх. '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
Чи включає діапазон () правильну кінцеву точку? З досвіду роботи з іншими мовами, це теж несподівано!
ShreevatsaR

1
@ShreevatsaR: Так, діапазон () дає "правильну" кінцеву точку, див. Мою відредаговану відповідь (і перейдіть за посиланням на функцію) для отримання додаткової інформації.
GreenMatt

1
Що я можу сказати ... більше PHP божевілля. :-) Немає іншої мови, яку я знаю, в якому діапазоні () працює так. (Звичайно, ні, скажімо, Хаскелл чи Пітон.) Чи Діккстра щось не написав про це?
ShreevatsaR

10
Божевілля полягає в неузгодженості PHP. діапазон ('A', 'CZ') працює зовсім по-іншому з приростом ++, і отриманий масив буде просто містити три значення: A, B і C.
Mark Baker

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 має функцію циклічного використання літер і може перевищувати окремі символи; решта буде зроблено так: aa ab ac ... zz тощо.

Спробуйте це:

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

0

Хоча наведені вище відповіді добре розуміють, що відбувається, і досить цікаві (я не знав, що так поводитиметься, і добре зрозуміти, чому.

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

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

4
Зауважте, що це дасть вам лише у, а не z
Марк Бейкер

До! так, хороший момент. Я бачу логіку як приріст, так і порівняння, але, безумовно, дивно, що іноді $ 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

Нічого, я насправді не знав про це, але це не великий код, ви можете спробувати відлуння "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.