This is an automated email from the ASF dual-hosted git repository.
jsorel pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 217d0a8 Filter : implement PropertyIsLike filter
217d0a8 is described below
commit 217d0a88386a31de06dcbcd2211294c2689c9467
Author: jsorel <johann.sorel@geomatys.com>
AuthorDate: Mon Jun 15 12:28:04 2020 +0200
Filter : implement PropertyIsLike filter
---
.../java/org/apache/sis/filter/DefaultLike.java | 90 +++++++++++++++++++++-
.../org/apache/sis/filter/LikeFunctionTest.java | 17 +++-
2 files changed, 103 insertions(+), 4 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultLike.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultLike.java
index 6963bda..e26c038 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultLike.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultLike.java
@@ -18,7 +18,9 @@ package org.apache.sis.filter;
import java.util.Arrays;
import java.util.Collection;
+import java.util.regex.Pattern;
import org.apache.sis.internal.filter.Node;
+import org.apache.sis.util.ArgumentChecks;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.PropertyIsLike;
import org.opengis.filter.expression.Expression;
@@ -40,7 +42,20 @@ final class DefaultLike extends Node implements PropertyIsLike {
private final String escape;
private final boolean matchingCase;
+ /**
+ * Cached java regular expression.
+ */
+ private Pattern regex;
+
DefaultLike(Expression expression, String pattern, String wildcard, String singleChar,
String escape, boolean matchingCase) {
+ ArgumentChecks.ensureNonNull("pattern", pattern);
+ ArgumentChecks.ensureNonNull("wildcard", wildcard);
+ ArgumentChecks.ensureNonNull("singleChar", singleChar);
+ ArgumentChecks.ensureNonNull("escape", escape);
+ if (wildcard.length() != 1) throw new IllegalArgumentException("WildCard string must
be one character long.");
+ if (singleChar.length() != 1) throw new IllegalArgumentException("SingleChar string
must be one character long.");
+ if (escape.length() != 1) throw new IllegalArgumentException("Escape string must
be one character long.");
+
this.expression = expression;
this.pattern = pattern;
this.wildcard = wildcard;
@@ -91,7 +106,9 @@ final class DefaultLike extends Node implements PropertyIsLike {
@Override
public boolean evaluate(Object object) {
- throw new UnsupportedOperationException("Not supported yet.");
+ final String value = expression.evaluate(object, String.class);
+ if (value == null) return false;
+ return getPattern().matcher(value).matches();
}
@Override
@@ -99,4 +116,75 @@ final class DefaultLike extends Node implements PropertyIsLike {
return visitor.visit(this, extraData);
}
+ /**
+ * Get or create java regex pattern.
+ */
+ private Pattern getPattern() {
+ if (regex == null) {
+ //convert pattern to java regex
+ final StringBuilder sb = new StringBuilder();
+ if (!matchingCase) {
+ //add case insensitive
+ sb.append("(?i)");
+ }
+ final int wld = wildcard.charAt(0);
+ final int sgl = singleChar.charAt(0);
+ final int esc = escape.charAt(0);
+
+ for (int i = 0, n = pattern.length(); i < n; i++) {
+ char c = pattern.charAt(i);
+
+ //user defined special characters
+ if (wld == c) {
+ sb.append('.');
+ sb.append('*');
+ } else if (sgl == c) {
+ sb.append('.');
+ } else if (esc == c) {
+ c = pattern.charAt(++i);
+ if (c == wld || c == sgl || c == esc) {
+ if (isMetaCharacter(c)) {
+ sb.append('\\');
+ }
+ sb.append(c);
+ } else {
+ throw new IllegalArgumentException("Escape character must be used
only to escape wild, single and escape characters.");
+ }
+ }
+ //java regex reserved metacharacters
+ else if (isMetaCharacter(c)) {
+ sb.append('\\');
+ sb.append(c);
+ }
+ //any other character
+ else {
+ sb.append(c);
+ }
+ }
+
+ regex = Pattern.compile(sb.toString());
+ }
+ return regex;
+ }
+
+ /**
+ * Returns true if given character is a regular expression meta-character.
+ */
+ private static boolean isMetaCharacter(char c) {
+ return c == '.'
+ || c == '*'
+ || c == '?'
+ || c == '('
+ || c == ')'
+ || c == '['
+ || c == ']'
+ || c == '{'
+ || c == '}'
+ || c == '\\'
+ || c == '^'
+ || c == '$'
+ || c == '|'
+ || c == '+';
+ }
+
}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/LikeFunctionTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/LikeFunctionTest.java
index 00a1efe..a97c34e 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/LikeFunctionTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/LikeFunctionTest.java
@@ -19,8 +19,8 @@ package org.apache.sis.filter;
import org.opengis.filter.FilterFactory;
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import org.junit.Ignore;
+import static org.apache.sis.test.Assert.*;
/**
* Tests {@code ComparisonFunction.Like} implementations.
@@ -47,9 +47,20 @@ public final strictfp class LikeFunctionTest extends TestCase {
/**
* Tests "Like" (construction, evaluation, serialization, equality).
*/
- @Ignore
@Test
public void testLike() {
- //todo
+
+ assertTrue(factory.like(factory.literal("Apache SIS"), "Apache*", "*", ".", "\\",
true).evaluate(null));
+ assertFalse(factory.like(factory.literal("Apache SIS"), "Oracle*", "*", ".", "\\",
true).evaluate(null));
+
+ // a character is missing, should not match
+ assertFalse(factory.like(factory.literal("Apache SIS"), "Apache*IS.*", "*", ".",
"\\", true).evaluate(null));
+ assertTrue(factory.like(factory.literal("Apache SIS"), "Apache*I.", "*", ".", "\\",
true).evaluate(null));
+
+ // test case insensitive
+ assertTrue(factory.like(factory.literal("Apache SIS"), "apache sis", "*", ".", "\\",
false).evaluate(null));
+
+ // test escape
+ assertTrue(factory.like(factory.literal("*Apache* SIS"), "!*Apache!* SIS", "*", ".",
"!", true).evaluate(null));
}
}
|