PHP

preg_match()関数で正規表現を利用して文字列を分割する

preg_match()の使い方を調べたのでメモ

正規表現をつかって文字列を分割して、

かつどんな文字列で分割したのかも知りたかった。


やりたかったこと

// これを

$array = [
'foo_foo_1' => 'f1',
'bar_bar_1' => 'b1',
'hoge_hoge_1' => 'h1',
'foo_foo_2' => 'f2',
'bar_bar_2' => 'b2',
'hoge_hoge_2' => 'h2',
'foo_foo_3' => 'f3',
'bar_bar_3' => 'b3',
'hoge_hoge_3' => 'h3',
// ...繰り返し
'foo_foo_n' => 'fn',
'bar_bar_n' => 'bn',
'hoge_hoge_n' => 'hn',
];

// こんな感じにしたかった
$array = [
1 => [
'foo_foo' => 'f1',
'bar_bar' => 'b1',
'hoge_hoge' => 'h1'
],
2 => [
'foo_foo' => 'f2',
'bar_bar' => 'b2',
'hoge_hoge' => 'h2'
],
3 => [
'foo_foo' => 'f3',
'bar_bar' => 'b3',
'hoge_hoge' => 'h3'
],

// ...繰り返し
n => [
'foo_foo' => 'fn',
'bar_bar' => 'bn',
'hoge_hoge' => 'hn'
],
];

つまり、foo_foo_nをfooとnに分割したい。(nは整数)


とりあえずやってみる

https://www.php.net/manual/ja/function.preg-match.php


matches を指定した場合、検索結果が代入されます。 \$matches[0] にはパターン全体にマッチしたテキストが代入され、 $matches[1] には 1 番目のキャプチャ用サブパターンにマッチした 文字列が代入され、といったようになります。


よくわからないけど

第3引数を指定すると検索結果が代入されるらしい。

$str = 'foo_foo_1';

preg_match('/_[\d]/u', $str, $matches);
var_dump($matches);

// array(1) {
// [0]=> string(2) "_1"
// }

分割に使用した文字列は取得できた。

$matches[0]しか代入されてないけど。


分割された後の文字列も取得したい

$str = 'foo_foo_1';

$bar = preg_match('/(\w+)_[\d]/u', $str, $matches);
var_dump($matches);
// array(2) {
// [0]=> string(9) "foo_foo_1"
// [1]=> string(7) "foo_foo"
// }

正規表現を()で囲むと\$matches[0],$matches[1]に代入された。

\$matches[0] // 元の文字列

\$matches[1] // ()で囲んだ正規表現にマッチした文字列

"_1"が消えてしまった。

()で囲まないと正規表現全体にマッチした文字列が$matches[0]に代入されて、

()で囲むと上記のような結果が得られるみたい。

$str = 'foo_foo_1';

$bar = preg_match('/(\w+)_([\d])/u', $str, $matches);
var_dump($matches);
// array(3) {
// [0]=> string(9) "foo_foo_1"
// [1]=> string(7) "foo_foo"
// [2]=> string(1) "1"
// }

欲しい結果を取得できた。

ただ\$matches[1]や$matches[2]では使いづらい。

\$matchesのキーに名前を指定できるようなのでやってみた。


$matchesのキーに名前を指定する

$str = 'foo_foo_1';

preg_match('/(?P<name>\w+)_(?P<num>[\d]+)/u', $str, $matches);
var_dump($matches);

// array(5) {
// [0]=> string(9) "foo_foo_1"
// ["name"]=> string(7) "foo_foo"
// [1]=> string(7) "foo_foo"
// ["num"]=> string(1) "1"
// [2]=> string(1) "1"
// }


やりたかった処理の実装

$array = [

'foo_foo_1' => 'foo1',
'bar_bar_1' => 'bar1',
'hoge_hoge_1' => 'hoge1',
'foo_foo_2' => 'foo2',
'bar_bar_2' => 'bar2',
'hoge_hoge_2' => 'hoge2',
'foo_foo_3' => 'foo3',
'bar_bar_3' => 'bar3',
'hoge_hoge_3' => 'hoge3',

'foo_foo_10' => 'foo10',
'bar_bar_10' => 'bar10',
'hoge_hoge_10' => 'hoge10',

'foo_foo_101' => 'foo101',
'bar_bar_101' => 'bar101',
'hoge_hoge_101' => 'hoge101',
];

$result = [];

foreach ($array as $key => $value) {
if(preg_match('/(?P<name>\w+)_(?P<num>[\d]+)/u', $key, $matches)) {
$k = (int)$matches['num'];
$result[$k][$matches['name']] = $value;
}
}

var_dump($result);

/*
array(5) {
[1]=>
array(3) {
["foo_foo"]=>
string(4) "foo1"
["bar_bar"]=>
string(4) "bar1"
["hoge_hoge"]=>
string(5) "hoge1"
}
[2]=>
array(3) {
["foo_foo"]=>
string(4) "foo2"
["bar_bar"]=>
string(4) "bar2"
["hoge_hoge"]=>
string(5) "hoge2"
}
[3]=>
array(3) {
["foo_foo"]=>
string(4) "foo3"
["bar_bar"]=>
string(4) "bar3"
["hoge_hoge"]=>
string(5) "hoge3"
}
[10]=>
array(3) {
["foo_foo"]=>
string(5) "foo10"
["bar_bar"]=>
string(5) "bar10"
["hoge_hoge"]=>
string(6) "hoge10"
}
[101]=>
array(3) {
["foo_foo"]=>
string(6) "foo101"
["bar_bar"]=>
string(6) "bar101"
["hoge_hoge"]=>
string(7) "hoge101"
}
}
*/

これで良さげ


ちなみに正規表現の'\w'は注意がいるみたい

正規表現「\w」の説明の訂正(レシピ045)

http://php-recipe.com/?p=483