Java tutorial
/* Copyright (c) 2014 Karol Stasiak * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package io.github.karols.hocr4j; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import java.util.Comparator; import java.util.Locale; import java.util.regex.Pattern; import javax.annotation.Nullable; /** * Utility class containing predicates and comparators for lines. * * @see io.github.karols.hocr4j.Line */ public final class LineThat { private final static Comparator<Line> HAS_LEAST_WORDS = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.words.size(); int c2 = line2.words.size(); if (c1 > c2) return -1; if (c1 < c2) return 1; return 0; } }; private final static Comparator<Line> HAS_MOST_WORDS = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.words.size(); int c2 = line2.words.size(); if (c1 > c2) return 1; if (c1 < c2) return -1; return 0; } }; private static final Predicate<Line> IS_ARBITRARY = Predicates.alwaysTrue(); private static final Comparator<Line> IS_AT_THE_BEGINNING = new Comparator<Line>() { @Override public int compare(Line line1, Line line2) { return LineThat.IS_AT_THE_END.compare(line2, line1); } }; private final static Comparator<Line> IS_AT_THE_BOTTOM = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.getBounds().getMiddle(); int c2 = line2.getBounds().getMiddle(); if (c1 > c2) return 1; if (c1 < c2) return -1; return 0; } }; private static final Comparator<Line> IS_AT_THE_END = new Comparator<Line>() { public int compare(Line line, Line line2) { Bounds b1 = line.bounds; Bounds b2 = line2.bounds; if (b1 != null && b2 != null) { if (b1.isBelow(b2)) return 1; if (b2.isBelow(b1)) return -1; if (b1.isToTheRight(b2)) return 1; if (b2.isToTheRight(b1)) return -1; if (b1.getMiddle() > b2.getMiddle()) return 1; if (b1.getMiddle() < b2.getMiddle()) return -1; if (b1.getCenter() > b2.getCenter()) return 1; if (b1.getCenter() < b2.getCenter()) return -1; return 0; } else { return Integer.compare(line.hashCode(), line2.hashCode()); } } }; private final static Comparator<Line> IS_AT_THE_LEFT = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.getBounds().getCenter(); int c2 = line2.getBounds().getCenter(); if (c1 > c2) return -1; if (c1 < c2) return 1; return 0; } }; private final static Comparator<Line> IS_AT_THE_RIGHT = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.getBounds().getCenter(); int c2 = line2.getBounds().getCenter(); if (c1 > c2) return 1; if (c1 < c2) return -1; return 0; } }; private final static Comparator<Line> IS_AT_THE_TOP = new Comparator<Line>() { public int compare(Line line, Line line2) { int c1 = line.getBounds().getMiddle(); int c2 = line2.getBounds().getMiddle(); if (c1 > c2) return -1; if (c1 < c2) return 1; return 0; } }; private static final Predicate<Line> IS_NOT_BLANK = new Predicate<Line>() { public boolean apply(Line input) { return input != null && !input.isBlank(); } }; /** * Returns a predicate that tests * if the line contains given string. * * @param string a string to search for, * @return predicate */ public static Predicate<Line> contains(final String string) { return new Predicate<Line>() { public boolean apply(Line input) { return input != null && input.mkString().contains(string); } }; } /** * Returns a predicate that tests * if the line contains given string, ignoring all whitespace and letter case. * * @param needle a string to search for, * @return predicate */ public static Predicate<Line> containsIgnoringCaseAndSpace(String needle, final Locale locale) { final String lowercaseSpacelessNeedle = needle.toLowerCase(locale); return new Predicate<Line>() { @Override public boolean apply(@Nullable Line line) { if (line == null) return false; String lowercaseSpacelessLine = line.mkLowercaseSpacelessString(locale); return lowercaseSpacelessLine.contains(lowercaseSpacelessNeedle); } }; } /** * Returns a comparator comparing lines by the number of words descending * * @return comparator */ public static Comparator<Line> hasLeastWords() { return HAS_LEAST_WORDS; } /** * Returns a comparator comparing lines by the number of words ascending * * @return comparator */ public static Comparator<Line> hasMostWords() { return HAS_MOST_WORDS; } /** * Returns a predicate that tests * if the line has any word that intersects given rectangle. * * @param rect rectangle * @return predicate */ public static Predicate<Line> hasWordsIntersecting(final Bounds rect) { return new Predicate<Line>() { public boolean apply(@Nullable Line input) { if (input == null) { return false; } for (Word w : input.words) { if (w.getBounds().intersects(rect)) { return true; } } return false; } }; } /** * Returns a predicate that always yields true. * * @return predicate */ public static Predicate<Line> isArbitrary() { return IS_ARBITRARY; } /** * Returns a comparator comparing lines * reverse to the natural flow of the left-to-right text * * @return comparator */ public static Comparator<Line> isAtTheBeginning() { return IS_AT_THE_BEGINNING; } /** * Returns a comparator comparing lines by their average y coordinate ascending * * @return comparator */ public static Comparator<Line> isAtTheBottom() { return IS_AT_THE_BOTTOM; } /** * Returns a comparator comparing lines * according to the natural flow of the left-to-right text * * @return comparator */ public static Comparator<Line> isAtTheEnd() { return IS_AT_THE_END; } /** * Returns a comparator comparing lines by their average x coordinate descending * * @return comparator */ public static Comparator<Line> isAtTheLeft() { return IS_AT_THE_LEFT; } /** * Returns a comparator comparing lines by their average x coordinate ascending * * @return comparator */ public static Comparator<Line> isAtTheRight() { return IS_AT_THE_RIGHT; } /** * Returns a comparator comparing lines by their average y coordinate descending * * @return comparator */ public static Comparator<Line> isAtTheTop() { return IS_AT_THE_TOP; } /** * Returns a predicate that tests if a line * is in the same column as the header and below it, * and also satisfies the inner predicate. * * @param header bounds of the column header * @param also inner predicate * @return predicate */ public static Predicate<Line> isBelowInTheSameColumnAndAlso(Bounded header, final Predicate<Line> also) { final Bounds headerBounds = header.getBounds(); if (headerBounds == null || also == null) { return Predicates.alwaysFalse(); } return new Predicate<Line>() { @Override public boolean apply(@Nullable Line line) { if (line == null) return false; Bounds bounds = line.bounds; if (bounds == null) return false; return bounds.inTheSameColumnAs(headerBounds) && bounds.isBelow(headerBounds) && also.apply(line); } }; } /** * Returns a predicate that returns <code>true</code> if the line is not blank. * * @return predicate */ public static Predicate<Line> isNotBlank() { return IS_NOT_BLANK; } /** * Returns a predicate that tests if a line * is in the same row as the header and to the right of it, * and also satisfies the inner predicate. * * @param header bounds of the row header * @param also inner predicate * @return predicate */ public static Predicate<Line> isRightInTheSameRowAndAlso(Bounded header, final Predicate<Line> also) { final Bounds headerBounds = header.getBounds(); if (headerBounds == null || also == null) { return Predicates.alwaysFalse(); } return new Predicate<Line>() { @Override public boolean apply(@Nullable Line line) { if (line == null) return false; Bounds bounds = line.bounds; if (bounds == null) return false; return bounds.inTheSameRowAs(headerBounds) && bounds.isToTheRight(headerBounds) && also.apply(line); } }; } /** * Returns a predicate that returns <code>true</code> * if the line matches given pattern case-sensitive * * @param regex pattern * @return predicate */ public static Predicate<Line> matchesRegex(String regex) { return matchesRegex(Pattern.compile(regex)); } /** * Returns a predicate that returns <code>true</code> * if the line matches given pattern * * @param regex pattern * @return predicate */ public static Predicate<Line> matchesRegex(final Pattern regex) { return new Predicate<Line>() { public boolean apply(Line input) { return input != null && regex.matcher(input.mkString()).matches(); } }; } /** * Returns a predicate that returns <code>true</code> * if the line matches given pattern case-insensitive * * @param regex pattern * @return predicate */ public static Predicate<Line> matchesRegexIgnoringCase(String regex) { return matchesRegex(Pattern.compile(regex, Pattern.CASE_INSENSITIVE)); } private LineThat() { } }