php - expresiones regulares que diferencian entre ISBN-10 y ISBN-13
regex validation (5)
¿Poner el cheque ISBN-13 antes del cheque ISBN-10? Esto es asumiendo que usted quiere hacer coincidirlos como parte de cualquier cadena, es decir (su ejemplo tiene un "ISBN:" adicional al comienzo, por lo que la coincidencia en cualquier parte de la cadena parece ser un requisito de algún tipo)
Tengo una declaración If-else que verifica una cadena para ver si hay un ISBN-10 o ISBN-13 (ID de libro).
El problema al que me enfrento es con la verificación ISBN-10 que ocurre antes de la verificación ISBN-13, la verificación ISBN-10 coincidirá con cualquier cosa con 10 caracteres o más y, por lo tanto, puede confundir un ISBN-13 con un ISBN-10.
Aquí está el código ...
$str = "ISBN:9780113411436";
if(preg_match("//d{9}(?:/d|X)/", $str, $matches)){
echo "ISBN-10 FOUND/n";
//isbn returned will be 9780113411
return 0;
}
else if(preg_match("//d{12}(?:/d|X)/", $str, $matches)){
echo "ISBN-13 FOUND/n";
//isbn returned will be 9780113411436
return 1;
}
¿Cómo me aseguro de evitar este problema?
Cambie el orden del bloque if else
, también elimine todos los espacios en blanco, dos puntos y guiones de su 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;
}
Realmente solo necesitas una expresión regular para esto. A continuación, realice una comprobación de strlen()
más eficiente para ver cuál fue coincidente. Lo siguiente coincidirá con los valores ISBN-10 y ISBN-13 dentro de una cadena con o sin guiones, y opcionalmente precedidos por la cadena ISBN:
ISBN:(space)
o ISBN(space)
.
Encontrar ISBNs:
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
Esto buscará una cadena proporcionada para ver si contiene un posible valor ISBN-10 (devuelve 1
) o un valor ISBN-13 (devuelve 2
). Si no lo hace devolverá false
.
Ver DEMO de arriba.
Validar los ISBN:
Para una validación estricta, el article Wikipedia para ISBN tiene algunas funciones de validación PHP para ISBN-10 y ISBN-13 . A continuación se muestran los ejemplos copiados, ordenados y modificados para usarlos en una versión ligeramente modificada de la función anterior.
Cambie el bloque de retorno a esto:
return (10 === strlen($matches[1]))
? isValidIsbn10($matches[1]) // ISBN-10
: isValidIsbn13($matches[1]); // ISBN-13
Validar 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;
}
Validar 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;
}
Ver DEMO de arriba.
Usa ^
y $
para hacer coincidir el principio y el final de la cadena. Al utilizar los delimitadores de cadena, no importará el orden en el que pruebe los códigos de 10 o 13 dígitos.
10 dígitos
/^ISBN:(/d{9}(?:/d|X))$/
13 dígitos
/^ISBN:(/d{12}(?:/d|X))$/
Nota: Según http://en.wikipedia.org/wiki/International_Standard_Book_Number , parece que los ISBN también pueden tener un -
en ellos. Pero según el $str
que está usando, parece que quitó los guiones antes de verificar 10 o 13 dígitos.
Nota adicional: como el último dígito del ISBN se utiliza como una especie de suma de comprobación para los dígitos anteriores, las expresiones regulares por sí solas no pueden validar que el ISBN sea válido. Solo puede verificar formatos de 10 o 13 dígitos.
$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";
}
Salida
found 10-digit ISBN
1234567890
found 10-digit ISBN
123456789X
found 13-digit ISBN
1234567890123
found 13-digit ISBN
123456789012X
invalid ISBN
ISBN10_REGEX = /^(?:/d[/ |-]?){9}[/d|X]$/i
ISBN13_REGEX = /^(?:/d[/ |-]?){13}$/i