Содержит ли строка какой-либо из списка подстрок в PHP? - PullRequest
1 голос
/ 18 апреля 2020

Я добавляю в приложение функцию, которая позволяет уполномоченному персоналу нефтяной вышки представлять отчеты о погоде (для использования нашими пилотами при планировании полетов) в нашу систему по электронной почте. Сложность в том, что мы хотим сопоставить эти отчеты с конкретной нефтяной платформой, но персонал (и его учетные записи электронной почты) могут перемещаться между буровыми установками.

У нас уже есть список точек, у каждой из которых есть псевдонимы. "поле. В основном, если в теме письма есть что-то в поле псевдонимов, мы должны сопоставить письмо с этой путевой точкой.

Тема может быть «Прогноз погоды 10 апреля @ 1100 Rig A для вас по запросу»

Псевдонимы для этой путевой точки будут выглядеть примерно так: «RRA RPA Rig A RigA»

Имейте в виду, что существует аналогичный список псевдонимов для всех остальных путевых точек.

Есть ли лучший способ сопоставления, чем итерация каждого слова каждого псевдонима и проверка, является ли это подстрокой темы письма? Потому что это звучит как проблема типа ^ 2.

В качестве альтернативы мы можем установить ограничение и сообщить операторам, что они должны указать название установки в начале или в конце темы.

1 Ответ

0 голосов
/ 18 апреля 2020

Это больше похоже на вопрос об алгоритмах, чем вопрос PHP. Взгляните на Какой самый быстрый алгоритм поиска подстроки?

Что ж, вы можете преобразовать его в нечто вроде алгоритма O (n log n), но это зависит от особенностей реализации stripos():

define('RIG_ID_1', 123);
define('RIG_ID_2', 456);

function get_rig_id($email_subject) {
    $alias_map = [
        'RRA' => RIG_ID_1,
        'RPA' => RIG_ID_1,
        'Rig A' => RIG_ID_1,
        'RigA' => RIG_ID_1,
        // ...
    ];
    foreach(array_keys($alias_map) as $rig_substr) {
        if(stripos($email_subject, $rig_substr) !== false) {
            return $alias_map[$rig_substr];
        }
    }
    return null;
}

Здесь каждая подстрока проверяется stripos() ровно один раз. Возможно, лучшим решением будет объединить эти строки в ряд регулярных выражений. Внутренне механизм регулярных выражений способен сканировать текст очень эффективно, обычно сканируя каждый символ только один раз:

пример:

<?php

define('RIG_ID_1', 123);
define('RIG_ID_2', 456);

function get_rig_id($email_subject) {
    $alias_map = [
        '/RRA|RPA|Rig\\sA|RigA/i' => RIG_ID_1,
        '/RRB|RPB|Rig\\sB|RigB/i' => RIG_ID_2,
        // ...
    ];
    foreach(array_keys($alias_map) as $rig_regex) {
        if(preg_match($rig_regex, $email_subject)) {
            return $alias_map[$rig_regex];
        }
    }
    return null;
}

Для ваших целей практическое решение очень сильно зависит от сколько у вас установок, сколько подстрок на каждую установку. Я подозреваю, что если вы не имеете дело с десятками тысяч буровых установок или если производительность не является критическим аспектом этого приложения, наивного решения O (n ^ 2), вероятно, будет достаточно. (Помните, что преждевременная оптимизация - это root всего зла!) Простой тест подтвердил бы это.

Еще лучшим решением - и, возможно, более быстрым - было бы создание экземпляраasticsearch, но, опять же, это может быть слишком большим усилием для go, когда наивный подход будет достаточен за долю времени реализации.

...