2017-06-17 46 views
0

我试图使用preg_match()在PHP做一个模式匹配具有此模式4位数字:如何搜索相邻的重复号码?

0033 
1155 
2277 

基本上第2个数字相同,并且在最后两位数字是相同的,但不是所有的4位数都是一样的。

preg_match()即使正确的功能使用?或者我应该将它们分开并按照这种方式进行匹配?

+0

为了记录,试图对此使用正则表达式非常困难。它可能可以完成,但我无法想象结果会是什么样子。需要这两个组的重复数字不同,这使得写出真正困难的正则表达式。使用其他解决方案你会更好。如果你可以放弃这个要求,'(\ d)\ 1(\ d)\ 2'可能会起作用。 – Joel

+0

@Joel我可以问\ 1和\ 2是什么意思?因为如果我有一个数字113022它匹配(\ d)\ 1 [30] +(\ d)\ 2。为什么?我认为\ 1和\ 2是数字的位置...... – John

+0

这些是捕获组的参考。这允许你指定一个捕获组应该被加倍或者增加三倍或者任何你想要的。您可以通过添加边界'^(\ d)\ 1(\ d)\ 2 $'来阻止它接受那种输入。这会将您的输入限制为4位“单词”。 – Joel

回答

1

您可以使用类似array_filter一个比较回调:

function compare($number) { 
    // Compare first 2 numbers 
    if (intval($number[0]) !== intval($number[1])) { 
     return false; 
    } 

    // Compare last 2 numbers 
    if (intval($number[2]) !== intval($number[3])) { 
     return false; 
    } 

    // Make sure first and last numbers aren't the same 
    if (intval($number[0]) === intval($number[3])) { 
     return false; 
    } 

    return true; 
} 

$data = array_filter($data, 'compare'); 

你也可以做到这一点使用一个封闭:

$data = array_filter($data, function($number) { 
    return intval($number[0]) === intval($number[1]) && intval($number[2]) === intval($number[3]) && intval($number[0]) !== intval($number[3]); 
}); 

例子在这里:http://ideone.com/0VwJz8

+0

这个答案并不要求每个字符都是一个数字,'str_split()'不是必需的,因为可以使用字符串偏移量进行相同的比较。使用三个单独的if语句意味着代码膨胀,更好地使用一组条件,如匿名'array_filter()'方法。卡西米尔的模式/方法可以根据需要执行,并可以与其他正则表达式模式组合使用,以在单个步骤中提取更多数据。 – mickmackusa

+0

@mickmackusa你说得对,不需要'str_split'然而,即使它是更多的代码是单次运行效率比使用'preg_match'这将在更大的数据集而加剧:http://ideone.com/ SZ7sRW/http://ideone.com/g7Txf8。我在方法中分解了它,以便OP能够看到每个语句在做什么。您可以在处理之前通过转换为int或使用sprintf来避开字符串限制,因为这会导致字符串因第三个条件失败,因为每个字母都将转换为零。 – sjdaws

+0

现在,它在每次迭代时看起来像3次比较和6次函数调用。我更喜欢一个'preg_match()'调用。 – mickmackusa

3

要搜索这种您可以使用的文字号码:

preg_match('~\b(\d)\1(?!\1)(\d)\2\b~', $str, $m) 

(或preg_match_all如果你想所有的人)

细节:

~  # pattern delimiter 
\b  # word boundary (to be sure that 1122 isn't a part of 901122) 
(\d)  # capture the first digit in group 1 
\1  # back-reference to the group 1 
(?!\1) # negative lookahead: check if the reference doesn't follow 
(\d)  # 
\2  # 
\b  # word boundary (to be sure that 1122 isn't a part of 112234) 
~  # 

如果你想检查是否整个字符串是数字,来代替使用字符串限制锚字边界:

~\A(\d)\1(?!\1)(\d)\2\z~ 
+0

好吧,这看起来像。不知道如果我需要创建一个新问题,但是将代码放在那里,是否有自动使用它来匹配任何模式的方法? XXYY0所以XX表示相同的数字,YY表示相同的数字,但不同于XX,然后是0,只是搜索0.或者模式可能是XXX0,所以5550会匹配。你能想出一种方法来编写动态构建匹配代码的代码,以匹配传递的模式吗? – John

+0

无论哪种方式,我会接受你的答案,只是想看看我们是否可以再采取一步来匹配我上面提到的模式。 – John

+0

@John你可以使用这个:http://sandbox.onlinephpfunctions.com/code/f1589e5e89b0c810662851a978f2696f3632610e – mickmackusa