【问题标题】:Regex Name Query Based on Phone Keypad基于电话键盘的正则表达式名称查询
【发布时间】:2013-02-19 14:47:45
【问题描述】:

从这里开始,我没有示例代码,我正在寻求有关这是否可能的建议以及有关如何操作的一些指示..

有人要求我创建一个 PHP 脚本来搜索我们的 Windows LDAP 通讯簿。 为了让事情变得尴尬,我被要求这样做,以便前端看起来像电话键盘,并且用户使用数字键盘输入姓名。

在我看来,数字将与字母相关:

2 = ABC
3 = DEF
4 = GHI
5 = JKL
6 = MNO
7 = PQRS
8 = TUV
9 = WXYZ

我可以看到两种不同的方式来做到这一点。

  1. 当用户输入第一个数字时,开始构建一个匹配数组,然后在他们输入第二个和第三个匹配时减少它。

  2. 建立输入的数字列表,然后搜索明确的匹配项。

我可以看到另一个问题,我需要知道用户输入了哪个数字以及何时在字符串中。

例如:用户输入 6 4 5 这将需要匹配为:

M, N or O, as the first character.
G, H or I as the second character.
J, K or L as the thrid character.

有没有人给点意见​​、指点?

谢谢

【问题讨论】:

  • 告诉任何一位经理认为这是一个停止做智障的想法?用户面前有一个完整的键盘,为什么他们要从电话式键盘输入字母。此外,您需要 javascript 来处理输入和字母过滤,而不是 php 中的正则表达式。使用 jquery 和 ajax 作为实际的通行信来搜索自动建议文本框之类的内容,这将与作为 ajax 请求页面的 LDAP 查询页面完美配合。
  • 那个电话簿有多少条目?一个近似值就足够了
  • 如果您希望它像真正的老式数字电话一样工作,那么我想您需要在用户输入字符后设置一个短计时器,以防用户想再次写入相同的字符。例如。亚瑟。 A - 如果用户在计时器内再次按下 1,则显示 B - 如果用户在计时器内再次按下 1,则显示 C 等并重复,但如果计时器已过,则编写另一个 A。不过,您的任务很愚蠢!: )
  • 感谢您的回复。我个人不想要电话键盘,但这不是我的电话:(通讯簿中目前大约有 3000 个条目

标签: php jquery ajax search


【解决方案1】:

这当然会限制对 LDAP 的调用。在您请求第一个数字的名称后,您仍然可以使用 getCombinations 函数过滤以下数字:

function startsWith($haystack, $needle) { 
    return !strncmp(strtoupper($haystack), $needle, strlen($needle)); 
} 


$combinations = getCombinations(array(6, 4, 5));
$results = array();
foreach ($resultsForFirstDigit as $ldapEntry) {
    foreach ($combinations as $combination) {
        if (startsWith($ldapEntry['sn'], $combination) {
            $result[] = $ldapEntry;
        }
    }
}

【讨论】:

    【解决方案2】:

    我同意 Dave 的观点,这确实是一个愚蠢的想法,但在您手动进行整个过滤之前,LDAP 过滤器可能是一个解决方案。您必须为可能的组合创建一个巨大的过滤器:

    function getCombinations(array $digits = array())
    {
        $digitToLetters = array(
            2 => array('A', 'B', 'C'),
            3 => array('D', 'E', 'F'),
            4 => array('G', 'H', 'I'),
            5 => array('J', 'K', 'L'),
            6 => array('M', 'N', 'O'),
            7 => array('P', 'Q', 'R', 'S'),
            8 => array('T', 'U', 'U'),
            9 => array('W', 'B', 'Y', 'Z')
        );
    
        $values = array('');
        foreach ($digits as $digit) {
            $newValues = array();
            foreach ($values as $value) {
                if (array_key_exists($digits[0], $digitToLetters)) {
                    foreach ($digitToLetters[$digit] as $letters) {
                        $newValues[] = $value . $letters;
                    }
                }
            }
            $values = $newValues;
        }
    
        return $values;
    }
    
    function getFilterForDigits(array $digits = array()) {
        $combinations = getCombinations($digits);
        $filter = '(|(sn=' . implode('*)(sn=', $combinations) . '*))';
    }
    

    假设您仅按姓氏 (sn) 进行过滤,但您可以轻松更改它,因此它可能适合 givenName - 请记住,如果您想同时过滤两者,过滤器大小会加倍,这可能会导致 LDAP 请求变慢。

    要过滤输入645 的所有可能结果,可以调用:

    $ds = ldap_connect("...");
    $result = ldap_search($ds, "...", getFilterForDigits(array(6, 4, 5)));
    

    我仍然强烈建议您不要这样做,但如果您束手无策,请确保您实施某种缓存。 :)

    【讨论】:

    • 谢谢,我会试试这个。我已经开始了,但在另一个方向。我已经开始根据输入的第一个数字的 ldap 搜索来构建一个名称数组。因此,如果输入 2,它会将所有以 A、B 或 C 开头的名称返回到数组中。这部分正在工作。然后我的计划是尝试根据输入的第 2 位和第 3 位数字从数组中删除条目。如果 3 是输入的第二个数字,则从数组中删除没有 D、E 或 F 的任何内容,因为它是第二个字符等。然后对第三个数字执行相同的操作。不知道这是否是一个好方法!
    猜你喜欢
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 2011-09-13
    • 2011-02-20
    • 2010-09-21
    相关资源
    最近更新 更多