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. 30
      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) { if (closingIndex == -1) {
throw new InvalidPathException("Pattern not closed. Expected " + PATTERN + " in " + filter); throw new InvalidPathException("Pattern not closed. Expected " + PATTERN + " in " + filter);
} else { } else {
if(filter.inBounds(closingIndex+1) && filter.charAt(closingIndex+1) == IGNORE_CASE){ if(filter.inBounds(closingIndex+1)) {
closingIndex++; 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); 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 { class PatternNode extends ValueNode {
private final String pattern; private final String pattern;
private final Pattern compiledPattern; private final Pattern compiledPattern;
private final String flags;
PatternNode(CharSequence charSequence) { PatternNode(CharSequence charSequence) {
String tmp = charSequence.toString(); String tmp = charSequence.toString();
int begin = tmp.indexOf('/'); int begin = tmp.indexOf('/');
int end = tmp.lastIndexOf('/'); int end = tmp.lastIndexOf('/');
int flags = tmp.endsWith("/i") ? Pattern.CASE_INSENSITIVE : 0;
this.pattern = tmp.substring(begin + 1, end); 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) { PatternNode(Pattern pattern) {
this.pattern = pattern.pattern(); this.pattern = pattern.pattern();
this.compiledPattern = pattern; this.compiledPattern = pattern;
this.flags = PatternFlag.parseFlags(pattern.flags());
} }
@ -83,10 +86,6 @@ public interface ValueNodes {
@Override @Override
public String toString() { public String toString() {
String flags = "";
if((compiledPattern.flags() & Pattern.CASE_INSENSITIVE) == Pattern.CASE_INSENSITIVE){
flags = "i";
}
if(!pattern.startsWith("/")){ if(!pattern.startsWith("/")){
return "/" + pattern + "/" + flags; return "/" + pattern + "/" + flags;
} else { } 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" }
}
);
}
}

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

@ -49,14 +49,28 @@ public class RegexpEvaluatorTest extends BaseTest {
public static Iterable data() { public static Iterable data() {
return Arrays.asList( return Arrays.asList(
new Object[][]{ new Object[][]{
{ "/true|false/", createStringNode("true", true), true }, { "/true|false/", createStringNode("true", true), true },
{ "/9.*9/", createNumberNode("9979"), true }, { "/9.*9/", createNumberNode("9979"), true },
{ "/fa.*se/", createBooleanNode("false"), true }, { "/fa.*se/", createBooleanNode("false"), true },
{ "/Eval.*or/", createClassNode(String.class), false }, { "/Eval.*or/", createClassNode(String.class), false },
{ "/JsonNode/", createJsonNode(json()), false }, { "/JsonNode/", createJsonNode(json()), false },
{ "/PathNode/", createPathNode(path()), false }, { "/PathNode/", createPathNode(path()), false },
{ "/Undefined/", createUndefinedNode(), 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