【问题标题】:Matching number with predifined patterns将数字与预定义模式匹配
【发布时间】:2015-11-16 14:23:24
【问题描述】:

我有一个问题,我已经考虑了一段时间,但未能找到最佳解决方案。

该应用程序适用于一家根据号码模式以不同价格出售特殊电话号码的公司。

所以用户有一堆数字。并使用某种约定定义模式。例如:

  • (ABCDEFG) 表示序列为 (1234567, 或 2345678 等...)。
  • (ZYX-ZYXW) 表示一个数字,例如 (654-6543)。

客户取号时,该号码应与其匹配的图案相匹配,当一个图案匹配时,该号码按匹配的图案的价格收费。

我的想法集中在三个可能的解决方案上:

  1. 我试图考虑正则表达式。但不确定是否可以 工作。
  2. 另一种解决方案是遍历每种可能性 对于每个模式并将其与购买的号码相匹配。但是我 我确信这在性能方面太昂贵了。
  3. 最后我想在用户添加一个时保存所有可能的数字 模式,这样当客户想要购买一个新号码时, 应用程序不搜索模式,但搜索实际数字。这 用户添加模式时性能瓶颈的方式 (这比客户选择号码的频率要低得多)。

你们对我应该使用哪种方法有什么建议吗?非常感谢任何提示。

编辑:

我对收到的回复感到非常高兴。它们都很有启发性,但到目前为止还不能解决我的问题。现实世界的场景将具有以下条件:

  • 某些模式会遵循某种数字顺序(顺序或非顺序),例如:ABCDEFG=1234567 或 ACEGECA=2468642。
  • 某些模式将基于数字的重复,例如:xyxyxyx=1919191 或 xyxzxyx=2829282。我想以某种方式我们可以将这个条件包含在上面的条件中。
  • 某些模式会有硬编码数字,例如 ABC0ABC 或 123xyxy
  • 模式的可能性没有限制。

到目前为止,所有提出的方法都有其自身的局限性。我还在想,所以如果你想出任何有用的命中,请与我分享!

【问题讨论】:

  • 正则表达式就可以了。例如,ZYX-ZYXW 可以与 ^(\d)(\d)(\d)-\1\2\3\d$^(\d)((?!\1)\d)((?!\1|\2)\d)-\1\2\3(?!\1|\2|\3)\d$ 匹配,如果您想确保 X、Y、Z 和 W 都是不同的数字。
  • 更复杂的模式呢,比如 (ACEGECA) like (2468642)。问题是我不知道会是什么样的模式。如果我选择正则表达式方法,我需要开发一个解决方案,将正常使用添加的模式转换为正则表达式模式。这甚至可能吗?
  • 是的,这是可能的。我会写一个答案。在上面的示例中,您真的需要 A != C 吗?
  • 实际上有两种模式:一种使用可能重复也可能不重复的序列(ABC-FGH)。另一种是使用重复数字(xyxyxyx,xxy*yxx)。
  • 我偶尔会遇到类似这些问题的问题(通常与 DNA 测序有关)。过去,所采用的解决方案似乎经常涉及应用程序级别的代码——而不是试图在 SQL 上解决问题,以防万一你是这么想的。

标签: php mysql regex search


【解决方案1】:

一个想法。 demo

$number = '987-9876';
$suffix = <<<'EOD'
0123456789 ABCDEFG 10 ABCABCD 15
9876543210 GFEDCBA 8 DCBDCBA 13
EOD;

$pattern = <<<'EOD'
~
\A (?<number>(\d{3})-?(\d{4})) \R 
(?|
    \d*? # rectus
    (?|
        \2 \3 \d*
        [ ] (?<format> ABCDEFG ) [ ] (?<price>\d+)
      |
        (?=\3) \2 \d*
        (?> [ ] [A-Z]+ [ ] \d+)*? # other formats until the good one
        [ ] ( ABCABCD ) [ ] (\d+)
    )
  |
    .* \R \d*? # inversus
    (?|
        \2 \3 \d*
        [ ] ( GFEDCBA ) [ ] (\d+)
      |
        (?=\3) \2 \d*
        (?> [ ] [A-Z]+ [ ] \d+)*?
        [ ] ( DCBDCBA ) [ ] (\d+)
    )
)
~x
EOD;

if (preg_match($pattern, $number . PHP_EOL . $suffix, $m))
    echo 'number: ' . $m['number'] . PHP_EOL . 'format: ' . $m['format'] . PHP_EOL
       . 'price: ' . $m['price'];

其他方法 (可能是性能最高的)

特殊号码是有限的。您可以生成和使用包含所有特殊数字的多维数组,如下所示:

$speNum = [
    'ABCDEFG' => [ '1234567', '2345678', '3456789' ],
    'GFEDCBA' => [ '9876543', '8765432', '7654321' ],
    'ABCABCD' => [ '1231234', '2342345' ... 
];

$prices = [ 'ABCDEFG' => 10, 'ABCABCD' => 15, 'GFEDCBA' => 8 ...];

并用一个简单的foreach,测试数字是否在数组中:

foreach ($speNum as $format => $nums) {
    if (in_array($number, $nums)) {
        echo 'number: ' . $number . PHP_EOL . 'format: ' . $format . PHP_EOL
           . 'price: ' . $prices[$format];
        break;
    }
}

注意:对于第二种方法(为什么不是第一种方法),请删除前面的连字符。这种方法的主要优点是您可以轻松地将其扩展到其他类型的模式。请注意,您可以对数据库执行相同操作。

【讨论】:

  • 这看起来很有趣,但我不太擅长正则表达式。您能解释一下后缀是什么以及它的作用吗?
  • @Lamar;正则表达式引擎无法计数(它只处理字符),因此它知道 2 在 1 之后和 3 在 2 之后的唯一方法是在主题中写入排序后的数字。通过这种方式,正则表达式引擎“能够计数”(它可以识别数字中的数字是否在后缀中)。在这个“表格”之后,您可以找到格式和价格。
  • 请注意,现实生活中的模式可能非常多样化。在设计时将它们全部列出几乎是不可能的。我需要用户实时编写自己的模式(使用 A、B、C 约定),应用程序需要将其转换为正则表达式。
  • @Lamar:如果你允许用户发明他们自己的模式(所以不是已知的模式),你如何确定价格?我认为必须预先确定模式(具有相关价格的格式)才能使您的系统正常工作。
【解决方案2】:

使用以下策略: 伪代码

String getPattern(String pn,int n) 
    {
        
        int[] nums = new int[7];
        for (int i = 0; i < 7; i++)
            nums[i] = int.Parse(pn[i].ToString());
        Array.Sort(nums);
        String pat = pn;
        Char chr = 'A';
        for (int i = 0; i < 7; i++)
        {
            if (nums[i] != n)
            {
                pat = pat.Replace(nums[i].ToString(), chr.ToString());
                if ((i + 1) < 7)
                {
                    int shif = nums[i + 1] - nums[i];
                    chr = (Char)(Convert.ToUInt16(chr) + shif);
                }
            }

        }
        return pat;
    }

它在 c# 中对我有用,它会自动检测输入数字的模式 您也可以将其开发为更高级(例如添加 zyx 模式检测)

【讨论】:

  • 谢谢,这很有启发性。我敢问你如何检测其他类型的重复模式,例如(xyxyxyx,xyz*xyz),其中顺序无关。
  • 其实我现在在想。我们可能会使用硬编码数字进行模式,例如 ABC0ABC。我认为使用您的反向方法可能无法涵盖这些情况。
  • 感谢您的帮助,事实上我的意思是任何数字,而不仅仅是零。真正的问题是我不知道模式可能是什么。无论如何,我正在尝试自己编写代码。完成后,我会将最终结果发布到问题中。同时分享的任何想法或建议都非常感谢:)
猜你喜欢
  • 1970-01-01
  • 2018-10-03
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
  • 1970-01-01
  • 2012-04-01
相关资源
最近更新 更多