Вам необходимо проверить действительность международного стандартного номера книги (ISBN), который может быть как в старом формате ISBN-10, так и в современном ISBN-13.
Вы хотите разрешить ведущий идентификатор «ISBN», а части ISBN по желанию могут быть разделены дефисами или пробелами. Ниже приведены примеры правильного ввода:
- ISBN 978-0-596-52068-7
- ISBN-13: 978-0-596-52068-7
- 978 0 596 52068 7
- 9780596520687
- ISBN-10 0-596-52068-9
- 0-596-52068-9
Вы не можете проверить ISBN только с помощью regex, потому что последняя цифра вычисляется с помощью алгоритма контрольной суммы. Регулярные выражения, приведенные в этом разделе, проверяют формат ISBN, а последующие примеры кода включают проверку достоверности последней цифры.
Регулярные выражения
Далее следуют три решения регулярных выражений, которые позволяют сопоставлять ISBN-10 и ISBN-13, как по отдельности, так и вместе. Каждое из решений показано с использованием свободного интервала и комментариев, а также без них. JavaScript не поддерживает свободный интервал, но в других языках программирования вы можете выбрать то, что вам больше подходит.
В регексах со свободным интервалом буквальные символы пробела экранированы обратными слэшами. Режим свободного интервала в Java требует экранирования даже пробелов внутри классов символов.
ISBN-10:
1 | ^(?:ISBN(?:-10)?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$)[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$ |
- (?:ISBN(?:-10)?:?\ )? - Необязательный идентификатор ISBN/ISBN-10.
- (?= - Базовые предварительные проверки формата (заблаговременная проверка)
- [0-9X]{10}$ - Требуется 10 цифр/X (без разделителей).
- | - Или
- (?=(?:[0-9]+[-\ ]){3}) - Требуется 3 разделителя
- [-\ 0-9X]{13}$ - из 13 символов всего.
- ) - Завершить предварительную проверку формата.
- [0-9]{1,5}[-\ ]? - 1-5-значный идентификатор группы.
- [0-9]+[-\ ]?[0-9]+[-\ ]? - Идентификаторы издателя и названия.
- [0-9X] - Контрольная цифра.
ISBN-13:
1 | ^(?:ISBN(?:-13)?:? )?(?=[0-9]{13}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)97[89][- ]?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9]$ |
- (?:ISBN(?:-13)?:?\ )? - Необязательный идентификатор ISBN/ISBN-13.
- (?= - Базовые предварительные проверки формата (заблаговременная проверка)
- [0-9]{13}$ - Требуется 13 цифр (без разделителей).
- | - Или
- (?=(?:[0-9]+[-\ ]){4}) - Требуется 4 разделителя
- [-\ 0-9]{17}$ - Всего 17 символов.
- ) - Завершаем предварительную проверку формата.
- 97[89][-\ ]? - Префикс ISBN-13.
- [0-9]{1,5}[-\ ]? - 1-5-значный идентификатор группы.
- [0-9]+[-\ ]?[0-9]+[-\ ]? - Идентификаторы издателя и названия.
- [0-9] - Контрольная цифра.
ISBN-10 или ISBN-13:
1 | ^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$ |
- (?:ISBN(?:-1[03]):?\ )? - Необязательный идентификатор ISBN/ISBN-10/ISBN-13.
- (?= - Основные предварительные проверки формата (lookahead)
- [0-9X]{10}$ - Требуется 10 цифр/X (без разделителей).
- | - Или:
- (?=(?:[0-9]+[-\ ]){3}) - Требуется 3 разделителя
- [-\ 0-9X]{13}$ - из 13 символов всего.
- | - Или:
- 97[89][0-9]{10}$ - 978/979 плюс 10 цифр (всего 13).
- | - Или:
- (?=(?:[0-9]+[-\ ]){4}) - Требуется 4 разделителя
- [-\ 0-9]{17}$ - всего 17 символов.
- ) - Завершаем предварительную проверку формата.
- (?:97[89][-\ ]?)? - Необязательный префикс ISBN-13.
- [0-9]{1,5}[-\ ]? - 1-5-значный идентификатор группы.
- [0-9]+[-\ ]?[0-9]+[-\ ]? - Идентификаторы издателя и названия.
- [0-9X] - Контрольная цифра.
Пример JavaScript с проверкой контрольной суммы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var subject = document.getElementById("isbn").value; // Проверка формата ISBN-10 или ISBN-13 var regex = /^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$| (?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$| (?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]? [0-9]+[- ]?[0-9]+[- ]?[0-9X]$/; if (regex.test(subject)) { // Удалите цифры, не относящиеся к ISBN, затем разделите на массив var chars = subject.replace(/[- ]|^ISBN(?:-1[03])?:?/g, "").split(""); // Удалите последнюю цифру ISBN из `chars` и присвойте ее `last`. var last = chars.pop(); var sum = 0; var check, i; if (chars.length == 9) { // Вычислите контрольную цифру ISBN-10 chars.reverse(); for (i = 0; i < chars.length; i++) { sum += (i + 2) * parseInt(chars[i], 10); } check = 11 - (sum % 11); if (check == 10) { check = "X"; } else if (check == 11) { check = "0"; } } else { // Compute the ISBN-13 check digit for (i = 0; i < chars.length; i++) { sum += (i % 2 * 2 + 1) * parseInt(chars[i], 10); } check = 10 - (sum % 10); if (check == 10) { check = "0"; } } if (check == last) { alert("Valid ISBN"); } else { alert("Invalid ISBN check digit"); } } else { alert("Invalid ISBN"); } |
Пример на языке Python, с проверкой контрольной суммы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import re import sys subject = sys.argv[1] # Проверяет формат ISBN-10 или ISBN-13 regex = re.compile("^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$| (?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$| (?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]? [0-9]+[- ]?[0-9]+[- ]?[0-9X]$") if regex.search(subject): # Удалите цифры, не относящиеся к ISBN, затем разделите на список chars = list(re.sub("[- ]|^ISBN(?:-1[03])?:?", "", subject)) # Удалите последнюю цифру ISBN из `chars` и присвойте ее `last`. last = chars.pop() if len(chars) == 9: # Вычислите контрольную цифру ISBN-10 val = sum((x + 2) * int(y) for x,y in enumerate(reversed(chars))) check = 11 - (val % 11) if check == 10: check = "X" elif check == 11: check = "0" else: # Вычислите контрольную цифру ISBN-13 val = sum((x % 2 * 2 + 1) * int(y) for x,y in enumerate(chars)) check = 10 - (val % 10) if check == 10: check = "0" if (str(check) == last): print("Valid ISBN") else: print("Invalid ISBN check digit") else: print("Invalid ISBN") |
Обсуждение
ISBN - это уникальный идентификатор для коммерческих книг и книгоподобных продуктов. 10-значный формат ISBN был опубликован в качестве международного стандарта ISO 2108 в 1970 году. Все ISBN, присвоенные с 1 января 2007 года, являются 13-значными.
Номера ISBN-10 и ISBN-13 состоят из четырех или пяти элементов соответственно. Три из них имеют переменную длину, остальные один или два элемента - фиксированную длину. Все пять элементов обычно разделяются дефисами или пробелами. Ниже приводится краткое описание каждого элемента:
- 13-значные ISBN начинаются с префикса 978 или 979.
- Идентификатор группы идентифицирует группу стран с общим языком. Его длина варьируется от одной до пяти цифр.
- Идентификатор издателя может быть разной длины и присваивается национальным агентством ISBN.
- Идентификатор заглавия также может быть разной длины и выбирается издателем.
- Последний символ называется контрольной цифрой и вычисляется с помощью алгоритма контрольной суммы. Контрольная цифра ISBN-10 может быть либо числом от 0 до 9, либо буквой X (римская цифра, обозначающая 10), в то время как контрольная цифра ISBN-13 - от 0 до 9. Допустимые символы различаются, потому что эти два типа ISBN используют разные алгоритмы контрольной суммы.
Все три регекса, показанные ранее, состоят из похожих частей, поэтому здесь мы сосредоточимся на регексе «ISBN-10 или ISBN-13». Его ведущая часть '^(?:ISBN(?:-1[03])?:? )?' имеет три необязательных элемента, что позволяет ему соответствовать любой из следующих семи строк (все, кроме варианта «пустая строка», включают символ пробела в конце):
- ISBN
- ISBN-10
- ISBN-13
- ISBN:
- ISBN-10:
- ISBN-13:
- Пустая строка (без префикса)
После ведущего '^(?:ISBN(?:-1[03])?:? )?', о котором мы только что говорили, идет положительный заголовок, который устанавливает один из четырех вариантов (разделенных оператором чередования '|') для длины и набора символов остальной части совпадения, а также количество допустимых разделителей (ноль или три для ISBN-10 и ноль или четыре для ISBN-13). Поскольку в нем есть четыре альтернативы, заставка довольно длинная. Here’s the full lookahead: ‹(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)›. Так как сам по себе этот вариант трудно проанализировать, далее показаны все четыре варианта, входящие в него. Все они заканчиваются якорем '$', который гарантирует, что в тексте не может быть никаких следов, не вписывающихся ни в один из шаблонов:
- '[0-9X]{10}$' - Позволяет указывать ISBN-10 без разделителей (всего 10 символов)
- (?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$ -Разрешает ISBN-10 с тремя разделителями (всего 13 символов)
- '97[89][0-9]{10}$' - Позволяет указывать ISBN-13 без разделителей (всего 13 символов)
- (?=(?:[0-9]+[- ]){4})[- 0-9]{17}$ -Разрешает ISBN-13 с четырьмя разделителями (всего 17 символов)
Два из этих вариантов (те, которые допускают разделители) включают собственные вложенные заставки, чтобы убедиться в наличии нужного количества разделителей, а затем перейти к проверке длины строки.
После того как положительная заставка проверит длину, набор символов и количество разделителей, мы сможем сопоставить отдельные элементы ISBN, не заботясь об их суммарной длине. '(?:97[89][- ]?)?' соответствует префиксу «978» или «979», требуемому для ISBN-13. Группа «не захват» необязательна, так как она не будет соответствовать строке темы ISBN-10. '[0-9]{1,5}[- ]?' соответствует идентификатору группы от одной до пяти цифр и необязательному следующему разделителю. '[0-9]+[- ]?[0-9]+[- ]?' соответствует идентификаторам издателя и заглавия переменной длины, а также их необязательным разделителям. Наконец, '[0-9X]$' соответствует контрольной цифре в конце строки.
Хотя регулярное выражение может проверить, что в последней цифре используется допустимый символ (цифра или X), оно не может определить, является ли он правильным для контрольной суммы ISBN. Один из двух алгоритмов контрольной суммы (в зависимости от того, с каким ISBN вы работаете - ISBN-10 или ISBN-13) используется для обеспечения определенного уровня гарантии того, что цифры ISBN не были случайно переставлены или введены неправильно. В примерах на JavaScript и Python, показанных ранее, реализованы оба алгоритма. В следующих разделах описываются правила контрольной суммы, чтобы помочь вам реализовать эти алгоритмы в других языках программирования.
Контрольная сумма ISBN-10
Контрольная цифра номера ISBN-10 варьируется от 0 до 10 (вместо 10 используется римская цифра X). Она вычисляется следующим образом:
- Умножьте каждую из первых 9 цифр на число в убывающей последовательности от 10 до 2 и сложите полученные результаты.
- Разделите сумму на 11.
- Вычтите остаток (не делитель) из 11.
- Если результат равен 11, используйте цифру 0, если 10 - букву X.
Вот пример того, как вывести контрольную цифру ISBN-10 для 0-596-52068-?
1 2 3 4 5 6 7 8 9 10 | Шаг 1: sum = 10×0 + 9×5 + 8×9 + 7×6 + 6×5 + 5×2 + 4×0 + 3×6 + 2×8 = 0 + 45 + 72 + 42 + 30 + 10 + 0 + 18 + 16 = 233 Шаг 2: 233 ÷ 11 = 21, remainder 2 Шаг 3: 11 − 2 = 9 Шаг 4: 9 [замена не требуется] |
Контрольная цифра - 9, поэтому полная последовательность - ISBN 0-596-52068-9.
Контрольная сумма ISBN-13
Контрольная цифра ISBN-13 варьируется от 0 до 9 и вычисляется по аналогичной схеме:
- Умножьте каждую из первых 12 цифр на 1 или 3, чередуя их по мере продвижения слева направо, и сложите полученные результаты.
- Разделите полученную сумму на 10.
- Вычтите остаток (не делитель) из 10.
- Если результат равен 10, используйте число 0.
Например, контрольная цифра ISBN-13 для 978-0-596-52068-? вычисляется следующим образом:
1 2 3 4 5 6 7 8 9 10 | Шаг 1: sum = 1×9 + 3×7 + 1×8 + 3×0 + 1×5 + 3×9 + 1×6 + 3×5 + 1×2 + 3×0 + 1×6 + 3×8 = 9 + 21 + 8 + 0 + 5 + 27 + 6 + 15 + 2 + 0 + 6 + 24 = 123 Шаг 2: 123 ÷ 10 = 12, remainder 3 Шаг 3: 10 − 3 = 7 Шаг 4: 7 [замена не требуется] |
Контрольная цифра - 7, а полная последовательность - ISBN 978-0-596-52068-7.
Вариации
Поиск ISBN в документах
Эта адаптация регекса «ISBN-10 или ISBN-13» использует границы слов вместо якорей, чтобы помочь вам найти ISBN в длинном тексте, но при этом гарантировать, что они стоят сами по себе. Идентификатор «ISBN» также стал обязательной строкой в этой версии по двум причинам. Во-первых, его требование помогает исключить ложные срабатывания (без него регекс может найти любое 10- или 13-значное число), а во-вторых, официально требуется, чтобы ISBN использовал этот идентификатор при печати:
1 | \bISBN(?:-1[03])?:? (?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]\b |
Устранение неправильных идентификаторов ISBN
Ограничение предыдущих регексов заключается в том, что они позволяют сопоставить номер ISBN-10, которому предшествует идентификатор «ISBN-13», и наоборот. Следующий регекс использует условия (см. Рецепт 2.17), чтобы убедиться, что за идентификатором «ISBN-10» или «ISBN-13» следует соответствующий тип ISBN. Она позволяет использовать как номера ISBN-10, так и ISBN-13, если тип не указан явно. Этот регекс является излишним в большинстве случаев, потому что тот же результат может быть достигнут более эффективно с помощью регексов для ISBN-10 и ISBN-13, которые были показаны ранее, по одному за раз. Она включена сюда только для того, чтобы продемонстрировать интересное использование регулярных выражений:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ^ (?:ISBN(-1(?:(0)|3))?:?\ )? (?(1) (?(2) # ISBN-10 (?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$) [0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X] | # ISBN-13 (?=[0-9]{13}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$) 97[89][- ]?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9] ) | # Без явного идентификатора; разрешить ISBN-10 или ISBN-13 (?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$|97[89][0-9]{10}$| (?=(?:[0-9]+[- ]){4})[- 0-9]{17}$) (?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X] ) $ |
См. также
Самую последнюю версию руководства пользователя ISBN, а также инструменты для проверки отдельных ISBN и конвертации между ISBN-10 и ISBN-13 можно найти на сайте Международного агентства ISBN по адресу http://www.isbn-international.org.