У меня есть инструкция If-else, которая проверяет строку, чтобы увидеть, есть ли ISBN-10 или ISBN-13 (идентификатор книги).
Проблема, с которой я сталкиваюсь, заключается в проверке ISBN-10, которая происходит до проверки ISBN-13, проверка ISBN-10 будет соответствовать любому значению с 10 символами или более, и поэтому может ошибиться в ISBN-13 для ISBN-10.
вот код …
$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; }
Как я могу избежать этой проблемы?
Для этого вам действительно нужно только одно регулярное выражение. Затем выполните более эффективную проверку strlen()
чтобы увидеть, какой из них был сопоставлен. Следующие значения будут соответствовать значениям ISBN-10 и ISBN-13 в строке с дефисами или без них, и необязательно предшествуют строке ISBN:
ISBN:(space)
или ISBN(space)
.
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
Это приведет к поиску предоставленной строки, чтобы увидеть, содержит ли она возможное значение ISBN-10 (возвращает 1
) или значение ISBN-13 (возвращает 2
). Если это не так, оно вернет false
.
См. ДЕМО выше.
Для строгой проверки статья Википедии для ISBN имеет некоторые функции проверки PHP для ISBN-10 и ISBN-13 . Ниже приведены примеры, скопированные, переработанные и измененные для использования с слегка измененной версией вышеуказанной функции.
Измените блок возврата на это:
return (10 === strlen($matches[1])) ? isValidIsbn10($matches[1]) // ISBN-10 : isValidIsbn13($matches[1]); // ISBN-13
Подтверждение 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; }
Подтверждение 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; }
См. ДЕМО выше.
Используйте ^
и $
для соответствия началу и концу строки. Используя ограничители строк, порядок, в котором вы тестируете 10 или 13-значные коды, не имеет значения.
/^ISBN:(\d{9}(?:\d|X))$/
/^ISBN:(\d{12}(?:\d|X))$/
Примечание. Согласно http://en.wikipedia.org/wiki/International_Standard_Book_Number , похоже, что ISBN могут иметь и -
в них. Но на основе $str
которую вы используете, похоже, что вы удалили дефисы, прежде чем проверять 10 или 13 цифр.
Дополнительное примечание: поскольку последняя цифра ISBN используется как своего рода контрольная сумма для предыдущих цифр, обычные выражения не могут подтвердить, что ISBN является допустимым. Он может проверять только 10 или 13-значные форматы.
$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"; }
Вывод
found 10-digit ISBN 1234567890 found 10-digit ISBN 123456789X found 13-digit ISBN 1234567890123 found 13-digit ISBN 123456789012X invalid ISBN
Поместите проверку ISBN-13 перед проверкой ISBN-10? Это предполагает, что вы хотите сопоставить их как часть любой строки, то есть (ваш пример имеет дополнительный «ISBN:» в начале, поэтому совпадение в любом месте строки, по-видимому, является требованием какого-то рода)
Переключите порядок блока if else
, также удалите все пробелы, двоеточия и дефисы из вашего 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; }
ISBN10_REGEX = /^(?:\d[\ |-]?){9}[\d|X]$/i ISBN13_REGEX = /^(?:\d[\ |-]?){13}$/i