首页 > 解决方案 > 字符串是否包含 PHP 中的任何子字符串列表?

问题描述

我正在向应用程序添加一项功能,该功能允许授权的石油钻井平台人员通过电子邮件向我们的系统提交天气报告(供我们的飞行员在计划飞行时使用)。棘手的部分是我们希望将这些报告与特定的石油平台相匹配,但人员(及其电子邮件帐户)可以在钻井平台之间移动。

我们已经有一个航点列表,每个航点都有一个“别名”字段。基本上,如果电子邮件主题在别名字段中包含某些内容,我们应该将电子邮件与该航路点匹配。

主题可以是“根据要求为您提供 4 月 10 日 @ 1100 Rig A 的天气报告”

该航路点的别名类似于“RRA RPA Rig A RigA”

请记住,我们拥有的所有其他航点都有一个类似的别名列表。

有没有比遍历每个别名的每个单词并检查它是否是电子邮件主题的子字符串更好的匹配方法?因为这听起来像是一个 ^2 类型的问题。

另一种方法是我们设置限制并告诉操作员他们必须将钻机名称放在主题的开头或结尾。

标签: phpstringmatching

解决方案


这听起来更像是一个算法问题,而不是一个 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) 解决方案可能就足够了。(请记住,过早的优化是万恶之源!)一个简单的基准就可以证明这一点。

一个更好的解决方案 - 并且可能更快 - 是设置一个弹性搜索实例,但是当一个简单的方法在一小部分实现时间内就足够了时,这可能会再一次付出太多努力。


推荐阅读