You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2020/05/17 10:53:32 UTC
[commons-validator] branch master updated: Add code to parse IBAN
Registry (TXT) file
This is an automated email from the ASF dual-hosted git repository.
sebb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-validator.git
The following commit(s) were added to refs/heads/master by this push:
new b31d8d4 Add code to parse IBAN Registry (TXT) file
b31d8d4 is described below
commit b31d8d44811336a358c85e144b9e7084468e223f
Author: Sebb <se...@apache.org>
AuthorDate: Sun May 17 11:53:04 2020 +0100
Add code to parse IBAN Registry (TXT) file
---
.../validator/routines/IBANValidatorTest.java | 144 ++++++++++++++++++++-
1 file changed, 140 insertions(+), 4 deletions(-)
diff --git a/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java b/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
index 90c6534..833f890 100644
--- a/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
+++ b/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
@@ -22,6 +22,17 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
import org.apache.commons.validator.routines.IBANValidator.Validator;
import org.apache.commons.validator.routines.checkdigit.IBANCheckDigit;
import org.junit.Test;
@@ -136,7 +147,7 @@ public class IBANValidatorTest {
"BY00NBRB3600000000000Z00AB00", // Wrong in SWIFT v73
"ST68000200010192194210112", // ditto
"SV62CENR0000000000000700025", // ditto
- };
+ };
private static final IBANValidator VALIDATOR = IBANValidator.getInstance();
@@ -220,9 +231,134 @@ public class IBANValidatorTest {
}
}
}
- public static void main(String [] a) {
+
+ private static void checkIBAN(File file, IBANValidator val) throws Exception {
+ // The IBAN Registry (TXT) file is a TAB-separated file
+ // Rows are the entry types, columns are the countries
+ CSVFormat format = CSVFormat.DEFAULT.withDelimiter('\t');
+ Reader rdr = new InputStreamReader(new FileInputStream(file), StandardCharsets.ISO_8859_1);
+ CSVParser p = new CSVParser(rdr, format);
+ CSVRecord country = null;
+ CSVRecord cc = null;
+ CSVRecord structure = null;
+ CSVRecord length = null;
+ for (CSVRecord o : p) {
+ String item = o.get(0);
+ if ("Name of country".equals(item)) {
+ country = o;
+ } else if ("IBAN prefix country code (ISO 3166)".equals(item)) {
+ cc = o;
+ } else if ("IBAN structure".equals(item)) {
+ structure = o;
+ } else if ("IBAN length".equals(item)) {
+ length = o;
+ }
+ }
+ for (int i=1; i < country.size(); i++) {
+ String newLength = length.get(i).split("!")[0]; // El Salvador currently has "28!n"
+ String newRE = fmtRE(structure.get(i), Integer.parseInt(newLength));
+ final Validator valre = val.getValidator(cc.get(i));
+ if (valre == null) {
+ System.out.println("// Missing entry:");
+ printEntry(
+ cc.get(i),
+ newLength,
+ newRE,
+ country.get(i));
+ } else {
+ String currentLength = Integer.toString(valre.lengthOfIBAN);
+ String currentRE = valre.validator.toString()
+ .replaceAll("^.+?\\{(.+)}","$1") // Extract RE from RegexValidator{re} string
+ .replaceAll("\\\\d","\\\\\\\\d"); // convert \d to \\d
+ // The above assumes that the RegexValidator contains a single Regex
+ if (currentRE.equals(newRE) && currentLength.equals(newLength)) {
+
+ } else {
+ System.out.println("// Expected: " + newRE + ", " + newLength + " Actual: " + currentRE + ", " + currentLength);
+ printEntry(
+ cc.get(i),
+ newLength,
+ newRE,
+ country.get(i));
+ }
+
+ }
+ }
+ p.close();
+ }
+
+ private static void printEntry(String ccode, String length, String ib, String country) {
+ String fmt = String.format("\"%s\"", ib);
+ System.out.printf(" new Validator(\"%s\", %s, %-40s), // %s\n",
+ ccode,
+ length,
+ fmt,
+ country);
+ }
+
+ // Unfortunately Java only returns the last match of repeated patterns
+ // Use a manual repeat instead
+ private static final String IBAN_PART = "(?:(\\d+)!([acn]))"; // Assume all parts are fixed length
+ private static final Pattern IBAN_PAT = Pattern.compile(
+ "([A-Z]{2})"+IBAN_PART+IBAN_PART+IBAN_PART+IBAN_PART+"?"+IBAN_PART+"?"+IBAN_PART+"?"+IBAN_PART+"?");
+
+ // convert IBAN type string and length to regex
+ private static String formatToRE(String type, int len) {
+ char ctype = type.charAt(0); // assume type.length() == 1
+ switch(ctype) {
+ case 'n':
+ return String.format("\\\\d{%d}",len);
+ case 'a':
+ return String.format("[A-Z]{%d}",len);
+ case 'c':
+ return String.format("[A-Z0-9]{%d}",len);
+ default:
+ throw new IllegalArgumentException("Unexpected type " + type);
+ }
+ }
+
+ private static String fmtRE(String iban_pat, int iban_len) {
+ Matcher m = IBAN_PAT.matcher(iban_pat);
+ if (m.matches()) {
+ StringBuilder sb = new StringBuilder();
+ String cc = m.group(1); // country code
+ int totalLen = cc.length();
+ sb.append(cc);
+ int len = Integer.parseInt(m.group(2)); // length of part
+ String curType = m.group(3); // part type
+ for (int i = 4; i <= m.groupCount(); i += 2) {
+ if (m.group(i) == null) { // reached an optional group
+ break;
+ }
+ int count = Integer.parseInt(m.group(i));
+ String type = m.group(i+1);
+ if (type.equals(curType)) { // more of the same type
+ len += count;
+ } else {
+ sb.append(formatToRE(curType,len));
+ totalLen += len;
+ curType = type;
+ len = count;
+ }
+ }
+ sb.append(formatToRE(curType,len));
+ totalLen += len;
+ if (iban_len != totalLen) {
+ throw new IllegalArgumentException("IBAN pattern " + iban_pat + " does not match length " + iban_len);
+ }
+ return sb.toString();
+ } else {
+ throw new IllegalArgumentException("Unexpected IBAN pattern " + iban_pat);
+ }
+ }
+
+ public static void main(String [] a) throws Exception {
IBANValidator validator = new IBANValidator();
- Validator[] vals = validator.getDefaultValidators();
- System.out.println("Number of entries: " + vals.length);
+ File iban_tsv = new File("target","iban-registry.tsv");
+ if (iban_tsv.canRead()) {
+ checkIBAN(iban_tsv, validator);
+ } else {
+ System.out.println("Please load the file " + iban_tsv.getCanonicalPath() + " from https://www.swift.com/standards/data-standards/iban");
+ }
}
}