読者です 読者をやめる 読者になる 読者になる

たぶん週刊「今週の進捗」

1週間に勉強したことや実装したことをネタに、週に1回(主に土日に)更新していく予定です。「多分」なので、臨時休刊があってもご海容ください。

PHPで、空白区切りの数値を数値として読む

ちょっとPHPをいじる機会があったのでメモ的に。

発端

空白区切りでN個(既知)の数値を読み込む場合、Cならば私はこう書く。

// 3個の整数値を読み込む場合
#include <stdio.h>
int main(void) {
	int a[3], i;
	for( i=0; i<3; i++)
		scanf("%d",&a[i]);
	for( i=0; i<3; i++)
		printf("%d ",a[i]);
}

予め判明している型でN回scanf()すれば良い。
しかしPHPで同じことをやろうと思ったら、こんなことにすら戸惑ったので
備忘録としてまとめておく。

PHPの場合

PHPで標準入力から読み込む場合、fgets(STDIN)を使うのだが、
数値も空白も一緒くたにstring型として読み込むので困る。

<?php
	$input = fgets(STDIN);	//標準入力からinputに読込

	print("type:".gettype($input)." ");	//inputの変数型を表示
	print("strlen:".strlen($input)."\n");	//inputのstring型としての長さを表示
	for( $i = 0; $i<strlen($input); $i++){
		echo "\$input[".$i."]:";
		if($input[$i]==" ")	// input[i]が空白のとき、"Space"と表示
			echo "Space\n";
		else if($input[$i]=="\n") // input[i]が改行のとき、"New Line"と表示
			echo "New Line\n";
		else echo $input[$i]."\n"; // それ以外は、input[i]を表示
	}
?>

入力(1)

100 200 300

出力

type:string strlen:12
$input[0]:1
$input[1]:0
$input[2]:0
$input[3]:Space
$input[4]:2
$input[5]:0
$input[6]:0
$input[7]:Space
$input[8]:3
$input[9]:0
$input[10]:0
$input[11]:New Line

こんな風に。
そういうときには、指定した文字列を正規表現で分割するpreg_split関数を使う(split関数は5.3.0で非推奨になったらしい)。
正規表現でどう表すかは今回は置いておくとして、空白で分割するときは次のようにするといいらしい。

<?php
	$input = preg_split('/ /', trim(fgets(STDIN)));	//空白区切りで標準入力からinputに読込

	print("type:".gettype($input)." ");	//inputの変数型を表示
	print("count:".count($input)."\n");	//inputの配列としての長さを表示
	for( $i = 0; $i<count($input); $i++){
		echo "\$input[".$i."]:";
		echo $input[$i]."\n"; // 
	}
?>

実行結果

type:array count:3
$input[0]:100
$input[1]:200
$input[2]:300

これでちゃんと数値として読み込まれてますね。
ちなみに、preg_split()の前にtrim()を挟んでいるのは、入力の末尾の改行等を取り除くためです。
文字列の場合はexplode()を使うらしいので、そっちもいつか記事として書きたいなぁ。

執筆中に降って湧いた新たな謎

これを書いてるときに「string型だからそのままじゃ計算出来ないし」と書こうとしていたのだが、
一応検証してみることにした。

<?php
	$input = fgets(STDIN);	//標準入力からinputに読込

	print("type:".gettype($input)." ");	//inputの変数型を表示
	print("strlen:".strlen($input)."\n");	//inputのstring型としての長さを表示
	for( $i = 0; $i<strlen($input); $i++){
		echo "\$input[".$i."]:";
		if($input[$i]==" ")	// input[i]が空白のとき、"Space"と表示
			echo "Space\n";
		else if($input[$i]=="\n") // input[i]が改行のとき、"New Line"と表示
			echo "New Line\n";
		else echo $input[$i]."\n"; // それ以外は、input[i]を表示
	}
	echo "input[0]:".$input[0];
	echo " input[4]:".$input[4];
	$sum = $input[0] + $input[4];	// input[0]とinput[4]の和を計算
	echo "input[0]+input[4]=".$sum."\n";
?>

実行結果(入力は(1)と同じ)

type:string strlen:12
$input[0]:1
$input[1]:0
$input[2]:0
$input[3]:Space
$input[4]:2
$input[5]:0
$input[6]:0
$input[7]:Space
$input[8]:3
$input[9]:0
$input[10]:0
$input[11]:New Line
input[0]:1 input[4]:2
input[0]+input[4]=3

できるのかよ!
string型じゃなかったんかアンタ…。

文字列の場合

文字列の場合はexplode()を使う。(splitでもできるだろうけど)

<?php
	$input = trim(fgets(STDIN));
    $words = explode(" ", $input);

    print_r($words);
?>

入力

hoge fuga piyo foo bar

出力

Array
(
    [0] => hoge
    [1] => fuga
    [2] => piyo
    [3] => foo
    [4] => bar
)

数値と文字列の混合

じゃあ数値と文字列の混合はどうするか。
splitを使ってみる。

<?php
	$input = preg_split('/ /', trim(fgets(STDIN)));	//空白区切りで標準入力からinputに読込

	print("type:".gettype($input)." ");	//inputの変数型を表示
	print("count:".count($input)."\n");	//inputの配列としての長さを表示
	for( $i = 0; $i<count($input); $i++){
		echo "\$input[".$i."]:";
		echo $input[$i]."\n"; // 
	}
	$sum = $input[1] + $input[3] + $input[5];
	echo $sum;
?>

入力

hoge 100 fuga -50 piyo 3.1415

出力

type:array count:6
$input[0]:hoge
$input[1]:100
$input[2]:fuga
$input[3]:-50
$input[4]:piyo
$input[5]:3.1415
53.1415

splitで問題なさそうですね。