なぜこのコードは単にAからZまでの文字を印刷しないのですか?


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

このスニペットは次の出力を提供します(改行はスペースに置き換えられます):

abcdefghijklmnopqrstu vwxyz aa ab ac ad ae af ag ah ai aj ak a am ao ap aq ar as at at av aw ax ax ay az ba bb bc bd be bf bg bh bi bj bk bl bm bn bo bp bq br bs bt bt 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 dt du dv dw dx dy dz ea eb ec ed ee ef eg eh ei ej ek el em eo eq eq et eu ew ex ... on to yz


31
PHPはCではありません。たとえ構文がその反対を説得しようとしても。
joni 2010年

3
これは非常に小さな変更で機能します:for($ i = 'a'; $ i!= 'aa'; $ i ++){echo "$ i \ n"; }
Surreal Dreams

2
そのPHPに関するコメントはCではありません-最も鋭敏でした。例:c:char c = 'a'; phpと同じではありません。$c = 'a';要点は、Cにはchar(文字1記号)のタイプがあることですが、PHPにはありません$c = 'a';。これは、UがPHPに通知する場合、これは1文字のみの文字列であることを意味します。これが、PHPで28文字を適切にループできない理由です。すべてのプログラマーが、数学の実践を忘れずに低水準言語と強力なタイピングを学び、それによって彼らがより強くなることを願っています。
Arthur Kushman、

うわー、本当にクールですが、「z」で止まらなかった理由
Prasanth Bendra

等価(==または!=)を使用して期待されるエンドポイントを取得する方法については、関連する質問に対するこの回答を確認してください
IMSoP 2013

回答:


342

ドキュメントから:

PHPはCではなく文字変数の算術演算を処理する場合、Perlの規則に従います。

例えば、Perlで'Z'+1変身'AA'Cにある間、'Z'+1になります'['ord('Z') == 90ord('[') == 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 2010年

6
ShreevatsaRが言っているように、問題は算術ではなくコンパレータです。++演算子に焦点を合わせないでください
slf

10
@ShreevatsaR:実際には、 'yz' + 1 = 'za'。失敗する最初の比較は 'za' <= 'z'です
MilanBabuškovNov

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'です。そのロジックはあまりうまく流れません。
Matthew Vines、2010年

19
@マシュー:それらをアルファベット順に。「aa」が最初に来るため、文字列「z」より「小さい」ことになります。ループは「zz」で終了します。これは、アルファベット順で「より大きい」(後に来る)「z」だからです。何かを「インクリメント」してより小さな値を取得できるという意味では非論理的ですが、アルファベット順では論理的です。
eldarerathis

2
文字インクリメンターはPerlロジックです(ドキュメントからのCMSの引用を参照)。比較 'aa' <'z'は、標準の文字列比較ロジックです。奇妙なことではなく、使い方を理解したら...ここの答えから、多くの人はそうではありません。
Mark Ba​​ker

5
@eldarerathisああ、私は間違いなくそれがどのように機能しているのか理解しています。私はそれを同時に奇妙だと思います。
Matthew Vines、2010年

2
これは、同じ論理シリーズに続くExcelの列で遊んで、私にとっては非常に便利です
マーク・ベイカー

97

その他の回答は、投稿されたコードの観察された動作を説明しています。ここにあなたが望むことをする1つの方法があります(そしてそれはよりクリーンなコード、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 2010年

1
何と言えばいいか…もっとPHPの狂気。:-) range()がこのように機能することを私が知っている他の言語はありません。(確かに、HaskellやPythonなどではありません。)ダイクストラはこれについて何か書きませんでしたか?
ShreevatsaR 2010年

10
狂気はPHPの矛盾です。範囲(「A」、「CZは」)++インクリメンタに全く異なる働き、そして得られた配列は、わずか3値が含まれます:A、BおよびCの
マーク・ベイカー

35

他の人たちは、なぜPHPが期待したものを表示しないのかをすでに述べています。希望する結果が得られる方法は次のとおりです。

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

2
不要。ord()を実行する必要はまったくありません。ループを終了するための正しい比較です
Mark Ba​​ker

2
+1 PHPのより風変わりな機能の1つに慣れていない場合は、はるかに理解しやすくなります。
lonesomeday

1
これは自己文書化コードの優れた例です。序数値を使用して変数を文字として表示するため、正確にb / cを簡単に理解できます。次のように最大値のテストが一度だけ決定される場合、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には文字をループする機能があり、1文字を超えることができます。残りはこのように行われます: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
これは、aからyのみを提供し、zは提供しないことに注意してください
Mark Ba​​ker

どー!うん、良い点。増分と比較の両方の背後にあるロジックを確認できますが、$ a ++ <$ a
jon_darkstar

0

PHPは、「AA」が「Z」よりも小さいとは見なしません。これを行う最良の方法は次のとおりです。

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

abcdefghijklmnopqrstuvwxyz


0

おそらく、このコードは機能します。簡単で理解できます:

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

ここで、26はアルファベットの文字の総数です。


-3

うわー、私はこれについては本当に知りませんでしたが、大きなコードではありません。ループの後にエコー "z"を試すことができます。Markは絶対に正しいです。

<?php
for ($i = "a"; $i = "y"; $i++) {
    echo "$i\n";
    if ($i == "z") {}
}
echo "z";
?>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.