#php #regex #preg-match #preg-match-all #preg-grep
#php #регулярное выражение #preg-match #preg-match-all #preg-grep
Вопрос:
Рассмотрим следующие элементы массива
1.benclinton
2.clintonharry
3.harryben
4.benwill
5.jasonsmith
6.smithclinton
Предположим, что список шаблонов — это Бен, Гарри, Клинтон, тогда результат, который я должен получить, это
1.benclinton
2.clintonharry
3.harryben
Итак, по сути, результат должен содержать строки, содержащие только слова, которые есть в списке шаблонов. Порядок не важен
Кроме того, каждая строка не будет содержать более двух слов. т.е. bensmithwill никогда не будет case.
Поскольку все мои строки находятся в массиве, я думал использовать preg_grep в php для этого, но я поражен тем, что не могу создать правильное регулярное выражение для этого.
какое регулярное выражение может этого достичь? Есть ли какой-либо другой эффективный способ, кроме сопоставления с регулярным выражением, который выполнит эту работу?
Заранее спасибо!
Ответ №1:
Что-то вроде этого
$names_list = ['benclinton','clintonharry','harryben','benwill','jasonsmith','smithclinton'];
$names = ['ben','harry','clinton'];
$matches = preg_grep('/('.implode('|',$names).')(?1)/', $names_list);
//- /(ben|harry|clinton)(?1)/ -- (?1) = recurse capture group 1
print_r($matches);
Вывод
Array
(
[0] => benclinton
[1] => clintonharry
[2] => harryben
)
Для этого требуется, чтобы по крайней мере два имени (даже одно и то же 2 раза) совпадали. Но в данном случае это своего рода данность, иначе все соответствовало бы.
Если вы хотите быть особенно внимательными, $names
может ли
содержать что-то важное для регулярного выражения, такое как *
,
,,, и т.д. вы можете добавить это
$matches = preg_grep('/('.implode('|',array_map(function($name){return preg_quote($name,'/');},$names)).')(?1)/', $names_list);
Комментарии:
1. Это соответствует
benbenclinton
. Не уверен, ожидает ли OP, что термин будет точным совпадением двух подстрок.2. @TimBiegeleisen — как и у вас. Песочница
3.Я могу сделать то же самое с
^
и$
Sandbox — просто говорю. 🙂
Ответ №2:
Похоже, вы хотите сопоставить элементы массива, которые являются точными комбинациями двух ключевых слов. Для подхода с использованием регулярных выражений мы можем попробовать взять перекрестное произведение вектора ключевых слов, а затем сгенерировать чередование. Затем мы можем использовать preg_grep
против вашего входного массива, чтобы найти все совпадающие элементы.
$array = array("benclinton", "clintonharry", "harryben", "benwill", "jasonsmith", "smithclinton");
$input = array("ben", "harry", "clinton");
$regex = "";
foreach ($input as $term1) {
foreach ($input as $term2) {
if ($regex != "") $regex .= "|";
$regex .= $term1.$term2;
}
}
$regex = "/^(" . $regex . ")$/";
$matches = preg_grep($regex, $array);
print_r($matches);
Array
(
[0] => benclinton
[1] => clintonharry
[2] => harryben
)
Вот чередование регулярных выражений, сгенерированное вышеупомянутым скриптом:
(benben|benharry|benclinton|harryben|harryharry|harryclinton|clintonben|
clintonharry|clintonclinton)
Комментарии:
1. Спасибо. Есть ли какой-либо способ без использования цикла for?
Ответ №3:
Без регулярного выражения.Делать с array_filter
и strpos
- Фильтровать массив с соответствующим соответствием второму массиву, количество которых больше 1
<?php
$a = ['benclinton','clintonharry','harryben','benwill','jasonsmith','smithclinton'];
$a2 = ['ben','clinton','harry'];
$res = array_filter($a,function($str="") use($a2){
$r =array_filter($a2,function($a2str) use($str){
return strpos($str,$a2str) !== FALSE;
});
return count($r) > 1;
});
print_r($res);
?>