fix(接口测试): json-schema按照正则表达式自动生成数据报错
--bug=1044111 --user=陈建星 【接口测试】接口-json请求参数-schema格式-string类型字段-参数值为空-json自动生成-正则表达式获取失败 https://www.tapd.cn/55049933/s/1550058
This commit is contained in:
parent
0480e75c43
commit
3dbde4f287
|
@ -94,12 +94,6 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- 根据正则表达式,生成随机字符串 -->
|
||||
<dependency>
|
||||
<groupId>com.github.krraghavan</groupId>
|
||||
<artifactId>xeger</artifactId>
|
||||
<version>${xeger.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -2,14 +2,16 @@ package io.metersphere.api.utils;
|
|||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.*;
|
||||
import io.metersphere.api.utils.regex.model.Node;
|
||||
import io.metersphere.api.utils.regex.model.OrdinaryNode;
|
||||
import io.metersphere.project.constants.PropertyConstant;
|
||||
import nl.flotsam.xeger.Xeger;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.text.RandomStringGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
@ -143,13 +145,17 @@ public class JsonSchemaBuilder {
|
|||
int max = isTextNotBlank(maxLength) ? maxLength.asInt() : 20;
|
||||
int min = isTextNotBlank(minLength) ? minLength.asInt() : 1;
|
||||
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||
value = enumValues.get(new SecureRandom().nextInt(enumValues.size())).asText();
|
||||
if (value.length() > max) {
|
||||
value = value.substring(0, max);
|
||||
}
|
||||
} else if (isTextNotBlank(pattern)) {
|
||||
Xeger generator = new Xeger(pattern.asText());
|
||||
value = generator.generate();
|
||||
try {
|
||||
Node node = new OrdinaryNode(pattern.asText());
|
||||
value = node.random();
|
||||
} catch (Exception e) {
|
||||
value = pattern.asText();
|
||||
}
|
||||
} else if (isTextNotBlank(defaultValue)) {
|
||||
value = defaultValue.asText();
|
||||
if (value.length() > max) {
|
||||
|
@ -159,7 +165,7 @@ public class JsonSchemaBuilder {
|
|||
value = value + generateStr(min - value.length());
|
||||
}
|
||||
} else {
|
||||
value = generateStr(new Random().nextInt(max - min + 1) + min);
|
||||
value = generateStr(new SecureRandom().nextInt(max - min + 1) + min);
|
||||
}
|
||||
}
|
||||
yield new TextNode(value);
|
||||
|
@ -169,7 +175,7 @@ public class JsonSchemaBuilder {
|
|||
JsonNode enumValues = propertyNode.get(PropertyConstant.ENUM_VALUES);
|
||||
JsonNode defaultValue = propertyNode.get(PropertyConstant.DEFAULT_VALUE);
|
||||
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||
value = enumValues.get(new SecureRandom().nextInt(enumValues.size())).asText();
|
||||
} else if (isTextNotBlank(defaultValue)) {
|
||||
value = defaultValue.asText();
|
||||
} else {
|
||||
|
@ -178,7 +184,7 @@ public class JsonSchemaBuilder {
|
|||
int max = isTextNotBlank(maximum) ? maximum.asInt() : Integer.MAX_VALUE;
|
||||
int min = isTextNotBlank(minimum) ? minimum.asInt() : Integer.MIN_VALUE;
|
||||
// 这里减去负数可能超过整型最大值,使用 Long 类型
|
||||
value = new Random().nextLong(Long.valueOf(max) - Long.valueOf(min)) + min + StringUtils.EMPTY;
|
||||
value = new SecureRandom().nextLong(Long.valueOf(max) - Long.valueOf(min)) + min + StringUtils.EMPTY;
|
||||
}
|
||||
} else {
|
||||
if (isVariable(value)) {
|
||||
|
@ -196,7 +202,7 @@ public class JsonSchemaBuilder {
|
|||
JsonNode enumValues = propertyNode.get(PropertyConstant.ENUM_VALUES);
|
||||
JsonNode defaultValue = propertyNode.get(PropertyConstant.DEFAULT_VALUE);
|
||||
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||
value = enumValues.get(new SecureRandom().nextInt(enumValues.size())).asText();
|
||||
} else if (isTextNotBlank(defaultValue)) {
|
||||
value = defaultValue.asText();
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package io.metersphere.api.utils.regex.exception;
|
||||
|
||||
public class RegexpIllegalException extends Exception {
|
||||
|
||||
public RegexpIllegalException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RegexpIllegalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RegexpIllegalException(String regexp, int index) {
|
||||
super(String.format("Invalid regular expression: %s, Index: %d", regexp, index));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.api.utils.regex.exception;
|
||||
|
||||
public class TypeNotMatchException extends Exception {
|
||||
|
||||
public TypeNotMatchException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TypeNotMatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.api.utils.regex.exception;
|
||||
|
||||
public class UninitializedException extends Exception {
|
||||
|
||||
public UninitializedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UninitializedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 参考 https://github.com/GitHub-Laziji/reverse-regexp 代码
|
||||
*
|
||||
*/
|
||||
public abstract class BaseNode implements Node {
|
||||
|
||||
private String expression;
|
||||
private List<String> expressionFragments;
|
||||
private boolean initialized;
|
||||
|
||||
protected BaseNode(String expression) throws RegexpIllegalException, TypeNotMatchException {
|
||||
this(expression, true);
|
||||
}
|
||||
|
||||
protected BaseNode(String expression, boolean initialize) throws RegexpIllegalException, TypeNotMatchException {
|
||||
this.expression = expression;
|
||||
this.expressionFragments = spliceExpression(expression);
|
||||
if (initialize) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
protected BaseNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
this(expressionFragments, true);
|
||||
}
|
||||
|
||||
protected BaseNode(List<String> expressionFragments, boolean initialize)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
this.expressionFragments = expressionFragments;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String fragment : expressionFragments) {
|
||||
stringBuilder.append(fragment);
|
||||
}
|
||||
this.expression = stringBuilder.toString();
|
||||
if (initialize) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String random() throws UninitializedException, RegexpIllegalException {
|
||||
if (!initialized) {
|
||||
throw new UninitializedException();
|
||||
}
|
||||
return random(expression, expressionFragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test() {
|
||||
return test(expression, expressionFragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws RegexpIllegalException, TypeNotMatchException {
|
||||
if (!initialized) {
|
||||
if (!test()) {
|
||||
throw new TypeNotMatchException();
|
||||
}
|
||||
init(expression, expressionFragments);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, UninitializedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
|
||||
}
|
||||
|
||||
protected boolean test(String expression, List<String> expressionFragments) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<String> spliceExpression(String expression) throws RegexpIllegalException {
|
||||
int l = 0;
|
||||
int r = expression.length();
|
||||
List<String> fragments = new ArrayList<>();
|
||||
while (true) {
|
||||
String result = findFirst(expression, l, r);
|
||||
if (result == null || result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
fragments.add(result);
|
||||
l += result.length();
|
||||
}
|
||||
return fragments;
|
||||
}
|
||||
|
||||
private String findFirst(String expression, int l, int r) throws RegexpIllegalException {
|
||||
if (l == r) {
|
||||
return null;
|
||||
}
|
||||
if (expression.charAt(l) == '\\') {
|
||||
if (l + 1 >= r) {
|
||||
throw new RegexpIllegalException(expression, l + 1);
|
||||
}
|
||||
return expression.substring(l, l + 2);
|
||||
}
|
||||
if (expression.charAt(l) == '[') {
|
||||
int i = l + 1;
|
||||
while (i < r) {
|
||||
if (expression.charAt(i) == ']') {
|
||||
return expression.substring(l, i + 1);
|
||||
}
|
||||
if (expression.charAt(i) == '\\') {
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new RegexpIllegalException(expression, r);
|
||||
}
|
||||
if (expression.charAt(l) == '{') {
|
||||
int i = l + 1;
|
||||
boolean hasDelimiter = false;
|
||||
while (i < r) {
|
||||
if (expression.charAt(i) == '}') {
|
||||
return expression.substring(l, i + 1);
|
||||
}
|
||||
if (expression.charAt(i) == ',') {
|
||||
if (hasDelimiter) {
|
||||
throw new RegexpIllegalException(expression, i);
|
||||
}
|
||||
hasDelimiter = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (expression.charAt(i) < '0' || expression.charAt(i) > '9') {
|
||||
throw new RegexpIllegalException(expression, i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new RegexpIllegalException(expression, r);
|
||||
}
|
||||
if (expression.charAt(l) == '(') {
|
||||
int i = l + 1;
|
||||
while (true) {
|
||||
String result = findFirst(expression, i, r);
|
||||
if (result == null || result.length() == 0 || result.length() + i >= r) {
|
||||
throw new RegexpIllegalException(expression, i);
|
||||
}
|
||||
i += result.length();
|
||||
if (expression.charAt(i) == ')') {
|
||||
return expression.substring(l, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expression.substring(l, l + 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LinkNode extends BaseNode {
|
||||
|
||||
private List<Node> children;
|
||||
|
||||
protected LinkNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments);
|
||||
}
|
||||
|
||||
protected LinkNode(List<String> expressionFragments, boolean initialize)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments, initialize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean test(String expression, List<String> expressionFragments) {
|
||||
for (String fragment : expressionFragments) {
|
||||
if ("|".equals(fragment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
children = new ArrayList<>();
|
||||
for (int i = 0; i < expressionFragments.size(); i++) {
|
||||
Node node;
|
||||
if (i + 1 < expressionFragments.size()) {
|
||||
node = new RepeatNode(
|
||||
Arrays.asList(expressionFragments.get(i), expressionFragments.get(i + 1)),
|
||||
false);
|
||||
if (node.test()) {
|
||||
node.init();
|
||||
children.add(node);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
node = new SingleNode(Collections.singletonList(expressionFragments.get(i)));
|
||||
children.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, UninitializedException {
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (Node node : children) {
|
||||
value.append(node.random());
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
public interface Node {
|
||||
|
||||
String getExpression();
|
||||
|
||||
String random() throws UninitializedException, RegexpIllegalException;
|
||||
|
||||
boolean test();
|
||||
|
||||
void init() throws RegexpIllegalException, TypeNotMatchException;
|
||||
|
||||
boolean isInitialized();
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class OptionalNode extends BaseNode {
|
||||
|
||||
private List<Node> children;
|
||||
|
||||
protected OptionalNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments);
|
||||
}
|
||||
|
||||
protected OptionalNode(List<String> expressionFragments, boolean initialize)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments, initialize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean test(String expression, List<String> expressionFragments) {
|
||||
for (String fragment : expressionFragments) {
|
||||
if ("|".equals(fragment)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
children = new ArrayList<>();
|
||||
List<String> subFragments = new ArrayList<>();
|
||||
for (String fragment : expressionFragments) {
|
||||
if ("|".equals(fragment)) {
|
||||
children.add(new OrdinaryNode(subFragments));
|
||||
subFragments = new ArrayList<>();
|
||||
continue;
|
||||
}
|
||||
subFragments.add(fragment);
|
||||
}
|
||||
children.add(new OrdinaryNode(subFragments));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws UninitializedException, RegexpIllegalException {
|
||||
return children.get(new SecureRandom().nextInt(children.size())).random();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
import java.util.List;
|
||||
|
||||
public class OrdinaryNode extends BaseNode {
|
||||
|
||||
private Node proxyNode;
|
||||
|
||||
public OrdinaryNode(String expression) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
protected OrdinaryNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
if (expressionFragments.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Node[] nodes = new Node[]{
|
||||
new OptionalNode(expressionFragments, false),
|
||||
new SingleNode(expressionFragments, false),
|
||||
new RepeatNode(expressionFragments, false),
|
||||
new LinkNode(expressionFragments, false)
|
||||
};
|
||||
for (Node node : nodes) {
|
||||
if (node.test()) {
|
||||
proxyNode = node;
|
||||
proxyNode.init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws UninitializedException, RegexpIllegalException {
|
||||
if (proxyNode == null) {
|
||||
return "";
|
||||
}
|
||||
return proxyNode.random();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class RepeatNode extends BaseNode {
|
||||
|
||||
private static final int MAX_REPEAT = 16;
|
||||
|
||||
private Node node;
|
||||
private int minRepeat = 1;
|
||||
private int maxRepeat = 1;
|
||||
|
||||
protected RepeatNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments);
|
||||
}
|
||||
|
||||
protected RepeatNode(List<String> expressionFragments, boolean initialize)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments, initialize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean test(String expression, List<String> expressionFragments) {
|
||||
if (expressionFragments.size() == 2) {
|
||||
String token = expressionFragments.get(1);
|
||||
return token != null
|
||||
&& ("+".equals(token) || "?".equals(token) || "*".equals(token) || token.startsWith("{"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
node = new SingleNode(Collections.singletonList(expressionFragments.get(0)));
|
||||
String token = expressionFragments.get(1);
|
||||
if ("+".equals(token)) {
|
||||
maxRepeat = MAX_REPEAT;
|
||||
} else if ("?".equals(token)) {
|
||||
minRepeat = 0;
|
||||
} else if ("*".equals(token)) {
|
||||
minRepeat = 0;
|
||||
maxRepeat = MAX_REPEAT;
|
||||
} else if (token.startsWith("{")) {
|
||||
String[] numbers = token.substring(1, token.length() - 1).split(",", 2);
|
||||
minRepeat = maxRepeat = Integer.parseInt(numbers[0]);
|
||||
if (numbers.length > 1) {
|
||||
maxRepeat = numbers[1].isEmpty() ? Math.max(MAX_REPEAT, minRepeat) : Integer.parseInt(numbers[1]);
|
||||
if (maxRepeat < minRepeat) {
|
||||
throw new RegexpIllegalException("Invalid regular expression: "
|
||||
+ getExpression() + " : Numbers out of order in {} quantifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, UninitializedException {
|
||||
int repeat = new SecureRandom().nextInt(maxRepeat - minRepeat + 1) + minRepeat;
|
||||
StringBuilder value = new StringBuilder();
|
||||
while (repeat-- > 0) {
|
||||
value.append(node.random());
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package io.metersphere.api.utils.regex.model;
|
||||
|
||||
import io.metersphere.api.utils.regex.exception.*;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class SingleNode extends BaseNode {
|
||||
|
||||
private Node node;
|
||||
|
||||
private List<Interval> intervals;
|
||||
|
||||
protected SingleNode(List<String> expressionFragments) throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments);
|
||||
}
|
||||
|
||||
protected SingleNode(List<String> expressionFragments, boolean initialize)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
super(expressionFragments, initialize);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean test(String expression, List<String> expressionFragments) {
|
||||
return expressionFragments != null && expressionFragments.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, TypeNotMatchException {
|
||||
if (expression.startsWith("(")) {
|
||||
node = new OrdinaryNode(expression.substring(1, expression.length() - 1));
|
||||
return;
|
||||
}
|
||||
if (expression.startsWith("[")) {
|
||||
int i = 1;
|
||||
Character preChar = null;
|
||||
while (i < expression.length() - 1) {
|
||||
if (expression.charAt(i) == '\\') {
|
||||
if (i + 1 >= expression.length() - 1) {
|
||||
throw new RegexpIllegalException(expression, i);
|
||||
}
|
||||
if (preChar != null && "dws".contains(expression.charAt(i + 1) + "")) {
|
||||
addIntervals(preChar, null, '-', null);
|
||||
preChar = null;
|
||||
}
|
||||
if (expression.charAt(i + 1) == 'd') {
|
||||
addIntervals('0', '9');
|
||||
} else if (expression.charAt(i + 1) == 'w') {
|
||||
addIntervals('0', '9', 'A', 'Z', 'a', 'z', '_', null);
|
||||
} else if (expression.charAt(i + 1) == 's') {
|
||||
addIntervals(' ', null, '\t', null);
|
||||
} else {
|
||||
if (preChar != null) {
|
||||
addIntervals(preChar, expression.charAt(i + 1));
|
||||
preChar = null;
|
||||
} else if (i + 2 < expression.length() && expression.charAt(i + 2) == '-') {
|
||||
preChar = expression.charAt(i + 1);
|
||||
i++;
|
||||
} else {
|
||||
addIntervals(expression.charAt(i + 1), null);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} else if (preChar != null) {
|
||||
addIntervals(preChar, expression.charAt(i));
|
||||
preChar = null;
|
||||
} else if (i + 1 < expression.length() && expression.charAt(i + 1) == '-') {
|
||||
preChar = expression.charAt(i);
|
||||
i++;
|
||||
} else {
|
||||
addIntervals(expression.charAt(i), null);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (preChar != null) {
|
||||
addIntervals(preChar, null, '-', null);
|
||||
}
|
||||
} else if (".".equals(expression)) {
|
||||
// 这里仅包含一般字符,参考 ASCII 码表
|
||||
addIntervals((char) 33, (char) 126);
|
||||
} else if ("\\s".equals(expression)) {
|
||||
addIntervals(' ', null, '\t', null);
|
||||
} else if ("\\d".equals(expression)) {
|
||||
addIntervals('0', '9');
|
||||
} else if ("\\w".equals(expression)) {
|
||||
addIntervals('0', '9', 'A', 'Z', 'a', 'z', '_', null);
|
||||
} else if (expression.startsWith("\\")) {
|
||||
addIntervals(expression.charAt(1), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String random(String expression, List<String> expressionFragments)
|
||||
throws RegexpIllegalException, UninitializedException {
|
||||
if (node != null) {
|
||||
return node.random();
|
||||
}
|
||||
if (intervals != null && intervals.size() > 0) {
|
||||
Character value = randomCharFromInterval(intervals.toArray(new Interval[0]));
|
||||
return value == null ? "" : value.toString();
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private Character randomCharFromInterval(Interval... intervals) {
|
||||
int count = 0;
|
||||
for (Interval interval : intervals) {
|
||||
count += interval.end + 1 - interval.start;
|
||||
}
|
||||
int randomValue = new SecureRandom().nextInt(count);
|
||||
for (Interval interval : intervals) {
|
||||
if (randomValue < interval.end + 1 - interval.start) {
|
||||
return (char) (interval.start + randomValue);
|
||||
}
|
||||
randomValue -= interval.end + 1 - interval.start;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addIntervals(Character... chars) throws RegexpIllegalException {
|
||||
if (intervals == null) {
|
||||
intervals = new ArrayList<>();
|
||||
}
|
||||
for (int i = 0; i + 1 < chars.length; i += 2) {
|
||||
Character start = chars[i];
|
||||
Character end = chars[i + 1] == null ? start : chars[i + 1];
|
||||
if (start == null) {
|
||||
throw new RegexpIllegalException("Invalid regular expression: "
|
||||
+ getExpression() + " : Character class is null");
|
||||
}
|
||||
if (end < start) {
|
||||
throw new RegexpIllegalException("Invalid regular expression: "
|
||||
+ getExpression() + " : Range out of order in character class");
|
||||
}
|
||||
intervals.add(new Interval(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Interval {
|
||||
private char start;
|
||||
private char end;
|
||||
|
||||
private Interval(char start, char end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue