package org.jabref.model.entry.identifier; import java.net.URI; import java.net.URISyntaxException; import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jabref.model.entry.FieldName; public class ISBN implements Identifier { private static final Pattern ISBN_PATTERN = Pattern.compile("^(\\d{9}[\\dxX]|\\d{13})$"); private final String isbnString; public ISBN(String isbnString) { this.isbnString = Objects.requireNonNull(isbnString).trim().replace("-", ""); } public static Optional<ISBN> parse(String input) { ISBN isbn = new ISBN(input); if (isbn.isValid()) { return Optional.of(isbn); } else { return Optional.empty(); } } public boolean isValidFormat() { Matcher isbnMatcher = ISBN_PATTERN.matcher(isbnString); if (isbnMatcher.matches()) { return true; } return false; } public boolean isValidChecksum() { boolean valid; if (isbnString.length() == 10) { valid = isbn10check(); } else { // length is either 10 or 13 based on regexp so will be 13 here valid = isbn13check(); } return valid; } public boolean isIsbn10() { return isbn10check(); } public boolean isIsbn13() { return isbn13check(); } // Check that the control digit is correct, see e.g. https://en.wikipedia.org/wiki/International_Standard_Book_Number#Check_digits private boolean isbn10check() { if (isbnString.length() != 10) { return false; } int sum = 0; for (int pos = 0; pos <= 8; pos++) { sum += (isbnString.charAt(pos) - '0') * ((10 - pos)); } char control = isbnString.charAt(9); if ((control == 'x') || (control == 'X')) { control = '9' + 1; } sum += (control - '0'); return (sum % 11) == 0; } // Check that the control digit is correct, see e.g. https://en.wikipedia.org/wiki/International_Standard_Book_Number#Check_digits private boolean isbn13check() { if (isbnString.length() != 13) { return false; } int sum = 0; for (int pos = 0; pos <= 12; pos++) { sum += (isbnString.charAt(pos) - '0') * ((pos % 2) == 0 ? 1 : 3); } return (sum % 10) == 0; } public boolean isValid() { return isValidFormat() && isValidChecksum(); } @Override public String getDefaultField() { return FieldName.ISBN; } @Override public String getNormalized() { return isbnString; } @Override public Optional<URI> getExternalURI() { try { return Optional.of(new URI("http://www.worldcat.org/isbn/" + isbnString)); } catch (URISyntaxException e) { return Optional.empty(); } } }