<?php
function parse(string $input): array
{
static $pattern = <<<'EOD'
/
# 先頭
^
# name 部分
(?<name>
# \p{L}\p{N} を最低1個は含む
(?=[^「」\p{C}\p{L}\p{N}]*+[\p{L}\p{N}])
# カッコと制御文字以外の繰り返し
[^「」\p{C}]++
)?
# カッコ+空白だけのコメントの場合は読み飛ばす条件分岐
(?:
# empty_comment 部分
(?<empty_comment>
「
# カッコの中身
(?:
# empty_comment の再帰
(?&empty_comment)
)*+
」
)
# empty_comment がマッチしたらそこまでをすべて読み飛ばす
(*SKIP)(*FAIL)
|
# comment 部分
(?<comment>
「
# カッコの中身
(?:
# \p{L}\p{N} を最低1個は含む
(?=[^「」\p{C}\p{L}\p{N}]*+[\p{L}\p{N}])
# カッコと制御文字以外の繰り返し
[^「」\p{C}]*+
# または
|
# comment の再帰
(?&comment)
)*+
」
)?
)
# 末尾
$
/ux
EOD;
preg_match($pattern, $input, $match);
$name = $match['name'] ?? '';
$comment = $match['comment'] ?? '';
// 外側のカッコを切り取り
$comment = mb_substr($comment, 1, -1, 'UTF-8');
$name = $name === '' ? null : $name;
$comment = $comment === '' ? null : $comment;
return compact('name', 'comment');
}
$inputs = [
/*
* 正しい値が与えられた場合、一方か両方に値が入る
*----------------------------------------------*/
'一郎「こんにちは」', // ["name"=>"一郎","comment"=>"こんにちは"]
'二郎「男の中の「男」です」', // ["name"=>"二郎","comment"=>"男の中の「男」です"]
'三郎', // ["name"=>"三郎","comment"=>"null"]
'「こんばんは」', // ["name"=>"null","comment"=>"こんばんは"]
/*
* 不正な値が与えられた場合、いずれも null を返す
*----------------------------------------------*/
//(1)以下のように「」の後に文字がある場合 null とする
'「こんばんは」です', // ["name"=>"null","comment"=>"null"]
//(2)以下のように「」がセットじゃない場合 null とする
'五郎「男の中の「男」かも', // ["name"=>"null","comment"=>"null"]
'「男の中の「男」かも', // 同上
'「やばい', // 同上
'ねむい」', // 同上
'「', // 同上
'」', // 同上
'「「」', // 同上
//(3)以下のように記号だけの場合 null とする
'「」', // ["name"=>"null","comment"=>"null"]
'「「」」', // 同上
'「★」', // 同上
'「!!」', // 同上
];
foreach ($inputs as $input) {
var_dump([$input => parse($input)]);
}
preferences:
25.15 ms | 407 KiB | 5 Q