我有一些字符串组,我需要通过正则表达式查找所有组,而组的顺序无关紧要
请,我需要在用户的答案中找到所有必需的成分。用户可以按任何顺序放置配料,并且可以用任何字符或字符串(空格,逗号)定界,也不需要定界符。
$string = "banana, strawberry, cherry and chocolate";
$regex = "/(banana)*(strawberry)*(cherry)*(chocolate)/";
if (preg_match($regex, $string)) {
// do something
}
我的代码中的问题是,如果用户的答案是“草莓,香蕉,樱桃”,则preg_match会将其验证为true,这很糟糕,因为在回答时也需要巧克力。或者,如果我键入“ strwberry”(草莓)而不是草莓,那也是如此。用户的答案必须以任何顺序包括所有4种成分,并且成分名称中不能包含错别字。非常感谢您的提示。
答案 0 :(得分:1)
关于您的请求:
用户可以按任何顺序放置配料,并且可以用任何字符或字符串(空格,逗号)定界,也不需要定界符。
配料顺序没有问题,我们稍后会看到。但是没有定界符是一个非常糟糕的主意!考虑以下示例(水果沙拉):
$ingredients = ['melon', 'orange', 'grape', 'apple'];
$userAnswer = 'watermelonorangegrapeapple';
问题很明显,没有办法用这种会导致误报的约束来区分“西瓜”和“西瓜”。
请不要忘记,用户应对自己写的内容负责,并且在未获得所需结果时会从自己的错误中学习。另一种方法是强制用户使用输入字段一个一个地输入配料。
用户的答案必须以任何顺序包括所有4种成分,并且其成分名称中不能包含错别字。
为什么不这样做,但是这次我的观点过于狭窄:如果用户写“ strawberries”而不是“ strawberry”怎么办?这实际上不是错字,我认为可以接受。
可能性:
让我们假设在所有可能的世界中,最好的东西都是最好的:单词是定界的,没有错字。
按照previously linked question中的建议,您可以执行以下操作:
if ( preg_match('~(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b)(?=.*\bword4\b)~Ai', $userAnswer) ) {
//...
}
但这并不是紧凑的,正确的梦想方式:
其他方法:您可以使用定界符分割用户字符串,然后使用array_diff
查看是否存在每种成分。
基本:
$delimiter = '~ \b \s* (?: , \s* | \s and \s+ ) ~uxi';
$parts = preg_split($delimiter, $userAnswer, -1, PREG_SPLIT_NO_EMPTY);
if ( empty(array_diff($ingredients, $parts)) ) {
// all ingredients are here
}
经过消毒:
$delimiter = '~ \b (?: [ ]? , [ ]? | [ ] and [ ] ) ~ux';
$userAnswer = trim(preg_replace('~[\s\pP]+~u', ' ', mb_strtolower($userAnswer)));
$parts = preg_split($delimiter, $userAnswer);
if ( empty(array_diff($ingredients, $parts)) ) {
// all ingredients are here
}
在字符串之间比较宽大:
$delimiter = '~ \b (?: [ ]? , [ ]? | [ ] and [ ] ) ~ux';
$userAnswer = trim(preg_replace('~[\s\pP]+~', ' ', mb_strtolower($userAnswer)));
$parts = preg_split($delimiter, $userAnswer);
if ( empty(array_udiff($ingredients, $parts, $callback)) ) {
// all ingredients are here
}
回调函数示例:
array_udiff
的回调函数只不过是用于对数组进行排序的比较函数,换句话说,排序是在后台进行两个数组比较的必要步骤。这就是为什么两个项目之间的比较应该得出正,负整数或0来确定顺序的原因。
PHP具有两个用于在字符串之间执行模糊比较的功能:similar_text()
和levenshtein()
。
使用左手边距离的示例。少于2表示只能替换,插入或删除一个字符,以使两个字符串相等(有关更多控制,请参见PHP手册)。
$callback = function ($a, $b) {
return levenshtein($a, $b) < 2 ? 0
: ( $a < $b ? -1 : 1 );
}
请注意,由于similar_text()
为O(max(m,n)^ 3)且levenshtein()
为O(m * n)(m和n是字符串的长度)。如果出现问题,您还可以使用metaphone()
或soundex()
之类的函数对字符串进行转换,然后再进行比较或编写自己的转换。这涉及必须预先修改包含成分的数据结构,以使比较变得容易。