001 002package org.xbib.standardnumber; 003 004import java.util.regex.Matcher; 005import java.util.regex.Pattern; 006 007/** 008 * Zeitschriftendatenbank ID 009 * 010 * ZDB is the world’s largest specialized database for serial titles (journals, annuals, newspapers, also 011 * e-journals). 012 * 013 * @see <a href="http://support.d-nb.de/iltis/onlineRoutinen/Pruefziffernberechnung.htm"></a>Prüfziffernberechnung in ILTIS</a> 014 * @see <a href="https://wiki.dnb.de/pages/viewpage.action?pageId=48139522">DNB Wiki</a> 015 */ 016public class ZDB extends AbstractStandardNumber implements Comparable<ZDB>, StandardNumber { 017 018 private final static Pattern PATTERN = Pattern.compile("\\b[\\p{Digit}]{2,10}\\-{0,1}[\\p{Digit}xX]{1}\\b"); 019 020 private String value; 021 022 private String formatted; 023 024 private boolean createWithChecksum; 025 026 @Override 027 public String type() { 028 return "zdb"; 029 } 030 031 @Override 032 public ZDB set(CharSequence value) { 033 this.value = value != null ? value.toString() : null; 034 return this; 035 } 036 037 @Override 038 public int compareTo(ZDB o) { 039 return value != null ? value.compareTo(o.normalizedValue()) : -1; 040 } 041 042 @Override 043 public String normalizedValue() { 044 return value; 045 } 046 047 @Override 048 public ZDB createChecksum(boolean createWithChecksum) { 049 this.createWithChecksum = createWithChecksum; 050 return this; 051 } 052 053 @Override 054 public ZDB normalize() { 055 Matcher m = PATTERN.matcher(value); 056 if (m.find()) { 057 this.value = dehyphenate(value.substring(m.start(), m.end())); 058 } 059 return this; 060 } 061 062 @Override 063 public boolean isValid() { 064 return value != null && !value.isEmpty() && check(); 065 } 066 067 @Override 068 public ZDB verify() throws NumberFormatException { 069 if (value == null || value.isEmpty()) { 070 throw new NumberFormatException("invalid"); 071 } 072 if (!check()) { 073 throw new NumberFormatException("bad checksum"); 074 } 075 return this; 076 } 077 078 @Override 079 public String format() { 080 if (formatted == null) { 081 StringBuilder sb = new StringBuilder(value); 082 this.formatted = sb.insert(sb.length()-1,"-").toString(); 083 } 084 return formatted; 085 } 086 087 @Override 088 public ZDB reset() { 089 this.value = null; 090 this.formatted = null; 091 this.createWithChecksum = false; 092 return this; 093 } 094 095 private boolean check() { 096 int l = value.length() - 1; 097 int checksum = 0; 098 int weight = 2; 099 int val; 100 for (int i = l-1; i >= 0; i--) { 101 val = value.charAt(i) - '0'; 102 checksum += val * weight++; 103 } 104 if (createWithChecksum) { 105 char ch = checksum % 11 == 10 ? 'X' : (char)('0' + (checksum % 11)); 106 value = value.substring(0, l) + ch; 107 } 108 return checksum % 11 == 109 (value.charAt(l) == 'X' || value.charAt(l) == 'x' ? 10 : value.charAt(l) - '0'); 110 } 111 112 private String dehyphenate(String value) { 113 StringBuilder sb = new StringBuilder(value); 114 int i = sb.indexOf("-"); 115 while (i >= 0) { 116 sb.deleteCharAt(i); 117 i = sb.indexOf("-"); 118 } 119 return sb.toString(); 120 } 121}