001package org.xbib.standardnumber; 002 003import java.util.regex.Matcher; 004import java.util.regex.Pattern; 005 006/** 007 * European Article Number is a 13-digit barcoding standard for marking products 008 * sold at retail point of sale. 009 * 010 * Numbers encoded in UPC and EAN barcodes are known as 011 * Global Trade Item Numbers (GTIN). 012 */ 013public class EAN extends AbstractStandardNumber implements Comparable<EAN>, StandardNumber { 014 015 private static final Pattern PATTERN = Pattern.compile("\\b[\\p{Digit}\\s]{13,18}\\b"); 016 017 private String value; 018 019 private boolean createWithChecksum; 020 021 @Override 022 public String type() { 023 return "ean"; 024 } 025 026 @Override 027 public int compareTo(EAN ean) { 028 return ean != null ? normalizedValue().compareTo(ean.normalizedValue()) : -1; 029 } 030 031 @Override 032 public EAN set(CharSequence value) { 033 this.value = value != null ? value.toString() : null; 034 return this; 035 } 036 037 @Override 038 public EAN createChecksum(boolean createWithChecksum) { 039 this.createWithChecksum = createWithChecksum; 040 return this; 041 } 042 043 @Override 044 public EAN normalize() { 045 Matcher m = PATTERN.matcher(value); 046 if (m.find()) { 047 this.value = despace(value.substring(m.start(), m.end())); 048 } 049 return this; 050 } 051 052 @Override 053 public boolean isValid() { 054 return value != null && !value.isEmpty() && check(); 055 } 056 057 @Override 058 public EAN verify() throws NumberFormatException { 059 if (value == null || value.isEmpty()) { 060 throw new NumberFormatException("invalid"); 061 } 062 if (!check()) { 063 throw new NumberFormatException("bad checkum"); 064 } 065 return this; 066 } 067 068 @Override 069 public String normalizedValue() { 070 return value; 071 } 072 073 @Override 074 public String format() { 075 return value; 076 } 077 078 public EAN reset() { 079 this.value = null; 080 this.createWithChecksum = false; 081 return this; 082 } 083 084 private boolean check() { 085 int l = value.length() - 1; 086 int checksum = 0; 087 int weight; 088 int val; 089 for (int i = 0; i < l; i++) { 090 val = value.charAt(i) - '0'; 091 weight = i % 2 == 0 ? 1 : 3; 092 checksum += val * weight; 093 } 094 int chk = 10 - checksum % 10; 095 if (createWithChecksum) { 096 char ch = (char)('0' + chk); 097 value = value.substring(0, l) + ch; 098 } 099 return chk == (value.charAt(l) - '0'); 100 } 101 102 private String despace(String isbn) { 103 StringBuilder sb = new StringBuilder(isbn); 104 int i = sb.indexOf(" "); 105 while (i >= 0) { 106 sb.deleteCharAt(i); 107 i = sb.indexOf(" "); 108 } 109 return sb.toString(); 110 } 111}