2017-06-17 8 views
0

Je suis en train d'utiliser preg_match() en PHP pour faire un match de modèle pour les numéros 4 chiffres qui ont ce modèle:Comment puis-je rechercher des numéros en double l'un à côté de l'autre?

0033 
1155 
2277 

Fondamentalement, les 2 premiers chiffres sont les mêmes et les 2 derniers chiffres sont les mêmes, mais les 4 chiffres ne sont pas tous identiques.

Est-ce que la fonction correcte est d'utiliser preg_match()? Ou devrais-je simplement les séparer et faire comme ça?

+0

Pour l'anecdote, essayer d'utiliser des expressions régulières est assez difficile. Cela peut probablement être fait, mais je ne peux pas imaginer à quoi ressemblerait le résultat. Ayant besoin que les deux groupes diffèrent dans leurs chiffres récurrents, il est vraiment difficile d'écrire une regex. Il vaut mieux utiliser une autre solution. Si vous pouviez vous passer de cette exigence, '(\ d) \ 1 (\ d) \ 2' fonctionnerait probablement. – Joel

+0

@Joel Puis-je demander ce que \ 1 et \ 2 signifient? Parce que si j'avais un numéro 113022 il correspond à (\ d) \ 1 [30] + (\ d) \ 2. Pourquoi? Je pensais \ 1 et \ 2 étaient la position du nombre ... – John

+0

Ce sont des références de groupe de capture. Cela vous permet de spécifier qu'un groupe de capture doit être doublé ou triplé ou ce que vous voulez. Vous pouvez l'empêcher d'accepter une entrée de ce type en ajoutant des limites '^ (\ d) \ 1 (\ d) \ 2 $'. Cela limitera vos entrées à "mots" à 4 chiffres. – Joel

Répondre

1

Vous pouvez utiliser quelque chose comme array_filter avec un rappel de comparaison:

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'); 

Vous pouvez aussi le faire en utilisant une fermeture:

$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]); 
}); 

Exemples ici: http://ideone.com/0VwJz8

+0

Cette réponse n'exige pas que chaque caractère soit un chiffre, et 'str_split()' n'est pas nécessaire car les mêmes comparaisons peuvent être faites en utilisant des offsets de chaîne. L'utilisation de trois instructions if distinctes signifie que le code est bloat, mieux vaut utiliser un seul ensemble de conditions comme dans la méthode 'array_filter()' anonyme. Le modèle/méthode de Casimir fonctionne comme souhaité et peut être utilisé en combinaison avec d'autres modèles d'expressions régulières pour extraire plus de données en une seule étape. – mickmackusa

+0

@mickmackusa vous avez raison de ne pas exiger 'str_split' mais même si c'est plus de code c'est plus efficace pour une seule exécution que d'utiliser' preg_match' qui sera exacerbé sur un ensemble de données plus important: http://ideone.com/ SZ7sRW/http://ideone.com/g7Txf8. Je l'ai décomposé dans la méthode afin que OP puisse voir ce que chaque déclaration faisait. Vous pouvez contourner la limitation de chaîne en envoyant un int ou en utilisant sprintf avant le traitement, car cela entraînera l'échec de la troisième condition, car chaque lettre sera convertie en zéro. – sjdaws

+0

Maintenant, il ressemble à 3 comparaisons et 6 appels de fonction à chaque itération.Je préférerais un seul appel 'preg_match()'. – mickmackusa

3

pour rechercher ce genre de nombre dans un texte que vous pouvez utiliser:

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

(ou avec preg_match_all si vous voulez tous)

détails:

~  # 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) 
~  # 

Si vous voulez vérifier si une chaîne entière est le nombre, utilisez les ancres limites de chaîne en place des limites de mots:

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

Ok ça ressemble à ça. Je ne sais pas si j'ai besoin de créer une nouvelle question, mais en prenant votre code là-bas, est-il possible de l'utiliser automatiquement pour correspondre à n'importe quel modèle comme ça? XXYY0 Donc XX signifie le même nombre, YY signifie le même nombre mais pas le même que XX et ensuite 0, en cherchant simplement 0. Ou le modèle pourrait être XXX0, donc 5550 correspondrait. Pouvez-vous penser à un moyen d'écrire du code qui construit dynamiquement votre code correspondant pour correspondre à n'importe quel modèle qui est passé? – John

+0

De toute façon je vais accepter votre réponse, je veux juste voir si nous pouvons prendre une étape de plus à utiliser pour correspondre au modèle que j'ai mentionné ci-dessus. – John

+0

@John Vous pouvez utiliser ceci: http://sandbox.onlinephpfunctions.com/code/f1589e5e89b0c810662851a978f2696f3632610e – mickmackusa