[Schmitzm-commits] r1626 - in trunk: . schmitzm-adresses schmitzm-adresses/src schmitzm-adresses/src/main schmitzm-adresses/src/main/java schmitzm-adresses/src/main/java/de schmitzm-adresses/src/main/java/de/schmitzm schmitzm-adresses/src/main/java/de/schmitzm/adresses schmitzm-adresses/src/main/resources schmitzm-adresses/src/test schmitzm-adresses/src/test/java schmitzm-adresses/src/test/java/de schmitzm-adresses/src/test/java/de/schmitzm schmitzm-adresses/src/test/java/de/schmitzm/adresses

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Tue Jul 12 21:53:04 CEST 2011


Author: keeb
Date: 2011-07-12 21:53:03 +0200 (Tue, 12 Jul 2011)
New Revision: 1626

Added:
   trunk/schmitzm-adresses/
   trunk/schmitzm-adresses/pom.xml
   trunk/schmitzm-adresses/src/
   trunk/schmitzm-adresses/src/main/
   trunk/schmitzm-adresses/src/main/java/
   trunk/schmitzm-adresses/src/main/java/de/
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/AddrStringUtil.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/Ebene.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormResult.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormRule.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/RuleRegistry.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSNormRule.java
   trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSRulesParser.java
   trunk/schmitzm-adresses/src/main/resources/
   trunk/schmitzm-adresses/src/main/resources/rules.xls
   trunk/schmitzm-adresses/src/main/resources/rulesHn.xls
   trunk/schmitzm-adresses/src/main/resources/rulesZusatz.xls
   trunk/schmitzm-adresses/src/test/
   trunk/schmitzm-adresses/src/test/java/
   trunk/schmitzm-adresses/src/test/java/de/
   trunk/schmitzm-adresses/src/test/java/de/schmitzm/
   trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/
   trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/AddrStringUtilTest.java
   trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/RuleRegistryTest.java
Modified:
   trunk/pom.xml
Log:
New Project schmitzm-adresses deals with german street adresses


Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/pom.xml	2011-07-12 19:53:03 UTC (rev 1626)
@@ -16,6 +16,7 @@
 		<module>schmitzm-gt</module>
 		<module>schmitzm-jfree</module>
 		<module>schmitzm-jfree-gt</module>
+		<module>schmitzm-adresses</module>
 	</modules>
 	
 	<distributionManagement>

Added: trunk/schmitzm-adresses/pom.xml
===================================================================
--- trunk/schmitzm-adresses/pom.xml	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/pom.xml	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,43 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>de.schmitzm</groupId>
+	<artifactId>schmitzm-adresses</artifactId>
+	<version>2.6-SNAPSHOT</version>
+	<packaging>jar</packaging>
+
+	<parent>
+		<groupId>de.schmitzm</groupId>
+		<artifactId>schmitzm-parent</artifactId>
+		<version>2.6-SNAPSHOT</version>
+		<relativePath>../schmitzm-parent/pom.xml</relativePath>
+	</parent>
+
+	<name>schmitzm-adresses</name>
+	<url>http://maven.apache.org</url>
+	<dependencies>
+		<dependency>
+			<groupId>net.sourceforge.jexcelapi</groupId>
+			<artifactId>jxl</artifactId>
+			<version>2.6.12</version>
+			<type>jar</type>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>de.schmitzm</groupId>
+			<artifactId>schmitzm-core</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>de.schmitzm</groupId>
+			<artifactId>schmitzm-core</artifactId>
+			<version>${project.version}</version>
+			<type>jar</type>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+
+</project>

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/AddrStringUtil.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/AddrStringUtil.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/AddrStringUtil.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,446 @@
+package de.schmitzm.adresses;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * Diese Klasse bietete nützliche Methoden zur Bearbeitung von
+ * Addressschreibweisen. Zur Zeit werden nur Strings mit Strasse [Hn] [Zusatz]
+ * behandelt.<br/>
+ * Es werden Methoden zum Aufteilen (Splitten) von String angeboten, um Strasse
+ * +Hn + Zusatz in drei Strings zu zerlegen. Weiterhin existieren Methoden um
+ * die Schreibweisen von Straßen, Hausnummern un Zusätzen zu normalisieren.
+ * Diese normalisierten Strings können dann zum abgeleichen von
+ * Addressinformationen verwendet werden.<br/>
+ * Ersetzungsregeln für die Normalisierung werden in drei Excel-Dateien
+ * verwaltet.<br/>
+ */
+public class AddrStringUtil {
+	static final private Logger log = Logger.getLogger(AddrStringUtil.class);
+
+	final static Pattern REGEX_splitHnZusatz = Pattern
+			.compile("(\\d+)\\s*(.*?)\\s*$");
+	final static Pattern REGEX_splitFullString = Pattern
+			.compile("^(.*\\d+\\.+[^\\d]*|[^\\d,]+)"
+					+ "\\s*"
+					+ "(\\d+|\\d+\\s*-\\s*\\d+|\\d+\\s*[,\\s*\\d+]+|\\d+\\s*[&]\\s*\\d+|\\d+\\s*bis\\s*\\d+|\\d+\\s*\\\\\\s*\\d+|\\d+\\s*[/\\s*\\d+]+)"
+					+ "\\s*" + "([^\\d].*[0][\\d]+|[^\\d]*?)" + "\\s*$");
+
+	final static Pattern REGEX_hnZusatzBereich2aBis2f = Pattern
+			.compile("(\\d+)([^\\d]?)\\s*(-|bis)\\s*(\\d*)([^\\d]?).*");
+	// final static Pattern REGEX_hnBereich = Pattern
+	// .compile("(\\d+)([^\\d]?)(\\s*)(-|bis)(\\s*)(\\w+).*");
+
+	final static Pattern REGEX_hnListe = Pattern
+			.compile("(\\d+)([^\\d]+)(\\d+).*");
+
+	final static Pattern REGEX_hnEinzeln = Pattern.compile("(\\d+)(.*)");
+
+	/**
+	 * Normalisiert die Schreibweise eines Straßennamens, z.B.
+	 * "Dr.-Vogeler-Str." -> "drvogelerstrasse"
+	 */
+	public static final NormResult normalizeStrasse(final String strasse) {
+		return normalize(RuleRegistry.getRulesStr(), strasse);
+	}
+
+	/**
+	 * Normalisiert die Schreibweise einer Hausnummer, z.B. " 5   " -> "5"
+	 */
+	public static final NormResult normalizeHn(final String hn) {
+		return normalize(RuleRegistry.getRulesHn(), hn);
+	}
+
+	/**
+	 * Normalisiert die Schreibweise eines Hn-Zusatzes, z.B. " A   " -> "a"
+	 */
+	public static final NormResult normalizeZusatz(final String zusatz) {
+		return normalize(RuleRegistry.getRulesZusatz(), zusatz);
+	}
+
+	/**
+	 * Applies the given "Rules"/ Transformations to the given String.
+	 */
+	private static NormResult normalize(final List<NormRule> rules,
+			final String string) {
+
+		if (string == null)
+			return new NormResult(null);
+
+		final NormResult nRes = new NormResult(string);
+
+		String lastResult = "";
+		while (!lastResult.equals(nRes.getResultStr())) {
+			lastResult = nRes.getResultStr();
+			for (final NormRule nRule : rules) {
+				nRule.applyTo(nRes);
+			}
+		}
+
+		return nRes;
+	}
+
+	/**
+	 * Diese Methode teilt einen String, der Hausnummer und einen optionalen
+	 * Zusatz enhält, in zwei Strings.
+	 * 
+	 * @param origHn
+	 *            darf <code>null</code> sein. Kann nur die HN oder HN+ZUSATZ
+	 *            enthalten.
+	 * @param origZusatz
+	 *            darf <code>null</code> sein.
+	 * @return Zwei Strings, zuerst ein String mit der Hausnummer (oder null),
+	 *         und als zweites ein String mit dem Zusatz (oder null).
+	 */
+	public static String[] splitHn(final String origHn, final String origZusatz) {
+		if (origHn == null)
+			return new String[] { null, origZusatz };
+
+		String hn = null;
+		String zusatz = null;
+
+		final Matcher m = REGEX_splitHnZusatz.matcher(origHn);
+		final boolean found = m.find();
+
+		if (!found) {
+			return new String[] { null, origZusatz };
+		}
+		try {
+			hn = m.group(1);
+			zusatz = m.group(2);
+		} catch (final Exception e) {
+			log.debug(e);
+		}
+
+		if (zusatz == null || zusatz.isEmpty()) {
+			zusatz = origZusatz;
+		} else if (origZusatz != null) {
+			zusatz += " " + origZusatz;
+		}
+
+		if (StringUtils.isEmpty(hn))
+			hn = null;
+		if (StringUtils.isEmpty(zusatz))
+			zusatz = null;
+
+		return new String[] { hn, zusatz };
+	}
+
+	/**
+	 * Diese Methode teilt einen String, der Hausnummer und einen optionalen
+	 * Zusatz enhält, in zwei Strings.
+	 * 
+	 * @param origHn
+	 *            darf null sein.
+	 * @param origZusatz2
+	 * @return Drei Objekte, String strasse, dann ein Integer mit der
+	 *         Hausnummer, und als drittes ein String mit dem Zusatz. bei können
+	 *         null sein.
+	 */
+	public static String[] split(final String... stringStrHnZusatz) {
+
+		boolean warn = false;
+
+		if (stringStrHnZusatz.length < 1 || stringStrHnZusatz.length > 3)
+			throw new IllegalArgumentException(
+					"Only 1, 2 or 3 String parameters are allowed (Straße [Hn] [Zusatz], Hausnummer, Zusatz)");
+
+		String origStrasse = null;
+		String origHn = null;
+		String origZusatz = null;
+		if (stringStrHnZusatz.length >= 1)
+			origStrasse = stringStrHnZusatz[0];
+		if (stringStrHnZusatz.length >= 2)
+			origHn = stringStrHnZusatz[1];
+		if (stringStrHnZusatz.length == 3)
+			origZusatz = stringStrHnZusatz[2];
+
+		if (origStrasse == null || origStrasse.isEmpty()
+				|| !origStrasse.matches(".*[A-Za-z][A-Za-z]+.*")) {
+			final String[] splitHn = splitHn(origHn, origZusatz);
+			return new String[] { null, splitHn[0], splitHn[1] };
+		}
+
+		String strasse = null;
+		String hn = null;
+		String zusatz = null;
+
+		// Evt. umschliessende " im String entfernen:
+		{
+			origStrasse = trimQuotes(origStrasse);
+			origHn = trimQuotes(origHn);
+			origZusatz = trimQuotes(origZusatz);
+		}
+
+		String zusammen = origStrasse + " "
+				+ (origHn != null ? " " + origHn : "")
+				+ (origZusatz != null ? " " + origZusatz : "");
+		zusammen = trimQuotes(zusammen);
+		zusammen = removeKommataAfterStreetname(zusammen);
+		zusammen = removeTrailingHyphens(zusammen);
+		zusammen = removeLeadingSpacesInfrontOfNumbers(zusammen);
+
+		zusammen = removeSpacesBetweenHiphenAndDotAndLetters(zusammen);
+
+		Matcher m = REGEX_splitFullString.matcher(zusammen);
+
+		final boolean found = m.find();
+
+		if (!found) {
+			// String[] splitHn = splitHn(origHn, origZusatz);
+			// log.warn(splitRegExp.toString() + " retuned no matches for "
+			// + origStrasse + " " + origHn + " " + origZusatz);
+			// return new String[] { null, splitHn[0], splitHn[1] };
+
+			Pattern p = Pattern
+					.compile("([^\\d]*)\\s([\\d]+[^\\s]*|[\\d]+\\s+\\d+)$");
+			m = p.matcher(zusammen);
+			if (m.find()) {
+				strasse = m.group(1);
+				hn = m.group(2);
+			} else {
+				p = Pattern.compile("(.+?)\\s([\\d]+.*)$");
+				m = p.matcher(zusammen);
+				if (m.find()) {
+					strasse = m.group(1);
+					hn = m.group(2);
+				} else {
+
+					// Wenn keine Zahl enthalten ist, dann ist alles strasse
+					p = Pattern.compile(".*\\d+.*$");
+					if (p.matcher(zusammen).find())
+						return new String[] { null, null, null, null };
+					else
+						return new String[] { zusammen, null, null, null };
+				}
+			}
+			warn = true;
+		}
+		try {
+			strasse = m.group(1).trim();
+			final String group2 = m.group(2);
+			if (group2 != null && !group2.isEmpty())
+				hn = group2;
+
+			// TODO
+			if (m.groupCount() >= 3) {
+				final String group3 = m.group(3);
+				if (group3 != null && !group3.trim().isEmpty())
+					zusatz = group3.trim();
+			}
+		} catch (final Exception e) {
+			log.error("", e);
+		}
+		strasse = StringUtils.trimToNull(strasse);
+		if (strasse == null || strasse.length() < 3) {
+
+			final Pattern p = Pattern
+					.compile("(.+?)\\s([\\d]+[-]?[\\d]*)(.*)$");
+			m = p.matcher(zusammen);
+			if (m.find()) {
+				strasse = m.group(1);
+				hn = m.group(2);
+				zusatz = m.group(3);
+			} else
+				return new String[] { null, null, null, null };
+
+			// log.error("Strasse = " + strasse);
+			warn = true;
+		}
+
+		if (strasse.contains("Flurstück") || strasse.contains("Flst")) {
+			return new String[] { null, null, null, null };
+		}
+
+		if (strasse.length() <= 2) {
+			// z.b. Strasse "-"
+			return new String[] { null, null, null, null };
+		}
+
+		if (warn)
+			log.warn("Aus '" + origStrasse + "' wurde Strasse='" + strasse
+					+ "', HN='" + StringUtils.trimToNull(hn) + "', Zusatz='"
+					+ StringUtils.trimToNull(zusatz) + "', richtig?");
+
+		return new String[] { strasse, StringUtils.trimToNull(hn),
+				StringUtils.trimToNull(zusatz) };
+	}
+
+	/**
+	 * @param zusammen
+	 * @return
+	 */
+	public static String removeTrailingHyphens(String zusammen) {
+		return zusammen.replaceAll("(.*)\\s?[-]$", "$1");
+	}
+
+	/**
+	 * @param zusammen
+	 * @return
+	 */
+	public static String removeKommataAfterStreetname(String zusammen) {
+		return zusammen.replaceAll("([A-Za-z][A-Za-z]+)\\s?[,]\\s?(\\d+)",
+				"$1 $2");
+	}
+
+	private static String removeSpacesBetweenHiphenAndDotAndLetters(
+			String zusammen) {
+		zusammen = zusammen.replaceAll("([A-Za-z]+)\\s+([.-]*)\\s?([.-])+",
+				"$1$2$3");
+		return zusammen;
+	}
+
+	/**
+	 * Bearbeitung eines Spezialfalls, der nicht funktioniert...
+	 */
+	public static String removeLeadingSpacesInfrontOfNumbers(String zusammen) {
+		return zusammen.replaceAll("([,/\\\\])\\s+(\\d+)", "$1$2");
+	}
+
+	/**
+	 * Entfernt evt. umschliessende " oder ' um den string
+	 */
+	public static String trimQuotes(String s) {
+		if (s == null)
+			return "";
+		s = s.trim();
+		s = s.replace('"', ' ');
+		s = s.replace('\'', ' ');
+		s = s.replace("  ", " ");
+		return s.trim();
+	}
+
+	// TODO sauberes rewrite unter besserer Ausnutzung von Rekursion
+	public static List<String> getHausnummernInterpreted(
+			final String hausnummern) {
+		final List<String> result = new ArrayList<String>();
+		if (hausnummern != null) {
+			final Matcher m = Pattern.compile("(\\d)+\\s*([a-z]+)[,]([a-z]+)")
+					.matcher(hausnummern);
+			if (m.find()) {
+				result.addAll(getHausnummern(m.group(1) + m.group(2)));
+				result.addAll(getHausnummern(m.group(1) + m.group(3)));
+				return result;
+			}
+			final String[] splitted = hausnummern.split("[,/;]+");
+			for (final String hn : splitted) {
+				result.addAll(getHausnummern(hn));
+			}
+		}
+		return result;
+	}
+
+	public static List<String> getHausnummern(String hausnummerUntested) {
+
+		if (hausnummerUntested == null)
+			return Collections.emptyList();
+
+		hausnummerUntested = hausnummerUntested.trim().toLowerCase();
+
+		final List<String> result = new ArrayList<String>();
+
+		hausnummerUntested = hausnummerUntested.replaceAll("\\s+", "");
+
+		Matcher m = REGEX_hnZusatzBereich2aBis2f.matcher(hausnummerUntested);
+		if (m.find()) {
+
+			// 15a - f
+			if (!m.group(2).isEmpty() && m.group(4).isEmpty()
+					&& !m.group(5).isEmpty()) {
+
+				for (char a = m.group(2).charAt(0); a <= m.group(5).charAt(0); a++) {
+					result.add(m.group(1) + a);
+				}
+				return result;
+			}
+
+			// TODO Hier stehen manchmal nicht nur zahlen drin!
+			/**
+			 * Stefan Tzeggai : Was soll das programm aus "9a - 11d" machen?
+			 * "9a, 10, 11d" ?
+			 */
+
+			// Überprüfen, ob hinter der Zahl noch was steht...
+
+			final String minNumStr = m.group(1);
+			final String maxNumStr = m.group(4);
+
+			// 12-15
+			if (m.group(2).isEmpty() && !maxNumStr.isEmpty()
+					&& m.group(5).isEmpty()) {
+				// Keine Zusätze in dem Bereich...
+				log.debug("Versuche Hausnummernbereich " + minNumStr + " bis "
+						+ maxNumStr + " aufzulösen...");
+				final int min = Integer.parseInt(minNumStr);
+				final int max = Integer.parseInt(maxNumStr);
+
+				if (max - min > 100) {
+					log.warn("Hausnummernbereich von " + min + " bis " + max
+							+ " ausgelassen, weil der Bereich zu groß ist.");
+					return Collections.EMPTY_LIST;
+				}
+
+				for (int i = min; i <= max; i++) {
+					// TODO Hier könnte man nur die geraden oder ungeraden
+					// zählen
+					result.add(Integer.toString(i));
+				}
+			} else {
+				log.debug("Hausnummernbereich " + minNumStr + m.group(2)
+						+ " bis " + maxNumStr + m.group(5)
+						+ " kann noch nicht hochgezählt werden.");
+				if (!minNumStr.isEmpty())
+					result.add(minNumStr + m.group(2));
+				if (!maxNumStr.isEmpty())
+					result.add(maxNumStr + m.group(5));
+			}
+			return result;
+		}
+
+		m = REGEX_hnListe.matcher(hausnummerUntested);
+		if (m.find()) {
+			result.add(m.group(1));
+			result.add(m.group(3));
+			m.group(2);
+			return result;
+		}
+
+		m = REGEX_hnEinzeln.matcher(hausnummerUntested);
+		if (m.find()) {
+			String match = m.group(1);
+			match += m.group(2);
+			result.add(match);
+			return result;
+		}
+
+		log.error("Hausnummer raw '" + hausnummerUntested
+				+ "' nicht verstanden.");
+		return result;
+	}
+
+	/**
+	 * Interpretiert eine GKZ, KKZ etc anhang Ihrer Länge und liefert ob es sich
+	 * um einen KREIS oder ein BUNDESLAND handelt
+	 * 
+	 * @return <code>null</code> wenn <code>null</code> übergeben worde oder der
+	 *         code nicht verstanden wurde.
+	 */
+	static Ebene getEbeneForEbeneCode(String code) {
+		if (code == null)
+			return null;
+		code = code.trim();
+		if (code.length() == 8)
+			return Ebene.KOMMUNE;
+		if (code.length() == 5)
+			return Ebene.KREISE;
+		if (code.length() == 2)
+			return Ebene.BUNDESLAND;
+		return null;
+	}
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/Ebene.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/Ebene.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/Ebene.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,26 @@
+package de.schmitzm.adresses;
+
+/**
+ * Administrative Ebene in Deutschland
+ */
+public enum Ebene {
+
+	LAND("D"), LANDESHAELFTE("LH"), BUNDESLAND("BL"), KREISE("KR"), KOMMUNE(
+			"KO"), SR("SR");
+
+	private final String id;
+
+	Ebene(String id) {
+		this.id = id;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public String toString() {
+		return id;
+	}
+
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormResult.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormResult.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormResult.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,53 @@
+package de.schmitzm.adresses;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class NormResult {
+	static final private Logger log = Logger.getLogger(NormResult.class);
+
+	@Override
+	/**
+	 * For some hacky convenience, this toString returns the resulting (changed) String directly. 
+	 */
+	public String toString() {
+		// return "NormResult [deltaMag=" + deltaMag + ", hitRules=" + hitRules
+		// + ", origStr=" + origStr + ", resultStr=" + resultStr + "]";
+		return getResultStr();
+	}
+
+	private int deltaMag = 0;
+	private List<NormRule> hitRules = new ArrayList<NormRule>();
+
+	final String origStr;
+
+	String resultString;
+
+	public NormResult(String origStr) {
+		this.origStr = origStr == null ? null : origStr.trim();
+		this.resultString = this.origStr;
+	}
+
+	public void addHitRule(NormRule nr) {
+		hitRules.add(nr);
+	}
+
+	public int getDeltaMag() {
+		return deltaMag;
+	}
+
+	public String getOrigStr() {
+		return origStr;
+	}
+
+	public String getResultStr() {
+		return resultString;
+	}
+
+	public void setResultString(String resultStr) {
+		this.resultString = resultStr;
+	}
+
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormRule.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormRule.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/NormRule.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,10 @@
+package de.schmitzm.adresses;
+
+import org.apache.log4j.Logger;
+
+public interface NormRule {
+	static final Logger log = Logger.getLogger(NormRule.class);
+
+	public void applyTo(NormResult nRes);
+
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/RuleRegistry.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/RuleRegistry.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/RuleRegistry.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,79 @@
+package de.schmitzm.adresses;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class RuleRegistry {
+    private static final String XLSRULESZUSATZ = "rulesZusatz.xls";
+
+	private static final String XLSRULESHN = "rulesHn.xls";
+
+	private static final String XLSRULES = "rules.xls";
+
+	static final private Logger log = Logger.getLogger(RuleRegistry.class);
+
+    private static final List<NormRule> allRules = new ArrayList<NormRule>();
+    private static final List<NormRule> rulesHn = new ArrayList<NormRule>();
+    private static final List<NormRule> rulesZusatz = new ArrayList<NormRule>();
+
+    private final static RuleRegistry _instance = new RuleRegistry();
+
+    NormRule lowerCaseRule = new NormRule() {
+
+        @Override
+        public void applyTo(NormResult nRes) {
+            String str = nRes.getResultStr();
+            String orig = str;
+            str = str.toLowerCase();
+            if (!orig.equals(str))
+                nRes.addHitRule(this);
+            nRes.setResultString(str);
+
+        }
+    };
+
+    private RuleRegistry() {
+        try {
+            allRules.add(lowerCaseRule);
+            rulesHn.add(lowerCaseRule);
+            rulesZusatz.add(lowerCaseRule);
+            
+            // read rules from excel table and fill all rules
+            XLSRulesParser xlsRulesParser = new XLSRulesParser(this);
+            xlsRulesParser.parserExcelRules(XLSRULES);
+            xlsRulesParser.parserExcelRules(XLSRULESHN);
+            xlsRulesParser.parserExcelRules(XLSRULESZUSATZ);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static List<NormRule> getRulesStr() {
+        return allRules;
+    }
+
+    public static RuleRegistry getInstance() {
+        return _instance;
+    }
+
+    public void addRule(XLSNormRule normRule, String xlsFilename) {
+        if (xlsFilename.equals("rules.xls")) {
+            allRules.add(normRule);
+        } else if (xlsFilename.equals("rulesHn.xls")){
+            rulesHn.add(normRule);
+        } else if (xlsFilename.equals("rulesZusatz.xls")){
+            rulesZusatz.add(normRule);
+        }
+    }
+
+    public static List<NormRule> getRulesZusatz() {
+        return rulesZusatz;
+    }
+
+    public static List<NormRule> getRulesHn() {
+        return rulesHn;
+    }
+
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSNormRule.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSNormRule.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSNormRule.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,46 @@
+package de.schmitzm.adresses;
+
+public class XLSNormRule implements NormRule {
+
+	@Override
+	public String toString() {
+		return "XLSNormRule [was=" + was + ", zu=" + zu + ", regEx=" + regEx
+				+ ", comment=" + comment + "]";
+	}
+
+	private final String was;
+	private final String zu;
+	private final boolean regEx;
+	private final String comment;
+
+	public XLSNormRule(String was, String zu, boolean regEx, String comment) {
+		this.regEx = regEx;
+		this.was = regEx ? was : was.toLowerCase();
+		this.zu = regEx ? zu : zu.toLowerCase();
+		this.comment = comment;
+	}
+
+	@Override
+	public void applyTo(NormResult nRes) {
+		String str = nRes.getResultStr();
+
+		String orig = str;
+
+		if (regEx) {
+			str = str.replaceAll(was, zu);
+		} else {
+			str = str.replace(was, zu);
+		}
+
+		if (!orig.equals(str)) {
+			nRes.addHitRule(this);
+			nRes.setResultString(str);
+		}
+
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+}

Added: trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSRulesParser.java
===================================================================
--- trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSRulesParser.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/main/java/de/schmitzm/adresses/XLSRulesParser.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,106 @@
+package de.schmitzm.adresses;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import jxl.Cell;
+import jxl.Sheet;
+import jxl.Workbook;
+import jxl.WorkbookSettings;
+import jxl.read.biff.BiffException;
+import jxl.read.biff.WorkbookParser;
+
+import org.apache.log4j.Logger;
+
+
+public class XLSRulesParser {
+
+	static final private Logger log = Logger.getLogger(XLSRulesParser.class);
+	private final RuleRegistry ruleRegistry;
+
+	public XLSRulesParser(RuleRegistry ruleRegistry) {
+		this.ruleRegistry = ruleRegistry;
+	}
+
+	/**
+	 * Chartset expected in the xls file
+	 */
+	private static final String EXCELCHARSET = "cp1252";
+
+	/**
+	 * Reads in Replacement Rules from a XLS file
+	 * 
+	 * @throws IOException
+	 * @throws BiffException
+	 */
+	void parserExcelRules(String xlsFilename) throws IOException, BiffException {
+
+		WorkbookSettings workbookSettings = new WorkbookSettings();
+		workbookSettings.setEncoding(EXCELCHARSET);
+
+		URL amdExcel = XLSRulesParser.class.getResource("/" + xlsFilename);
+
+		if (amdExcel == null)
+			throw new RuntimeException(xlsFilename + " nicht gefunden!");
+
+		InputStream openStream = amdExcel.openStream();
+
+		try {
+
+			WorkbookParser workbook = (WorkbookParser) Workbook.getWorkbook(
+					openStream, workbookSettings);
+
+			// We except only one sheet!
+			Sheet sheet = workbook.getSheet(0);
+
+			int rows = sheet.getRows();
+			log.debug("Importiere " + (rows - 10)
+					+ " Zeilen mit Regeln. Erwartetes Charset der "
+					+ xlsFilename + " ist " + EXCELCHARSET);
+
+			// Start in der 10. Zeile
+			for (int y = 10; y < rows; y++) {
+				importXlsRule(sheet.getRow(y), xlsFilename);
+			}
+
+		} finally {
+			openStream.close();
+		}
+
+	}
+
+	final static int ROW_IDX_WAS = 0;
+	final static int ROW_IDX_ZU = 1;
+	final static int ROW_IDX_REGEXBOOL = 2;
+	final static int ROW_IDX_COMMENT = 3;
+
+	/**
+	 * Imports a replacement rule defined in the xls file
+	 */
+	private void importXlsRule(Cell[] row, String xlsFilename) {
+
+		String was = row[ROW_IDX_WAS].getContents();
+		if (was == null)
+			return;
+		String zu = "";
+		if (row.length > ROW_IDX_ZU) {
+			zu = row[ROW_IDX_ZU].getContents();
+		}
+
+		boolean regEx = false;
+		if (row.length > ROW_IDX_REGEXBOOL) {
+			String regBoolStr = row[ROW_IDX_REGEXBOOL].getContents();
+			regEx = regBoolStr != null ? (!regBoolStr.isEmpty()) : false;
+		}
+
+		String comment = null;
+		if (row.length > ROW_IDX_COMMENT) {
+			comment = row[ROW_IDX_COMMENT].getContents();
+		}
+
+		XLSNormRule xlsNormRule = new XLSNormRule(was, zu, regEx, comment);
+
+		ruleRegistry.addRule(xlsNormRule, xlsFilename);
+	}
+}

Added: trunk/schmitzm-adresses/src/main/resources/rules.xls
===================================================================
(Binary files differ)


Property changes on: trunk/schmitzm-adresses/src/main/resources/rules.xls
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/schmitzm-adresses/src/main/resources/rulesHn.xls
===================================================================
(Binary files differ)


Property changes on: trunk/schmitzm-adresses/src/main/resources/rulesHn.xls
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/schmitzm-adresses/src/main/resources/rulesZusatz.xls
===================================================================
(Binary files differ)


Property changes on: trunk/schmitzm-adresses/src/main/resources/rulesZusatz.xls
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/AddrStringUtilTest.java
===================================================================
--- trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/AddrStringUtilTest.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/AddrStringUtilTest.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,258 @@
+package de.schmitzm.adresses;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import de.schmitzm.adresses.AddrStringUtil;
+import de.schmitzm.lang.LangUtil;
+
+/**
+ *
+ */
+public class AddrStringUtilTest {
+
+	@Test
+	public void testGetHausnummernInterpreted() {
+		checkHausnummern("6 - 14", "6", "7", "8", "9", "10", "11", "12", "13",
+				"14");
+
+		checkHausnummern("0175-123456789");
+
+		checkHausnummern("1-", "1");
+
+		checkHausnummern("3/4", "3", "4");
+		checkHausnummern("3/4", "3", "4");
+		checkHausnummern(" 2, 2 a, 4,", "2", "2a", "4");
+
+		checkHausnummern("22 - 23", "22", "23");
+		checkHausnummern("22,23", "22", "23");
+		checkHausnummern(" 22 - 24 ", "22", "23", "24");
+		checkHausnummern(" 25 bis 28 ", "25", "26", "27", "28");
+		checkHausnummern(" 23/24;77 ", "23", "24", "77");
+		checkHausnummern("1,2,3,8", "1", "2", "3", "8");
+		checkHausnummern("1,3a,3ab", "1", "3a", "3ab");
+		checkHausnummern("1a-c,3b,3a", "1a", "1b", "1c", "3b", "3a");
+		checkHausnummern(" 3/4/8 ", "3", "4", "8");
+
+		checkHausnummern("1 a-c", "1a", "1b", "1c");
+		checkHausnummern("1 a - c", "1a", "1b", "1c");
+		checkHausnummern("1 a,c", "1a", "1c");
+		checkHausnummern("1/1A", "1", "1a");
+		checkHausnummern("1/3//22", "1", "3", "22");
+		checkHausnummern("1/3//22", "1", "3", "22");
+
+		// checkHausnummern("1/73E", null);
+		checkHausnummern("999", "999");
+		// checkHausnummern("1000", null);
+		// checkHausnummern("21300", null);
+
+		// checkHausnummern("40237", "1", "3");
+
+		checkHausnummern("2 - 3", "2", "3");
+		checkHausnummern("2a", "2a");
+		// checkHausnummern("2c - 6b", "2c", "4", "6b");
+		checkHausnummern("2, 2 a, 4,", "2", "2a", "4");
+		checkHausnummern("2 a", "2a");
+		checkHausnummern("2     a", "2a");
+		checkHausnummern("2,3", "2", "3");
+		checkHausnummern("9a - 10d", "9a", "10d");
+		checkHausnummern(" 2 - 4 ", "2", "3", "4");
+		checkHausnummern(" 5 bis 8 ", "5", "6", "7", "8");
+	}
+
+	private void checkHausnummern(String ist, String... soll) {
+		List<String> check = AddrStringUtil.getHausnummernInterpreted(ist);
+		if (soll.length == 0)
+			assertEquals(Collections.EMPTY_LIST, check);
+		String[] array = check.toArray(new String[] {});
+		assertEquals(LangUtil.stringConcatWithSep(";", soll),
+				LangUtil.stringConcatWithSep(";", array));
+	}
+
+	@Test
+	public void testSplit() {
+		checkSplit("Leypoldt Strasse", "Leypoldt Strasse 6,/10 8/1", "6", null,
+				",/10 8/1", null);
+		
+		checkSplit("ander B2", "ander B2 5-6", "5-6", null, null, null);
+
+		checkSplit("Bettina Strasse", "Bettina Strasse 52-54 2.OG", "52-54",
+				null, "2.OG", null);
+
+		checkSplit("Dieselstr.", "Dieselstr .11 - 13", "11 - 13", null, null,
+				null);
+
+		checkSplit("Clarenbachstrasse", "Clarenbachstrasse 6 & 8", "6 & 8",
+				null, null, null);
+
+		checkSplit(null, "Flurstück 3 a 2", null, null, null, null);
+
+		checkSplit("Ober-Ramstädter Str.", "Ober-Ramstädter Str .  96 G 1",
+				"96", null, "G 1", null);
+
+		checkSplit("Kocherstrasse", "Kocherstrasse ,  5 - 9 -", "5 - 9", null,
+				null, null);
+
+		checkSplit("H.-Weigel-Str.", "H . -Weigel-Str .  5 b/ 0402 -", "5",
+				null, "b/0402", null);
+
+		checkSplit("Richard Strauss Straße", "Richard Strauss Straße 80 &",
+				"80", null, "&", null);
+
+		checkSplit(null, "'W 10 / 0170'", null, null, null, null);
+
+		checkSplit("Marder Weg", "Marder Weg", null, null, null, null);
+
+		checkSplit("Gänsepforte", "Gänsepforte 10a-12b", "10a-12b", null, null,
+				null);
+
+		checkSplit("Marder Weg", "Marder Weg 2-4", "2-4", null, null, null);
+
+		checkSplit("Hochgericht", "Hochgericht 33,35", "33,35", null, null,
+				null);
+		checkSplit("Annenstr.", "Annenstr. 23, 25, 27, 29,", "23,25,27,29,",
+				null, null, null);
+
+		checkSplit("Maternistraße", "Maternistraße 6 - 14", "6 - 14", null,
+				null, null);
+
+		checkSplit("Berliner Str.", "Berliner Str. 2,2a,4", "2,2a,4", null,
+				null, null);
+		checkSplit("Berliner Str.", "Berliner Str. 2,2a,4,", "2,2a,4,", null,
+				null, null);
+		checkSplit("Berliner Str.", "Berliner Str. 2,2 a,4", "2,2 a,4", null,
+				null, null);
+		checkSplit("Berliner Str.", "Berliner Str. 2, 4", "2,4", null, null,
+				null);
+		checkSplit("Berliner Str.", "Berliner Str. 2, 4", "2,4", null, null,
+				null);
+		checkSplit("Berliner Str.", "Berliner Str. 2a,4", "2a,4", null, null,
+				null);
+		checkSplit("Berliner Str.", "Berliner Str. 2a, 4", "2a,4", null, null,
+				null);
+		checkSplit("Berliner Str.", "Berliner Str. 2,2a, 4", "2,2a,4", null,
+				null, null);
+		checkSplit("Berliner Str.", "Berliner Str. 2, 2 a, 4,", "2,2 a,4,",
+				null, null, null);
+
+		checkSplit("Dammweg", "Dammweg 3/4", "3/4", null, null, null);
+
+		checkSplit("Hochgericht", "Hochgericht 33,35,66,78", "33,35,66,78",
+				null, null, null);
+
+		checkSplit("Marder Weg", "Marder Weg 2/4/10", "2/4/10", null, null,
+				null);
+
+		// checkSplit("Burgstr.", "Burgstr. 16,16A-B", "16,16A-B", null, null,
+		// null);
+
+		checkSplit("Marder Weg", "Marder Weg 2 - 4 ", "2 - 4", null, null, null);
+		checkSplit("Marder Weg", "Marder Weg 2 bis 4", "2 bis 4", null, null,
+				null);
+		checkSplit("Marder Weg", "Marder Weg 2\\4", "2\\4", null, null, null);
+		checkSplit("Marder Weg", "Marder Weg 2/4", "2/4", null, null, null);
+
+		checkSplit("Marder Weg", "Marder Weg 4", "4", null, null, null);
+		checkSplit("Marder Weg", "Marder Weg 4a", "4", null, "a", null);
+		checkSplit("Marder Weg", "Marder Weg", "2", "2", null, null);
+		checkSplit("Marder Weg", "Marder Weg", "2", "2a", "a", null);
+		checkSplit("Marder Weg", "Marder Weg", "2", "2", "a", "a");
+
+		checkSplit("Marderweg", "Marderweg", null, null, null, null);
+		checkSplit("Marderweg", "Marderweg 4", "4", null, null, null);
+		checkSplit("Marderweg", "Marderweg 4a", "4", null, "a", null);
+		checkSplit("Marderweg", "Marderweg", "2", "2", null, null);
+		checkSplit("Marderweg", "Marderweg", "2", "2a", "a", null);
+		checkSplit("Marderweg", "Marderweg", "2", "2", "a", "a");
+
+		checkSplit("Marderweg", "Marderweg", "2", "2", "a", "a");
+
+		// checkSplit("Strasse des 3. Juni", "Strasse des 3. Juni", null, null,
+		// null, null);
+		// checkSplit("Strasse des 3. Juni", "Strasse des 3. Juni 4b", "4",
+		// null,
+		// "b", null, null, null);
+
+		checkSplit(null, null, null, null, null, null);
+		checkSplit(null, null, "3", "3 aa", "aa", null);
+		checkSplit(null, null, "3", "3 aa ", "aa", null);
+		checkSplit(null, null, "3", "3 aa a", "aa a", null);
+		checkSplit(null, null, "3", " 3 a", "a", null);
+		checkSplit(null, null, "2", "2a", "a blub", "blub");
+		checkSplit(null, null, "2", "2", "blub", "blub");
+	}
+
+	private void checkSplit(String sollStrasse, String istStrasse,
+			String sollHn, String istHn, String sollZusatz, String istZusatz) {
+
+		String[] objects = AddrStringUtil.split(istStrasse, istHn, istZusatz);
+
+		String strasse = objects[0];
+		String hn = objects[1];
+		String zusatz = objects[2];
+		assertEquals(sollStrasse, strasse);
+		assertEquals(sollHn, hn);
+		assertEquals(sollZusatz, zusatz);
+
+	}
+
+	@Test
+	public void testNormalizeStrasse() {
+		checkNormalizeStrasse("jaegerndorferzeile", "Jägerndorfer Zeile");
+		checkNormalizeStrasse("weststrasse", "West  Straße");
+		checkNormalizeStrasse("weststrasse", "West  Str.");
+		checkNormalizeStrasse("hatschiergasse", " hatschiergasse ");
+		checkNormalizeStrasse("eichendorfstrasse", "Eichendorfstr.");
+		checkNormalizeStrasse("burgstrasse", "Burgstr.");
+		checkNormalizeStrasse("burgstrasse", "Burg Straße");
+		checkNormalizeStrasse("drosselweg", "Drossel Weg");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr.-Vogeler-Str.");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr. Vogeler Str.");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr. Vogeler Str .");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr. Vogeler Strasse");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr. Vogeler Straße");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr. Vogeler-Straße");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr.Vogeler-Straße");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr.Vogelerstraße");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr.Vogelerstrasse");
+		checkNormalizeStrasse("drvogelerstrasse", "Dr.Vogeler S");
+
+	}
+
+	@Test
+	public void testNormalizeZusatz() {
+		checkNormalizeZusatz("palim palim", "Palim  Palim");
+		checkNormalizeZusatz("dumdidum", "  dumdidum  ");
+		checkNormalizeZusatz("strasse", "Straße");
+		checkNormalizeZusatz("oe", "ö");
+		checkNormalizeZusatz("ae", "ä");
+		checkNormalizeZusatz("ue", "ü");
+		checkNormalizeZusatz("e", "é");
+		checkNormalizeZusatz("a", "á");
+	}
+
+	private void checkNormalizeStrasse(String s1, String s2) {
+		assertEquals(s1, AddrStringUtil.normalizeStrasse(s2).getResultStr());
+	}
+
+	private void checkNormalizeZusatz(String s1, String s2) {
+		assertEquals(s1, AddrStringUtil.normalizeZusatz(s2).getResultStr());
+	}
+
+	@Test
+	public void testTrimQuotes() {
+		assertEquals("m m m 3", AddrStringUtil.trimQuotes("\"m m \"m 3\""));
+	}
+
+	@Test
+	public void testRemoveLeadingSpacesInfrontOfNumbers() {
+		assertEquals("2a,4",
+				AddrStringUtil.removeLeadingSpacesInfrontOfNumbers("2a, 4"));
+
+	}
+
+}

Added: trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/RuleRegistryTest.java
===================================================================
--- trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/RuleRegistryTest.java	2011-07-11 18:27:42 UTC (rev 1625)
+++ trunk/schmitzm-adresses/src/test/java/de/schmitzm/adresses/RuleRegistryTest.java	2011-07-12 19:53:03 UTC (rev 1626)
@@ -0,0 +1,23 @@
+package de.schmitzm.adresses;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import de.schmitzm.adresses.RuleRegistry;
+import de.schmitzm.testing.TestingClass;
+
+public class RuleRegistryTest extends TestingClass {
+
+	@Test
+	public void testGetRulesStr() {
+		List<NormRule> ar = RuleRegistry.getInstance().getRulesStr();
+
+		assertNotNull(ar);
+		assertTrue(ar.size() > 4);
+	}
+
+}



More information about the Schmitzm-commits mailing list