/* * Copyright (C) 2014 Jörg Prante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses * or write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. * * The interactive user interfaces in modified source and object code * versions of this program must display Appropriate Legal Notices, * as required under Section 5 of the GNU Affero General Public License. * */ package org.xbib.standardnumber; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Zeitschriftendatenbank ID * * ZDB is the world’s largest specialized database for serial titles (journals, annuals, newspapers, also * e-journals). * * @see <a href="http://support.d-nb.de/iltis/onlineRoutinen/Pruefziffernberechnung.htm"></a>Prüfziffernberechnung in ILTIS</a> * @see <a href="https://wiki.dnb.de/pages/viewpage.action?pageId=48139522">DNB Wiki</a> */ public class ZDB extends AbstractStandardNumber implements Comparable<ZDB>, StandardNumber { private final static Pattern PATTERN = Pattern.compile("^[\\p{Digit}]{2,10}\\-{0,1}[\\p{Digit}xX]{1}\\b"); private String value; private String formatted; private boolean createWithChecksum; @Override public String type() { return "zdb"; } @Override public ZDB set(CharSequence value) { this.value = value != null ? value.toString() : null; return this; } @Override public int compareTo(ZDB o) { return value != null ? value.compareTo(o.normalizedValue()) : -1; } @Override public String normalizedValue() { return value; } @Override public ZDB createChecksum(boolean createWithChecksum) { this.createWithChecksum = createWithChecksum; return this; } @Override public ZDB normalize() { Matcher m = PATTERN.matcher(value); if (m.find()) { this.value = dehyphenate(value.substring(m.start(), m.end())); } return this; } @Override public boolean isValid() { return value != null && !value.isEmpty() && check(); } @Override public ZDB verify() throws NumberFormatException { if (value == null || value.isEmpty()) { throw new NumberFormatException("invalid"); } if (!check()) { throw new NumberFormatException("bad checksum"); } return this; } @Override public String format() { if (formatted == null) { StringBuilder sb = new StringBuilder(value); this.formatted = sb.insert(sb.length()-1,"-").toString(); } return formatted; } @Override public ZDB reset() { this.value = null; this.formatted = null; this.createWithChecksum = false; return this; } private boolean check() { int l = value.length() - 1; int checksum = 0; int weight = 2; int val; for (int i = l-1; i >= 0; i--) { val = value.charAt(i) - '0'; checksum += val * weight++; } if (createWithChecksum) { char ch = checksum % 11 == 10 ? 'X' : (char)('0' + (checksum % 11)); value = value.substring(0, l) + ch; } return checksum % 11 == (value.charAt(l) == 'X' || value.charAt(l) == 'x' ? 10 : value.charAt(l) - '0'); } private String dehyphenate(String value) { StringBuilder sb = new StringBuilder(value); int i = sb.indexOf("-"); while (i >= 0) { sb.deleteCharAt(i); i = sb.indexOf("-"); } return sb.toString(); } }