我是一个电报机器人,很难从字符串中获取输入值。我的目标是使我的命令易于编写和理解。这是我从客户消息中获得的一些示例命令
,simpleImage. query Dark background. width 200. height 200. text %fortune_teller%
应该是这样的数组
[simple_image][query] => 'Dark background'
[simple_image][width] => '200'
[simple_image][height] => '200'
[simple_image][text] => '%fortune_teller%'
对于空参数,应该这样
,sayHello. %custom_id%
[say_hello] => '%custom_id%'
但是当我尝试输入一些日语文本和诸如\, *, &, |, et cetera
之类的特殊字符时,我遇到了一些问题
,cmd. cat files.txt 2>/dev/null && find $HOME -type f -iname \*.mp3 -delete
这是我到目前为止编写的一些代码
<?php
function parse($string) {
preg_match_all("/,?([a-z_]+)?\..([a-z]+)\s([a-z\s%_]+)/", $string, $tmp);
$query = array_combine($tmp[2], $tmp[3]);
if(!empty($tmp[1])) {
return array_merge([$tmp[1][0]=>true], $query);
}
}
var_dump(parse($update['message']));
答案 0 :(得分:0)
我几乎从不建议使用命名捕获组,因为它们只会使模式和匹配项的输出数组膨胀,但是对于那些喜欢它们的人,您可以使用以下方法:
~(?:^,(?<COMMANDS>[^.]+)|\G(?!^))\.(?= )(?: (?<KEYS>\S+))? (?<VALUES>.+?(?=\. |$))~
否则:
~~(?:^,([^.]+)|\G(?!^))\.(?= )(?: (\S+))? (.+?(?=\. |$))~~
有效地,您应该使用\G
(继续元字符)继续匹配前导命令子字符串后可变数量的序列。我的模式基于以下事实:命令和后续键值对由点后紧跟一个空格分隔。如果您不能100%依靠此定界顺序,则需要解决此问题,然后再尝试前进。
一旦有了matchs数组(Demo),您只需要对其进行迭代以构建所需的输出结构即可。
代码:(Demo)
$commands = [
',simpleImage. query Dark background. width 200. height 200. text %fortune_teller%',
',sayHello. %custom_id%',
',cmd. cat files.txt 2>/dev/null && find $HOME -type f -iname \*.mp3 -delete',
];
foreach ($commands as $command) {
$result = [];
if (preg_match_all('~(?:^,([^.]+)|\G(?!^))\.(?= )(?: (\S+))? (.+?(?=\. |$))~', $command, $out)) {
foreach ($out[2] as $index => $subKey) {
if (strlen($subKey)) {
$result[$out[1][0]][$subKey] = $out[3][$index];
} else {
$result[$out[1][0]] = $out[3][$index];
}
}
}
echo var_export($result, true) . "\n---\n";
}
输出:
array (
'simpleImage' =>
array (
'query' => 'Dark background',
'width' => '200',
'height' => '200',
'text' => '%fortune_teller%',
),
)
---
array (
'sayHello' => '%custom_id%',
)
---
array (
'cmd' =>
array (
'cat' => 'files.txt 2>/dev/null && find $HOME -type f -iname \\*.mp3 -delete',
),
)
---