PHPのprintfと型変換子でつまずいた

## PHPのprintfの型変換子でつまずいた
PHPのprintfの型変換子でつまずいたのでメモを残します。長くなりますが、1つ1つの型変換子の意味を理解していき、組み合わせて使う練習をしていきました。

## 文字列
まずは文字列の場合に絞って理解していきます。

### 文字列を表示
printf('%s', 'hello')
の1個目の引数の、%の後にs(string、文字列の意味)を指定すると、2個目の引数に指定された文字列で置き換えされてそのまま表示されます。
※「%s」が表示される部分ですが、「%s」は「hello」に置き換えられてから、表示されています。
printf('%s', 'hello')
![スクリーンショット 2023-10-18 11.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/759c6b7f-a43e-5687-a5ba-5ef9280ad579.png)

### 一部を文字列で置き換えて表示
1個目の引数の「%s」の部分"だけ"が、2個目の引数の値で置き換えられるので、以下のコードだと
「%s    world !」が
「hello world !」となり、文章の一部だけを指定の文字列で置き換えられるようになります。
printf('%s world !', 'hello')
![スクリーンショット 2023-10-18 11.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/424fc3eb-f382-e762-63ca-0a53ebadb1cf.png)

### 指定の長さになるよう埋めた文字列を表示
「.3」のように、ピリオドの後に桁数の数字をつなげたものを追加すると、その文字数になるように、文字列が切り捨てられます。
今回は「hello」が3文字になるよう切り捨てられ、「hel」となります。
※%から始まり、sで終わるので、「.3」はその中に書く必要があります。「%.3s」が正しくて、「.3%s」や「%s.3」は間違いです。
printf('%.3s', 'hello')
![スクリーンショット 2023-10-18 12.01.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/92d08875-d8bb-2b28-0a69-083bb41f9228.png)

### ↑は日本語の場合注意
先ほど「.3」だと3文字になるよう切り捨てられると言いましたが、正確には3バイトになるように切り捨てられています。
文字バイトについて理解する必要がありますが、例えば日本語の「こんにちは」は、5文字全てが3バイトずつで合計15バイトなので、3バイトになるように切り捨てると「こんにちは」が「こ」と切り捨てられ表示されます。
printf('%.3s', 'こんにちは')
![スクリーンショット 2023-10-18 12.08.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/7757ce09-e3ea-eede-64d4-71262f19d687.png)

### 〇文字になるように埋める
「hello」が10文字になるように、半角スペースで埋めて「     hello」にします。
「%」と「s」の間に、1以上の整数を入れると、その桁数になるよう半角スペースで埋められます。
※半角スペースが追加されていないように見えますが、実際は5個追加されていて、strlen()で長さを確認すると10文字あります。
※後々追加する数字が増えていきますが、この〇文字になるように埋めるという文字数の指定は、「s」の直前で、他のパラメーターより後ろになる位置に書く必要があります。
printf("%10s", 'hello');
![スクリーンショット 2023-10-18 12.22.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/c263fb22-6e16-b3d1-4c26-818995fbe441.png)

### 〇文字になるよう埋める(helloが左寄せになるように)
上の続きで、「hello」が10文字になるように、「hello」が左寄せになるように半角スペースで埋めて「hello     」とするには、10(文字数の指定)の前に、-(マイナス記号)をつけます。
※これも上と同じく半角スペースが見えていませんが、strlen()関数で確認すると10文字になっています。
printf("%-10s", 'hello');
![スクリーンショット 2023-10-18 12.22.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/028ec699-5eaa-dbc1-cb4c-7b59e2f3d66b.png)

### 〇文字になるよう好きな文字で埋める
上の続きで、「hello」が10文字になるように、「a」や「_」など半角スペース以外の好きな文字で埋めて「aaaaahello」とするには、シングルクオーテーションの後に好きな文字を書いたものを、文字数の前に入れます。
「10」で10文字指定して、どの文字で埋めるかを10の前にシングルクオーテーションをつけて書き「'a10」として、それを%とsで挟めみ「%'a10s」とすると、「%s」を「a」で10文字になるように埋めてくれます。
※ここでも順番が重要です。「s」の前に数字があればそれは何文字になるよう埋めるかを指定する数字で、その前に文字があれば、その文字で埋めるという意味なので、後ろから意味を追っていきます。
※躓いてしまったのですが、シングルクオーテーションを使うので、1個目の引数はシングルクオーテーションではなく、ダブルクオーテーションで囲まないとエラーが出ます。「'%'a10s'」ではなく「"%'a10s"」が正しいです。
printf("%'a10s", 'hello');
![スクリーンショット 2023-10-18 12.43.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/d9e93687-c758-8ca5-9866-e28c544c994d.png)

### 〇文字になるよう0で埋める
これがややこしかったのですが、書く順番が大きな意味を持っていて、何文字になるよう埋めるかを指定した文字数の前に0と書くだけで、指定文字数になるよう0で埋めてくれるようになります。
※0の場合だけダブルクオーテーションが必要なく、単純に0を追加すればいいので「こんな書き方で数字が並んだら、意味がわからなくならないのか？」と混乱しましたが、何文字になるよう埋めるかの指定の前に書く必要があり、順番が重要なことに気づいて納得できました。
「10」で10文字になるよう埋めるように指定して、0で埋めたいので10文字指定の直前に0を書き「010」とし、これで０で10文字になるよう埋めるという意味なので、「%」と「s」の間に入れます。
printf("%010s", 'hello');
![スクリーンショット 2023-10-18 12.31.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/dc512c91-12ba-903f-df1d-7edf40c09b8a.png)

### 〇文字になるよう日本語で埋める
日本語の「あ」などのマルチバイト文字で埋めたい場合はうまくいかないので、別の文字に置き換えた上で、str_replace関数などで置き換えます。
一例として一旦「z」で10文字になるように埋めた上で、str_replace()関数で「z」を「あ」に置き換えました。
※printf関数は出力だけで実行結果を変数に格納できないので、それができるsprintf関数を使用しました。
＄word = sprintf("%'z10s", 'hello')
＄word = str_replace('z', 'あ', $word)
print ＄word
![スクリーンショット 2023-10-18 12.56.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/77058814-ee3a-7877-974f-65aebf9a3b61.png)

### 複数の文字列を置き換える
「%s」を「hello」に置き換えてきましたが、「%s」を使って、「hello」だけでなく「world」と「!」の3つを置き換えて、「helloworld!」という文を作って出力してみます。
1個目の引数は今までと同じく「%」から始まり「s」で終わるものを書き、2個目以降の引数に好きなだけ置き換えたいワードをカンマ区切りで追加していきます。
そして、引数の2個目以降に追加した数だけ、1個目の引数の中に「%s」を増やしていき、今回は3個にするので「%s」も3回出現するよう「%s%s%s」とします。
※1番目の「%s」は2個目の引数の「hello」に置き換えられ、2番目の%sが3個目の引数の「world」に置き換えられ、3番目の%sが4個目の引数の「!」に置き換えられています。
printf("%s%s%s", 'hello', 'world', '!');
![スクリーンショット 2023-10-18 13.01.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/6787a6e9-05e6-2846-433b-07662feffa91.png)

### ↑は%sだけでなく好きな文字があってもいい
「%s%s%s」のように「%s」だけでなく、例えば「%s %s %sと出力する勉強をしています。」のように、好きな文章の中の「%s」だけ置き換えることもできます。
※「%s%s%s」の間に半角スペースを入れて「%s %s %s」としているので、半角スペースが入り「helloworld!」の部分が「hello world !」となっています。
printf("%s %s %sと出力する勉強をしています。", 'hello', 'world', '!');
![スクリーンショット 2023-10-18 13.07.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/58bb1bec-fa3a-a7db-48ba-c7a645cced64.png)

### 順番を指定して入れ替えることもできる
↑では「%s%s%s」を、2個目以降の引数の'hello', 'world', '!'と順番通りに置き換えて「helloworld!」とデフォルトでは表示されますが、順番を指定して例えば「world!hello」とすることもできます。
printf("%s%s%s", 'hello', 'world', '!');
↑では'hello'が1番目、'world'が2番目、'!'が3番目に置き換えられるものですので、「＄」を使って1番目の'hello'を表示したければ、「1$」を%とsの間に入れて「%1$s」とすることで実現できます。
例えば、'!'を表示したければ3番目の引数なので「3＄」を%とsの間に入れればいいので、「%3＄s」となります。
次のようにすると「world!hello」と出力できます。
※「＄」は「""」で囲んで書くときはエスケープが必要な文字なので、「""」ではなく「''」で囲んで書いています。
※「%」で始まり「s」で終わることを意識して、「%2＄s」と「%3＄s」と「%1＄s」が塊で分かれて見えるようにならないといけません。
※この何番目の引数を表示するかを指定する「1＄」などは、もし使う場合は、「%」から始まり「s」で終わる中の、「%」の"直後"に書く必要があり、書く順番が重要になります。
printf('%2$s%3$s%1$s', 'hello', 'world', '!');
![スクリーンショット 2023-10-18 13.22.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576117/ee41891e-b7f1-1c26-a6fa-7115ec897066.png)

## 数字と文字が連続して訳がわからなくなりました
↑で「＄」と数字がまた増えてしまい、数字と記号がたくさん並んで分からなくなったことが原因でも少し躓きましたが、「1」と「＄」の順番が重要で、「＄」の直前に何番目の引数を取得するかを指定する「1」を書く必要があり、順番が重要でした。
※これまでに話した、何文字になるよう置き換えるかを指定する数字(「%s」の「s」の直前に「%10s」などと書くもの)、どの文字で置き換えるかを指定するシングルクオーテーションと文字列や数字(「'a」や「'_」や「'1」など)、0で置き換える場合はシングルクオーテーションなしで0のみ(「0」)、などが混在するので私は混乱しましたが、まず最初に「'」があればその後の文字や数字とセットで「'1」と見て、「$」があればその前の数字とセットで「2$」と見て、その後で最後に残った数字が何文字になるように置き換えるかという数字になるので、このように塊で見るようになると意味がわかるようになりました。
例えば、これは
printf('%2＄-010s', 'hello', 'world', '!');
このように見えていて、
printf('% 2＄ - 0 10 s', 'hello', 'world', '!');
「%」から始まり、「2$」で2番目の引数の'world'を置き換えるんだな、「-」は'world'を左づめになるよう何かの文字列で置き換えるんだな、「0」は置き換える文字列を表していて0の場合だけシングルクオーテーションなしで0と書いて良く、0で置き換えるんだな、「10」でworldが10文字になるように置き換えるんだな、「s」でここまでで「%」からの処理の記述が終わりか、というふうに考えるようになりました。
※順番のルールとして「2＄」など何番目の引数を取得するかは、指定したい場合は「%」の直後に書き、「10」など何文字になるように指定文字で埋めたいかは「s」の直前に書く必要があるので、これも重要だと思いました。
文字列の場合しか書けませんでしたが、ここまでの内容が分かれば整数や小数点の内容も理解できました。
文字列、整数、少数が使用頻度が多いかと思いましたので、この3つに絞って勉強しましたが、間違っていなかったと感じました。
ダラダラと思うままに書き続けて長く非常にわかりにくい文章になりましたが、勉強したことの軌跡として残しておきます。