le regex différencie L'ISBN-10 de L'ISBN-13

j'ai une instruction If-else qui vérifie une chaîne pour voir s'il y a un ISBN-10 ou un ISBN-13 (ID de livre).

le problème auquel je suis confronté est avec la vérification ISBN-10 qui se produit avant la vérification ISBN-13, la vérification ISBN-10 va correspondre à tout ce qui a 10 caractères ou plus et donc peut confondre un ISBN-13 pour un ISBN-10.

voici le code...

$str = "ISBN:9780113411436";

if(preg_match("/d{9}(?:d|X)/", $str, $matches)){
   echo "ISBN-10 FOUNDn";  
   //isbn returned will be 9780113411
   return 0;
}

else if(preg_match("/d{12}(?:d|X)/", $str, $matches)){
   echo "ISBN-13 FOUNDn";
   //isbn returned will be 9780113411436
   return 1;
}

Comment puis-je m'assurer d'éviter ce problème?

20
demandé sur cryptic ツ 2012-12-31 03:30:35

5 réponses

vous n'avez vraiment besoin que d'un seul regex pour cela. Alors faites un plus efficace strlen() vérifier pour voir lequel correspond. Ce qui suit correspondra aux valeurs ISBN-10 et ISBN-13 dans une chaîne avec ou sans trait d'Union, et éventuellement précédée de la chaîne ISBN:,ISBN:(space) ou ISBN(space).

Trouver Isbn :

function findIsbn($str)
{
    $regex = '/\b(?:ISBN(?:: ?| ))?((?:97[89])?\d{9}[\dx])\b/i';

    if (preg_match($regex, str_replace('-', '', $str), $matches)) {
        return (10 === strlen($matches[1]))
            ? 1   // ISBN-10
            : 2;  // ISBN-13
    }
    return false; // No valid ISBN found
}

var_dump(findIsbn('ISBN:0-306-40615-2'));     // return 1
var_dump(findIsbn('0-306-40615-2'));          // return 1
var_dump(findIsbn('ISBN:0306406152'));        // return 1
var_dump(findIsbn('0306406152'));             // return 1
var_dump(findIsbn('ISBN:979-1-090-63607-1')); // return 2
var_dump(findIsbn('979-1-090-63607-1'));      // return 2
var_dump(findIsbn('ISBN:9791090636071'));     // return 2
var_dump(findIsbn('9791090636071'));          // return 2
var_dump(findIsbn('ISBN:97811'));             // return false

ceci va rechercher une chaîne de caractères fournie pour voir si elle contient une valeur ISBN-10 possible (retourne 1) ou une valeur ISBN-13 (renvoie 2). Si c' n'est-ce pas sera de retour false.

Voir DEMO de ci-dessus.


Validation ISBNs:

strict validation de la Wikipédia article pour ISBN a quelques fonctions de validation PHP pour ISBN-10 et ISBN-13. Vous trouverez ci-dessous les exemples copiés, rangés et modifiés pour être utilisés dans une version légèrement modifiée de ce qui précède. fonction.

changez le bloc de retour en ceci:

    return (10 === strlen($matches[1]))
        ? isValidIsbn10($matches[1])  // ISBN-10
        : isValidIsbn13($matches[1]); // ISBN-13

Validate ISBN-10:

function isValidIsbn10($isbn)
{
    $check = 0;

    for ($i = 0; $i < 10; $i++) {
        if ('x' === strtolower($isbn[$i])) {
            $check += 10 * (10 - $i);
        } elseif (is_numeric($isbn[$i])) {
            $check += (int)$isbn[$i] * (10 - $i);
        } else {
            return false;
        }
    }

    return (0 === ($check % 11)) ? 1 : false;
}

Validate ISBN-13:

function isValidIsbn13($isbn)
{
    $check = 0;

    for ($i = 0; $i < 13; $i += 2) {
        $check += (int)$isbn[$i];
    }

    for ($i = 1; $i < 12; $i += 2) {
        $check += 3 * $isbn[$i];
    }

    return (0 === ($check % 10)) ? 2 : false;
}

Voir DEMO de ci-dessus.

39
répondu cryptic ツ 2014-02-21 19:00:26

Utiliser ^ et $ pour faire correspondre le début et la fin de la chaîne. En utilisant les délimiteurs de chaîne, l'ordre dans lequel vous testez les codes à 10 ou 13 chiffres n'aura pas d'importance.

10 chiffres

/^ISBN:(\d{9}(?:\d|X))$/

13 chiffres

/^ISBN:(\d{12}(?:\d|X))$/

Remarque: Selon http://en.wikipedia.org/wiki/International_Standard_Book_Number, il semble que l'Isbn peut avoir un -. Mais basé sur le $str vous utilisez, il semble que vous avez enlevé les traits d'union avant de vérifier pour 10 ou 13 chiffres.

notes: parce que le dernier chiffre de L'ISBN est utilisé comme une sorte de somme de contrôle pour les chiffres précédents, les expressions régulières seules ne peuvent pas valider que L'ISBN est valide. Il peut seulement 10 ou 13 chiffres formats.


$isbns = array(
  'ISBN:1234567890',       // 10-digit
  'ISBN:123456789X',       // 10-digit ending in X
  'ISBN:1234567890123',    // 13-digit
  'ISBN:123456789012X',    // 13-digit ending in X
  'ISBN:1234'              // invalid
);

function get_isbn($str) {
   if (preg_match('/^ISBN:(\d{9}(?:\d|X))$/', $str, $matches)) {
      echo "found 10-digit ISBN\n";
      return $matches[1];
   }
   elseif (preg_match('/^ISBN:(\d{12}(?:\d|X))$/', $str, $matches)) {
      echo "found 13-digit ISBN\n";
      return $matches[1];
   }
   else {
      echo "invalid ISBN\n";
      return null;
   }
}

foreach ($isbns as $str) {
   $isbn = get_isbn($str);
   echo $isbn."\n\n";
}

Sortie

found 10-digit ISBN
1234567890

found 10-digit ISBN
123456789X

found 13-digit ISBN
1234567890123

found 13-digit ISBN
123456789012X

invalid ISBN
3
répondu maček 2012-12-30 23:56:20

mettre la vérification ISBN-13 avant la vérification ISBN-10? Ceci suppose que vous voulez les apparier comme faisant partie de n'importe quelle chaîne, c'est-à-dire (votre exemple a un "ISBN:" supplémentaire au début donc apparier n'importe où dans une chaîne semble être une exigence d'une certaine sorte)

1
répondu Matti Virkkunen 2012-12-30 23:32:59

changer l'ordre de la if else bloc, également supprimer tous les espaces, virgules, et des traits d'union à partir de votre ISBN:

//Replace all the fluff that some companies add to ISBNs
$str = preg_replace('/(\s+|:|-)/', '', $str);

if(preg_match("/^ISBN\d{12}(?:\d|X)$/", $str, $matches)){
   echo "ISBN-13 FOUND\n";
   //isbn returned will be 9780113411436
   return 1;
}

else if(preg_match("/^ISBN\d{9}(?:\d|X)$/", $str, $matches)){
   echo "ISBN-10 FOUND\n";  
   //isbn returned will be 9780113411
   return 0;
}
0
répondu Will C. 2012-12-31 00:02:01
ISBN10_REGEX = /^(?:\d[\ |-]?){9}[\d|X]$/i
ISBN13_REGEX = /^(?:\d[\ |-]?){13}$/i
0
répondu Naeem Ul Hassan 2016-08-11 07:46:49