[QUIZ#1] zeja (Java)


zeja

Erfahrenes Mitglied
#1
Java:
package de.tutorials.quiz.one;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * tutorials.de Coding Quiz Nummer 1: Unscharfe Suche
 *
 * @author zeja
 *
 */
public class UnsharpSearch {

	/**
	 * Für unmarkiertes und markiertes Suchergebnis in einem Objekt.
	 */
	private static final class SearchResult {
		final String plain;
		final String marked;
		private final boolean ignoreCase;

		public SearchResult(final String plain, final String marked, final boolean ignoreCase) {
			this.plain = plain;
			this.marked = marked;
			this.ignoreCase = ignoreCase;
		}

		// Equals und hashCode von eclipse generiert. Plain reicht aus,
		// da es vom Inhalt her identisch mit marked ist.
		// Sofern bei der Suche Groß- und Kleinschreibung ignoriert wurde,
		// wird diese auch hier ignoriert. So erhält man
		// keine doppelten Ergebnisse.
		@Override
		public int hashCode() {
			final String compare = ignoreCase && plain != null ? plain.toUpperCase() : plain;
			final int prime = 31;
			int result = 1;
			result = prime * result + ((compare == null) ? 0 : compare.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			SearchResult other = (SearchResult) obj;
			if (plain == null) {
				if (other.plain != null)
					return false;
			} else {
				if(ignoreCase){
					if (!plain.equalsIgnoreCase(other.plain)){
						return false;
					}
				}
				else{
					if (!plain.equals(other.plain)){
						return false;
					}
				}
			}
			return true;
		}

	}

	/**
	 * Durchsucht eine Wortliste nach einem gegebenen Suchwort.<br/> <br/>
	 *
	 * Dies ist eine unscharfe Suche:<br/>
	 * Ein Suchwort wird in der Liste gefunden,
	 * wenn es in einem Wort der Liste in der richtigen Reihenfolge der
	 * Buchstaben vorkommt.<br/>
	 *
	 * Beispiel:<br/>
	 * John F. Kennedy wird durch die Angabe von JFK gefunden.
	 *
	 * @param searchList Die zu durchsuchende Liste.
	 * @param lookFor Das Suchwort.
	 * @param ignoreCase <code>true</code> wenn Groß-/Kleinschreibung ignoriert
	 *            werden soll.
	 * @return Die Ergebnisse der Suche.
	 */
	private static Set<SearchResult> doSearch(final Set<String> searchList,
			final String lookFor, final boolean ignoreCase) {
		final Set<SearchResult> resultList = new HashSet<SearchResult>();
		//Buchstaben des Suchwortes in ein Array packen.
		//Sofern ignoreCase = true, vorher in Großbuchstaben umwandeln.
		//toCharArray wird nicht verwendet, da nicht in jedem Encoding jeder
		//Buchstabe mit einem Char dargestellt werden kann.
		final String[] arr = ignoreCase ? lookFor.toUpperCase().split("")
				: lookFor.split("");
		//Über die Wörter der Liste iterieren
		for (final String possibleResult : searchList) {
			int startIndex = 0;
			//Sofern ignoreCase = true, zu durchsuchendes Wort
			//für die Suche in Großbuchstaben umwandeln.
			final String searchString = ignoreCase ? possibleResult
					.toUpperCase() : possibleResult;
					//Array mit den Buchstaben des Wortes für die Markierung
					//des Suchergebnis
					String[] marked = possibleResult.split("");
					//Über die Buchstaben des Suchwort iterieren.
					//Mittels indexOf(String,int) prüfen ob die Buchstaben
					//in der richtigen Reihenfolge vorkommen.
					//Bei i = 1 starten, da erstes Element im Array leer ist.
					for (int i = 1; i < arr.length; i++) {
						//Prüfen ob der
						int res = searchString.indexOf(arr[i], startIndex);
						if (res == -1) {
							//Suche für dieses Wort abbrechen wenn Buchstabe nicht gefunden wird.
							break;
						} else {
							//gefundenen Buchstaben markieren
							marked[res + 1] = "<" + marked[res + 1] + ">";
							//Startindex für indexOf Operation so setzen
							//dass der gerade gefundene Buchstabe nicht nochmal
							//gefunden wird
							startIndex = res + 1;
							//Wenn es sich um den letzten zu findenen Buchstaben
							//handelt, das Wort der Ergebnisliste hinzufügen.
							if (i == arr.length - 1) {
								final StringBuilder b = new StringBuilder();
								for (final String m : marked) {
									b.append(m);
								}
								resultList.add(new SearchResult(possibleResult, b
										.toString(),ignoreCase));
							}
						}
					}
		}
		return resultList;
	}

	/**
	 * Liest die Liste von zu durchsuchenden Wörtern zeilenweise aus einer Datei
	 * ein und gibt dieser zurück.
	 *
	 * Doppelte Wörter werden durch das Set ignoriert.
	 *
	 * @param path Der Pfad von welchem die Liste eingelesen werden soll.
	 * @return Ein Set mit Suchwörtern.
	 * @throws IOException Wenn die Datei nicht gefunden wird, oder beim
	 *             auslesen ein Fehler auftritt.
	 */
	private static Set<String> loadFromFile(final String path)
	throws IOException {
		final Set<String> searchList = new HashSet<String>();
		final File f = new File(path);
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(f));
			String line = null;
			while ((line = reader.readLine()) != null) {
				// Leerzeichen am Anfang und Ende entfernen. Sind
				// für die Suche nicht relevant
				searchList.add(line.trim());
			}
		} catch (IOException e) {
			throw e;
		} finally {
			reader.close();
		}
		return searchList;
	}

	/**
	 * Gibt eine Hilfe zur Benutzung aus.
	 */
	private static void usage() {
		System.out.println("Usage:");
		System.out.println("\t[-i] ignore case");
		System.out.println("\tPath to word file");
		System.out.println("\tSearch word");
		System.out.println("Example:");
		System.out.println("java " + UnsharpSearch.class.getName()
				+ " -i presidents.txt JFK");
	}

	public static void main(String[] args) throws IOException {
		// -i ist optional, daher entweder 2 oder 3 Argumente erlaubt
		if (args.length < 2 || args.length > 3) {
			usage();
			return;
		}
		int startIndex = 0;
		boolean ignoreCase = false;

		// Bei 3 Optionen muss die erste -i sein
		if (args.length == 3) {
			if (!args[0].equals("-i")) {
				usage();
				return;
			} else {
				ignoreCase = true;
				startIndex++;
			}
		}

		// Suchliste aus der Datei laden
		final Set<String> searchList = loadFromFile(args[startIndex++]);
		final String lookFor = args[startIndex++];
		// Suche durchführen
		final Set<SearchResult> resultList = doSearch(searchList, lookFor,
				ignoreCase);

		// Ergebnisse ausgeben wenn vorhanden
		if (!resultList.isEmpty()) {
			System.out.println("Your search for '" + lookFor
					+ "' has the following results: ");
			for (SearchResult result : resultList) {
				System.out.println("\t" + result.plain + " (" + result.marked
						+ ")");
			}
		} else {
			System.out.println("Your search for '" + lookFor
					+ "' has no results.");
		}
	}

}
 

zeja

Erfahrenes Mitglied
#2
Noch eine zweite Suchmethode für Patternmatching:
Java:
	/**
	 * Wandelt einen Suchstring in einen Regulären Ausdruck zur Suche um.
	 *
	 * @param search Der Suchstring
	 * @return Der reguläre Ausdruck für die Suche.
	 */
	private static String toSearchPattern(String search) {
		StringBuilder b = new StringBuilder();
		final String[] splitted = search.split("");
		for (int i = 1; i < splitted.length; i++) {
			b.append(".*(");
			b.append(splitted[i]);
			b.append(")");
		}
		b.append(".*");
		return b.toString();
	}

	/**
	 * Wandelt ein String-Array in einen String um.
	 *
	 * @param marked Das Array
	 * @return Der String
	 */
	private static String toString(String[] marked) {
		final StringBuilder b = new StringBuilder();
		for (final String m : marked) {
			b.append(m);
		}
		return b.toString();
	}

	private static String mark(String strg) {
		return "<" + strg + ">";
	}

	private static Set<SearchResult> doSearch2(final Set<String> searchList,
			final String lookFor, final boolean ignoreCase) {
		final Set<SearchResult> resultList = new HashSet<SearchResult>();
		final String pattern = toSearchPattern(ignoreCase ? lookFor
				.toUpperCase() : lookFor);
		final Pattern p = Pattern.compile(pattern);
		for (final String possibleResult : searchList) {
			final Matcher m = p.matcher(ignoreCase ? possibleResult
					.toUpperCase() : possibleResult);
			if (m.matches()) {
				// Anhand der Gruppen des Pattern die Suchwörter
				// markieren
				final String[] marked = possibleResult.split("");
				for (int i = 1; i <= m.groupCount(); i++) {
					int start = m.start(i);
					marked[start + 1] = mark(marked[start + 1]);
				}
				resultList.add(new SearchResult(possibleResult,
						toString(marked), ignoreCase));
			}
		}

		return resultList;
	}