sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jso...@apache.org
Subject [sis] branch geoapi-4.0 updated: Filter : implement PropertyIsLike filter
Date Mon, 15 Jun 2020 10:29:27 GMT
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));
     }
 }


Mime
View raw message