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 番目のキャプチャ用サブパターンにマッチした 文字列が代入され、といったようになります。

よくわからないけど
第３引数を指定すると検索結果が代入されるらしい。

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

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

分割に使用した文字列は取得できた。
$matches[0]しか代入されてないけど。

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

```php
$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]に代入されて、
()で囲むと上記のような結果が得られるみたい。

```php
$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のキーに名前を指定する
```php
$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"
// }
```

#やりたかった処理の実装
```php
$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