Регулярное выражение для получения строк, содержащих только слова из списка шаблонов?

#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. Фильтровать массив с соответствующим соответствием второму массиву, количество которых больше 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);
?>