Browse Source

Add support for pattern flags

pull/423/head
Uladzislau Arlouski 6 years ago
parent
commit
cbdc9c82e0
  1. 7
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
  2. 48
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/PatternFlag.java
  3. 11
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java
  4. 47
      json-path/src/test/java/com/jayway/jsonpath/internal/filter/PatternFlagTest.java
  5. 16
      json-path/src/test/java/com/jayway/jsonpath/internal/filter/RegexpEvaluatorTest.java

7
json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java

@ -280,8 +280,11 @@ public class FilterCompiler {
if (closingIndex == -1) {
throw new InvalidPathException("Pattern not closed. Expected " + PATTERN + " in " + filter);
} else {
if(filter.inBounds(closingIndex+1) && filter.charAt(closingIndex+1) == IGNORE_CASE){
closingIndex++;
if(filter.inBounds(closingIndex+1)) {
int equalSignIndex = filter.nextIndexOf('=');
int endIndex = equalSignIndex > closingIndex ? equalSignIndex : filter.nextIndexOfUnescaped(CLOSE_PARENTHESIS);
CharSequence flags = filter.subSequence(closingIndex + 1, endIndex);
closingIndex += flags.length();
}
filter.setPosition(closingIndex + 1);
}

48
json-path/src/main/java/com/jayway/jsonpath/internal/filter/PatternFlag.java

@ -0,0 +1,48 @@
package com.jayway.jsonpath.internal.filter;
import java.util.regex.Pattern;
public enum PatternFlag {
UNIX_LINES(Pattern.UNIX_LINES, 'd'),
CASE_INSENSITIVE(Pattern.CASE_INSENSITIVE, 'i'),
COMMENTS(Pattern.COMMENTS, 'x'),
MULTILINE(Pattern.MULTILINE, 'm'),
DOTALL(Pattern.DOTALL, 's'),
UNICODE_CASE(Pattern.UNICODE_CASE, 'u'),
UNICODE_CHARACTER_CLASS(Pattern.UNICODE_CHARACTER_CLASS, 'U');
private final int code;
private final char flag;
private PatternFlag(int code, char flag) {
this.code = code;
this.flag = flag;
}
public static int parseFlags(char[] flags) {
int flagsValue = 0;
for (char flag : flags) {
flagsValue |= getCodeByFlag(flag);
}
return flagsValue;
}
public static String parseFlags(int flags) {
StringBuilder builder = new StringBuilder();
for (PatternFlag patternFlag : PatternFlag.values()) {
if ((patternFlag.code & flags) == patternFlag.code) {
builder.append(patternFlag.flag);
}
}
return builder.toString();
}
private static int getCodeByFlag(char flag) {
for (PatternFlag patternFlag : PatternFlag.values()) {
if (patternFlag.flag == flag) {
return patternFlag.code;
}
}
return 0;
}
}

11
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java

@ -47,19 +47,22 @@ public interface ValueNodes {
class PatternNode extends ValueNode {
private final String pattern;
private final Pattern compiledPattern;
private final String flags;
PatternNode(CharSequence charSequence) {
String tmp = charSequence.toString();
int begin = tmp.indexOf('/');
int end = tmp.lastIndexOf('/');
int flags = tmp.endsWith("/i") ? Pattern.CASE_INSENSITIVE : 0;
this.pattern = tmp.substring(begin + 1, end);
this.compiledPattern = Pattern.compile(pattern, flags);
int flagsIndex = end + 1;
this.flags = tmp.length() > flagsIndex ? tmp.substring(flagsIndex) : "";
this.compiledPattern = Pattern.compile(pattern, PatternFlag.parseFlags(flags.toCharArray()));
}
PatternNode(Pattern pattern) {
this.pattern = pattern.pattern();
this.compiledPattern = pattern;
this.flags = PatternFlag.parseFlags(pattern.flags());
}
@ -83,10 +86,6 @@ public interface ValueNodes {
@Override
public String toString() {
String flags = "";
if((compiledPattern.flags() & Pattern.CASE_INSENSITIVE) == Pattern.CASE_INSENSITIVE){
flags = "i";
}
if(!pattern.startsWith("/")){
return "/" + pattern + "/" + flags;
} else {

47
json-path/src/test/java/com/jayway/jsonpath/internal/filter/PatternFlagTest.java

@ -0,0 +1,47 @@
package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class PatternFlagTest extends BaseTest {
private final int flags;
private final String expectedFlags;
public PatternFlagTest(int flags, String expectedFlags) {
this.flags = flags;
this.expectedFlags = expectedFlags;
}
@Test
public void testParseFlags() {
Assert.assertEquals(expectedFlags, PatternFlag.parseFlags(flags));
}
@Parameterized.Parameters
public static Iterable data() {
return Arrays.asList(
new Object[][]{
{ 1, "d" },
{ 2, "i" },
{ 4, "x" },
{ 8, "m" },
{ 32, "s" },
{ 64, "u" },
{ 256, "U" },
{ 300, "xmsU" },
{ 13, "dxm" },
{ 7, "dix" },
{ 100, "xsu" },
{ 367, "dixmsuU" }
}
);
}
}

16
json-path/src/test/java/com/jayway/jsonpath/internal/filter/RegexpEvaluatorTest.java

@ -56,7 +56,21 @@ public class RegexpEvaluatorTest extends BaseTest {
{ "/JsonNode/", createJsonNode(json()), false },
{ "/PathNode/", createPathNode(path()), false },
{ "/Undefined/", createUndefinedNode(), false },
{ "/NullNode/", createNullNode(), false }
{ "/NullNode/", createNullNode(), false },
{ "/test/i", createStringNode("tEsT", true), true },
{ "/test/", createStringNode("tEsT", true), false },
{ "/\u00de/ui", createStringNode("\u00fe", true), true },
{ "/\u00de/", createStringNode("\u00fe", true), false },
{ "/\u00de/i", createStringNode("\u00fe", true), false },
{ "/test# code/", createStringNode("test", true), false },
{ "/test# code/x", createStringNode("test", true), true },
{ "/.*test.*/d", createStringNode("my\rtest", true), true },
{ "/.*test.*/", createStringNode("my\rtest", true), false },
{ "/.*tEst.*/is", createStringNode("test\ntest", true), true },
{ "/.*tEst.*/i", createStringNode("test\ntest", true), false },
{ "/^\\w+$/U", createStringNode("\u00fe", true), true },
{ "/^\\w+$/", createStringNode("\u00fe", true), false },
{ "/^test$\\ntest$/m", createStringNode("test\ntest", true), true }
}
);
}

Loading…
Cancel
Save