【PHP】競技プログラミング用の関数チートシート【プロコン】

## はじめに
最近競技プログラミング/プログラミングコンテストへの参戦を始めましたが、PHPでやっている人が少なくあまり情報がないのと、自分用のメモとしても、PHPで参戦する競技プログラミングのチートシートをまとめて行きたいと思います。

#### 前提
下記のファイルを用意。index.phpが実行ファイル、test.txtが標準入力用のファイルとします。

```text:test.txt
1 2 3
4 5 6
7 8 9
```

## 標準入力

#### fgets()
[PHP マニュアル : fgets — ファイルポインタから 1 行取得する](https://www.php.net/manual/ja/function.fgets.php)

```php:index.php
$line = fgets(STDIN); // STDIN(スタンダードインプット:標準入力)から1行を取得
echo $line; // 結果：1 2 3
```
`fgets()`での読み出しは length のオプションを指定しない場合、改行またはEOF(End of File)に達したかのいずれかの時点で終了します。

#### fscanf()
[fscanf — フォーマットに基づきファイルからの入力を処理する](https://www.php.net/manual/ja/function.fscanf.php)
test.txtのように1行に複数の文字列が含まれる場合、フォーマットを指定して別々の変数に格納することができます。`fscanf()`をコールする度に、ファイルから1行ずつ読み込みます。

```php:index.php
// 半角スペースを区切りとして、別々の変数に格納
fscanf(STDIN, "%d %d %d", $a, $b, $c);
echo $a; // 1
echo $b; // 2
echo $c; // 3
```
区切り文字がカンマの場合は`"%d,%d,%d"`とします。
各種フォーマットの種類と、それらを指定するオプションについては下記リンクを参照。
例えばよく使われるのは、文字列を意味する`%s`(string)や、10進数の整数を意味する`%d`(digit)などです。
`%s`や`%d`のことは型指定子またはフォーマット指定子といいます。C言語などでは馴染みが深いのではないでしょうか。

[sprintf — フォーマットされた文字列を返す](https://www.php.net/manual/ja/function.sprintf.php)


#### fopen()

ローカル環境で標準入力用のファイルを用意してテストを行う場合は以下のようにしてみました。

```php:index.php
// ファイルパス指定し、任意のファイルを読み取り専用でファイルオープン
$file = fopen("test.txt", "r");
// ファイルオープンして代入した変数 $file から fgets() で1行 $line に代入
$line = fgets($file);
echo $line; // 結果：1 2 3
```

#### 2019/12/13 追記

ローカル検証時、fopen()を使わなくてもパイプを使って標準入力（STDIN）の受け渡しが可能。

```shell
cat test.txt | php index.php
```

（今までブラウザを通して検証していましたが、ターミナルで実行するなら上記コマンドで大丈夫でした。@k-onoda さんありがとうございました！）

#### while()
[whileループ](https://www.php.net/manual/ja/control-structures.while.php)
標準入力の内容が複数行に渡る場合、whileを使うと簡単にすべての行を取り出せます。
条件分岐でよくある挙動は「trueなら実行する、falseなら実行しない」ですが、whileについても「条件式がtrueである間は実行する」というループになります。そのためwhileの条件式に`($line = fgets(STDIN))`という内容を設定した場合は、ファイルの最終行まで実行して読み込めるものがなくなったらfalse(実行終了)となります。

```php:index.php
while ($line = fgets(STDIN)){
    echo $line;
    // 1回目の繰り返し：1 2 3
    // 2回目の繰り返し：4 5 6
    // 3回目の繰り返し：7 8 9
};
```

## 文字列の加工

#### trim()

[trim — 文字列の先頭および末尾にあるホワイトスペースを取り除く](https://www.php.net/manual/ja/function.trim.php)
用意された標準入力ファイルの行頭・行末に余計な空白等があって望んだ出力が得られない場合はそれらを削除します。オプションを指定しなければtrim()は空白・タブ・改行などを削除してくれます。


```php:index.php
$line = fgets(STDIN);
$i = trim($line);
echo $i; // 1 2 3
```

#### explode()

[explode — 文字列を文字列により分割する](https://www.php.net/manual/ja/function.explode.php)
文字列を区切り文字で分割した結果を配列として返します。

```php:index.php
$line = fgets(STDIN);
// 半角スペースを区切りとして、配列に格納
$arr = explode(" ", $line);
echo $arr[0]; // 1
echo $arr[1]; // 2
echo $arr[2]; // 3
```

#### implode()

[implode — 配列要素を文字列により連結する](https://www.php.net/manual/ja/function.implode.php)
区切り文字で、配列の中身を連結したいときは`implode()`を使用します。引数には区切り文字として使用する文字列と、連結したい文字列の格納された配列を用意します。


```php:index.php
$line = fgets(STDIN);
$arr = explode(" ", $line);
// カンマを区切りとして、配列の中身を連結
$str = implode(",", $arr);
echo $str; // 1,2,3
```

#### strtoupper()

[strtoupper — 文字列を大文字にする](https://www.php.net/manual/ja/function.strtoupper.php)
文字列に含まれるアルファベット部分をすべて大文字にして返します｡ a-z の一般的な半角英字が対象です。

```php:index.php
$str = "i love you";
echo strtoupper($str); // I LOVE YOU
```


#### mb_strtoupper()

[mb_strtoupper — 文字列を大文字にする](https://www.php.net/manual/ja/function.mb-strtoupper.php)

文字列に含まれるアルファベット部分をすべて大文字にして返します｡ 接頭辞の `mb` はマルチバイトなので a-z の一般的な半角英字以外にも、α（アルファ）、β（ベータ）などのアルファベットや、全角英字も対象です。
下記サンプルでは α（アルファ）、β（ベータ）、γ（ガンマ）、ω（オメガ）のほか、全角の ａｂｃ を `$str` に代入しています。

```php:index.php
$str = "αβγω ａｂｃ";
echo mb_strtoupper($str); // ΑΒΓΩ ＡＢＣ
```

#### strtolower()

[strtolower — 文字列を小文字にする](https://www.php.net/manual/ja/function.strtolower.php)
文字列に含まれるアルファベット部分をすべて小文字に変換して返します｡ a-z の一般的な半角英字が対象です。

```php:index.php
$str = "I LOVE YOU";
echo strtolower($str); // i love you
```

#### mb_strtolower()

[mb_strtolower — 文字列を小文字にする](https://www.php.net/manual/ja/function.mb-strtolower.php)

文字列に含まれるアルファベット部分をすべて小文字に変換して返します｡ 接頭辞の `mb` はマルチバイトなので a-z の一般的な半角英字以外にも、Γ（ガンマ）、Ω（オメガ）などのアルファベットや、全角英字も対象です。
下記サンプルでは Γ（ガンマ）、Ω（オメガ）、全角の ＡＢＣ を `$str` に代入しています。


```php:index.php
$str = "ΓΩ - ＡＢＣ";
echo mb_strtolower($str); // γω - ａｂｃ
```

#### str_split()

[str_split — 文字列を配列に変換する](https://www.php.net/manual/ja/function.str-split.php)
文字列を1文字ずつ分割して配列に格納します。オプションに文字数nを指定すれば、n文字ずつ格納することができます。

```php:index.php
$line = fgets(STDIN);
$arr = str_split($line);
echo $arr[0]; // 1
echo $arr[1]; // 半角スペース
echo $arr[2]; // 2
echo $arr[3]; // 半角スペース
echo $arr[4]; // 3
```




## 文字列の検索
#### str_replace()

[str_replace — 検索文字列に一致したすべての文字列を置換する](https://www.php.net/manual/ja/function.str-replace.php)
第三引数の文字列の中で、第一引数の文字列を検索し、第二引数の文字列に置換します。

```php:index.php
$line = fgets(STDIN);
// $lineで定義された"1 2 3"という文字列から"1"を探し"9"に置き換える
$str = str_replace("1", "9", $line);
echo $str; // 9 2 3
```

#### strpos()

[strpos — 文字列内の部分文字列が最初に現れる場所を見つける](https://www.php.net/manual/ja/function.strpos.php)
第一引数の文字列の中から、第二引数の文字列を検索し、検索文字列が最初に現れる位置を返します。位置は0から始まる数え方で表され、検索した文字列が存在しない場合はfalseを返します。検索する文字が英字の場合は大文字・小文字もきちんと区別されます。

```php:index.php
while($line = fgets(STDIN)){
    $arr[] = trim($line);
}
echo strpos($arr[0], "1"); // 0
```
似たような挙動である`strstr()`と比べて高速でメモリ消費も少なく、PHPマニュアルによると文字列の検索だけであれば上記の`strpos()`を使うと良いそうです。

[strstr — 文字列が最初に現れる位置を見つける](https://www.php.net/manual/ja/function.strstr.php)

> もし特定の haystack に needle があるかどうかを調べるだけの場合、 より高速でメモリ消費も少ない strpos() を代わりに使用してください。

#### array_search()

[array_search — 指定した値を配列で検索し、見つかった場合に対応する最初のキーを返す](https://www.php.net/manual/ja/function.array-search.php)

この関数では、配列の中から、文字や数値を検索します。返り値は検索して見つかった場合の最初の配列番号（インデックス）となります。インデックスは0始まりなので、下記の場合では3が返ってきます。

```php:index.php
$arr = [1, 87, 51, 45, 99, 3];
echo array_search(51, $arr); // 2
```


## カウント・個数や回数を数える
#### mb_substr_count()

[mb_substr_count — 部分文字列の出現回数を数える](https://www.php.net/manual/ja/function.mb-substr-count.php)
第一引数に指定された文字列の中で、第二引数で指定された文字列の個数を数えます。

```php:index.php
$line = fgets(STDIN);
echo mb_substr_count($line, "3"); // 1
```

#### strlen
[strlen — 文字列の長さを得る](https://www.php.net/manual/ja/function.strlen.php)
文字長をバイト数で数えます。1や2などの半角数字は1としてカウントされ、半角スペースや改行やタブなども1としてカウントされます。
test.txtにおける`1 2 3`であれば`1,半角スペース,2,半角スペース,3,改行`とカウントされ6が結果となりますが、文字列が`あいう`（全角ひらがなのみ、改行やスペースなし）などであった場合、ひらがなは単純計算で1文字3バイトとして数えられるため、出力結果は3文字x3バイトで`9`となります。

```php:index.php
$line = fgets(STDIN);
echo strlen($line); // 6
```

#### mb_strlen()
[mb_strlen — 文字列の長さを得る](https://www.php.net/manual/ja/function.mb-strlen.php)
引数に長さを調べたい文字列を指定すると、マルチバイトで文字列の長さを返してくれますう。スペースや改行や全角半角文字を含む文字数がわかり、文字のバイト数は問わないため文字列が`あいう`（全角ひらがなのみ、改行やスペースなし）などであった場合は`3`が返ってきます。

```php:index.php
$line = fgets(STDIN);
echo mb_strlen($line); // 6
```

#### count()

[count — 変数に含まれるすべての要素、 あるいはオブジェクトに含まれる何かの数を数える](https://www.php.net/manual/ja/function.count.php)
引数で指定した、配列またはオブジェクトの数を数えます。配列の要素の数を数えるときなどに便利です。

```php:index.php
while ($line = fgets(STDIN)){
    $arr[] = $line;
};
$cnt = count($arr);
echo $cnt; // 3
```

## 計算・合計値や絶対値や指数表現

#### array_sum()

[array_sum — 配列の中の値の合計を計算する](https://www.php.net/manual/ja/function.array-sum.php)
配列に格納された数値を合計し、整数または float として返します。

```php:index.php
$temp = fgets(STDIN);
$line = trim($temp);
$arr = explode(" ", $line);
echo $arr[0]; // 1
echo $arr[1]; // 2
echo $arr[2]; // 3
echo array_sum($arr); // 1+2+3= 6
```

#### abs()
[abs — 絶対値](https://secure.php.net/manual/ja/function.abs.php)
数値の絶対値を返します。簡単に言うと、負の数を正の数に（マイナスの数をプラスの数に）変換します。絶対値なので、正の数は正の数のままになります。

```php:index.php
$temp = fgets(STDIN);
$line = trim($temp);
$arr = explode(" ", $line);
$num = $arr[0] - $arr[2]; // -2
echo abs($num); // 2
```
#### pow()

[pow — 指数表現](https://www.php.net/manual/ja/function.pow.php)
数値を2乗、3乗など、累乗・べき乗する計算をしたいときに指数を使って求めることができます。
代数演算子を使用して `$a` の `$b` 乗 を `$a ** $b` として計算することもできます。

```php:index.php
echo pow(3, 3); // 3の3乗 => 3 * 3 * 3 なので 出力結果は 27
echo pow(2, 5); // 2の5乗 => 2 * 2 * 2 * 2 * 2 なので 出力結果は 32

echo 3 ** 3; // 3の3乗 => 3 * 3 * 3 なので 出力結果は 27
echo 2 ** 5; // 2の5乗 => 2 * 2 * 2 * 2 * 2 なので 出力結果は 32
```


## 小数点・切り捨てと繰り上げ

#### floor()

[floor — 端数の切り捨て](https://www.php.net/manual/ja/function.floor.php)
小数点以下の数字を切り捨てて小さい方の整数へ合わせます。

```php:index.php
<?php
echo floor(4.3);   // 4
echo floor(9.999); // 9
echo floor(-3.14); // -4
```

#### ceil()

[ceil — 端数の切り上げ](https://www.php.net/manual/ja/function.ceil.php)
小数点以下の数字を繰り上げて大きい方の整数へ合わせます。

```php:index.php
<?php
echo ceil(4.3);    // 5
echo ceil(9.999);  // 10
echo ceil(-3.14);  // -3
```


## 配列・ソートや除外

#### sort()

[sort — 配列をソートする](https://www.php.net/manual/ja/function.sort.php)
この関数は配列を昇順ソートします。キーと値（バリュー・要素の中身）の関係性が一新され、処理後は配列内の各値が小さい方から順に並び変わった状態になります。

```index.php
$fruits = ["lemon", "orange", "banana", "apple"];
sort($fruits);
foreach ($fruits as $key => $val) {
    echo "fruits[" . $key . "] = " . $val . "\n";
}
// $fruits[0] = apple
// $fruits[1] = banana
// $fruits[2] = lemon
// $fruits[3] = orange
```

#### asort()

[asort — 連想キーと要素との関係を維持しつつ配列をソートする](https://www.php.net/manual/ja/function.asort.php)
asort関数では要素の中身（バリュー）を判定して番号順やアルファベット順に配列を組み替えます。

```php:index.php
$test = ["d" => 1, "a" => 4, "b" => 2, "c" => 3];
asort($test);
foreach ($test as $key => $val) {
    echo "$key = $val\n";
    // 出力結果： d = 1
    // 出力結果： b = 2
    // 出力結果： c = 3
    // 出力結果： a = 4
}
```
これをすることによって元の配列の順序は変更され、`asort()`自体の返り値としては成功した場合に TRUE を、失敗した場合に FALSE を返します。

#### krsort()

[krsort — 配列をキーで逆順にソートする](https://www.php.net/manual/ja/function.krsort.php)

キーと値の関係は維持したまま、キーの順序を逆順にすることによって、配列の中身を組み替えます。
こちらも関数自体の返り値としては成功した場合に TRUE を、失敗した場合に FALSE を返します。

```php:index.php
$test = ["a", "p", "p", "l", "e"];
krsort($test);
foreach ($test as $key => $val) {
    echo "$key = $val\n";
    // 出力結果： 4 = e
    // 出力結果： 3 = l
    // 出力結果： 2 = p
    // 出力結果： 1 = p
    // 出力結果： 0 = a
}
```


[配列のソート](https://www.php.net/manual/ja/array.sorting.php)

PHPには、配列を並び替える・順序を変更するための関数が複数用意されているので、上記のリストから状況や目的に応じて関数を選択すると良さそうです。

#### array_unique()

[array_unique — 配列から重複した値を削除する](https://www.php.net/manual/ja/function.array-unique.php)
引数として与えられた配列を元に、値に重複のない新規配列を返します。配列内の要素がすべて同じ値であるかどうかを知りたいときなどに便利です。
例えばゾロ目の判定をしたいとき、桁数の多い数をひと桁ずつ、配列のひとつひとつの要素として分解後、array_unique()によって重複を削除することでゾロ目の数値であるかがわかります。
重複を削除すればゾロ目のものは配列が1つしか残りませんし、ゾロ目でなければ2つ以上となります。

```php:index.php
$array = [1, 1, 1, 1];

if (count(array_unique($array)) == 1) {
    echo "Yes\n"; // 配列の値がすべて同じなのでYesとなる
} else {
    echo "No\n";
}
```
#### range()

[range — ある範囲の整数を有する配列を作成する](https://www.php.net/manual/ja/function.range.php)
指定した数値の範囲を配列にします。例えば1〜5の数を配列にしたい場合、最初の1と最後の5を引数に与えれば、1から5までの数字を順番に格納した配列が作られます。

```php:index.php
$arr = range(1, 5);
var_dump($arr);
// array(5) {
//   [0]=>int(1)
//   [1]=>int(2)
//   [2]=>int(3)
//   [3]=>int(4)
//   [4]=>int(5)
// }
```

## その他
#### 改行
改行(\n)はダブルコーテーション内で使用することで改行として認識されます。
HTMLの改行`<br>`とは異なるので、ブラウザでレンダリングされたHTMLによる画面表示としてではなく、PHPの出力として改行されていることを検証ツールなどで確認してください。

```php:index.php
echo "月が\n綺麗ですね。";
// 月が
// 綺麗ですね。
```


個人的によく使うものを中心にまとめましたが、また増えると思うので随時追加します。

## 参考URL
[ファイルから1行ずつ読み込む - fgets()](https://webkaru.net/php/function-fgets/)
[PHPでファイルの読み込みをする主な4つの方法](https://www.flatflag.nir87.com/fgets-810#fgets1)
[標準入力、標準出力とは何か?](http://www.creatology.jp/unix/outin.html)
[標準入出力](http://wisdom.sakura.ne.jp/programming/c/c44.html)
[Paizaで使える標準入力の取得](https://qiita.com/one-kelvin/items/09068b8971c4da509cd3)
[PHPで標準入力から値を取得して表示する方法を解説](https://qiita.com/yuhei_umeda/items/552c3f2f19e55f80fdfb)
[フォーマットを作る！PHPのsprintf関数の使い方【初心者向け】](https://techacademy.jp/magazine/12286)
[PHPの出力で文字を改行（\n）させるには’’（シングルコーテーション）じゃなくて""（ダブルコーテーション）で記述する](https://qiita.com/sola-msr/items/0814c4470dcbbd1f5ec3)
[余分な空白・改行を取り除くtrim関数を使おう!〜PHP入門編〜](https://www.sejuku.net/blog/26644)
[PHP関数iconv_strlen、mb_strlen、およびstrlenの違いは何ですか？](https://codeday.me/jp/qa/20190212/249049.html)
[PHPの文字数検知 Tips](https://qiita.com/west/items/5e08c7d82f1fac5c752b)
[grapheme_strlen](http://phpspot.net/php/man/php/function.grapheme-strlen.html)
[UTF-8における「strlen」と「mb_strlen」の挙動について](https://website-planner.com/utf-8における「strlen」と「mb_strlen」の挙動について/)
[【PHP入門】文字列の置換 | str_replace・str_ireplace・strtr](https://www.sejuku.net/blog/23430#i)
[【PHP】複数文字列の置換(str_replace)](https://qiita.com/kazu56/items/35c10fdd79393686b26d)
[%sとか%ｄってなんだ？【PHP】](http://911.ddtea.com/?eid=1286755)
[explodeとimplodeの使い方](http://phper.g.hatena.ne.jp/ha1t/20080902/1220351261)
[PHPでカンマ区切りデータを配列に入れる方法 （explode）](http://www.php-mysql-linux.com/php/php-function/array-explode/)
[【php】文字列を1文字ずつに分解して配列にする](https://www.softel.co.jp/blogs/tech/archives/5445)
[PHPで配列を初期化する方法](https://uxmilk.jp/14771)
[PHPで配列に要素を追加する方法](https://uxmilk.jp/8880)
[PHPのcount関数を使って配列の要素の数をカウントする方法【初心者向け】](https://techacademy.jp/magazine/11620)
[php 負数を正数にする（絶対値）](http://raharu0425.hatenablog.com/entry/20100811/1281510654)
[phpでの小数点を切り捨てや切り上げする方法！【floor/ceil/round】](https://blog.codecamp.jp/php-floor-ceil-round)
[配列の値が全て同じか判定する方法](https://lab.syncer.jp/Web/PHP/Snippet/14/)
[PHPで文字列を検索をする：strpos, strstr, preg_match](https://uxmilk.jp/14115)
[【PHP】特定の文字列を含むかのチェック](https://qiita.com/kazu56/items/2c72d187438de07c2503)
[PHP：特定の文字列を含むかどうか検索する方法、まとめ。](http://www-creators.com/archives/2282)
[英字の大文字を小文字にする(strtolower関数)](https://itsakura.com/php-strtoupper-strtolower)
[文字列を大文字 / 小文字に変換 - strtoupper()、strtolower() - mb_strtoupper()、mb_strtolower()](https://webkaru.net/php/function-strtoupper-strtolower/)
[foreachで配列の中身を全部足してみる](http://piyo-php.com/2010/09/108/)