使用正则表达式生成字符串而不是匹配它们

我正在编写一个 Java 实用程序,它可以帮助我为性能测试生成大量数据。如果能够为 String 指定一个正则表达式,以便我的生成器输出与之匹配的内容,那将是 真的很酷的一件事。

外面是不是有什么东西已经烤好了,我可以用来做这个?还是有个图书馆能让我大部分时间都去那儿?

103771 次浏览

您必须编写自己的解析器,就像 String: : Random (Perl)的作者那样。实际上,他并没有在模块的任何地方使用正则表达式,这只是 perl 编码器所习惯的。

另一方面,也许你可以看看 源头,得到一些指导。


该死 Blair 比我快了15秒。

编辑:

关于这个问题的建议图书馆完整清单:

  1. Xeger *-Java
  2. Generex *-Java
  3. Rgxgen -Java
  4. Rxrdg -C #

*-取决于 dk.brics.automaton

编辑: 正如评论中提到的,Google Code 提供了一个库来实现这一点: Https://code.google.com/archive/p/xeger/

参见 Mifmif所建议的 https://github.com/mifmif/Generex

原文:

首先,对于足够复杂的 regexp,我认为这是不可能的。但是您应该能够为简单的 regexp 组装一些东西。

如果您看一下 java.util.regex 类的源代码。模式,您将看到它使用 Node 实例的内部表示形式。每个不同的模式组件都有自己的 Node 子类实现。这些节点组织成一棵树。

通过生成一个遍历此树的访问者,您应该能够调用重载的生成器方法或某种拼凑起来的 Builder。

在 stackoverflow 播客11:

是的。还有一个新产品,如果你不想使用那里的团队系统我们在 Redgate 的朋友有一个产品叫做 SQL 数据生成器[ http://www.red-gate.com/products/sql_data_generator/index.htm]。这是295美元,它只是生成一些真实的测试数据。它可以在城市列中生成实际存在的城市,然后当它生成这些城市时,它会得到正确的州,而不是得到错误的州,或者把州放到德国的城市中,诸如此类的东西,你知道,它会生成非常逼真的数据。我不太确定所有的特征是什么。

这可能不是你想要的,但是它可能是一个很好的起点,而不是创建你自己的。

我似乎在 google 上找不到任何东西,所以我建议解决这个问题,将给定的正则表达式解析为最小的工作单元(w,[ x-x ] ,d 等) ,并编写一些基本的方法来支持这些正则表达式短语。

因此,对于 w,可以有一个返回任意随机字母的方法 getRRandom Letters () ,还可以有一个 getRRandom Letters (char startLetters,char endLetters) ,它给出两个值之间的一个随机字母。

我知道已经有了一个可以接受的答案,但是我一直在使用 RedGate 的数据生成器(克雷格的答案中提到的那个) ,它对于我给出的所有答案都非常有效。它很快,这让我想要使用相同的正则表达式来生成真正的数据,比如这个东西吐出的注册代码。

它需要像下面这样的正则表达式:

[A-Z0-9]{3,3}-[A-Z0-9]{3,3}

它会产生大量独特的代码,比如:

LLK-32U

这是红门搞出来的什么大秘密算法我们都不走运还是我们这些凡人真的能做到的?

它远远不能支持完整的 PCRE regexp,但是我编写了以下 Ruby 方法来获取一个类似 regexp 的字符串并在其上生成一个变体。(适用于基于语言的验证码)

# q = "(How (much|many)|What) is (the (value|result) of)? :num1 :op :num2?"
# values = { :num1=>42, :op=>"plus", :num2=>17 }
# 4.times{ puts q.variation( values ) }
# => What is 42 plus 17?
# => How many is the result of 42 plus 17?
# => What is the result of 42 plus 17?
# => How much is the value of 42 plus 17?
class String
def variation( values={} )
out = self.dup
while out.gsub!( /\(([^())?]+)\)(\?)?/ ){
( $2 && ( rand > 0.5 ) ) ? '' : $1.split( '|' ).random
}; end
out.gsub!( /:(#{values.keys.join('|')})\b/ ){ values[$1.intern] }
out.gsub!( /\s{2,}/, ' ' )
out
end
end


class Array
def random
self[ rand( self.length ) ]
end
end

为此,我已经开始使用我的 自己的库(在 c # 中,但对于 Java 开发人员来说应该很容易理解)。

Rxrdg 最初是为了解决为实际项目创建测试数据的问题。基本思想是利用现有的(正则表达式)验证模式来创建符合这些模式的随机数据。这样就创建了有效的随机数据。

为简单的正则表达式模式编写解析器并不困难。使用抽象语法树生成字符串应该更加容易。

Xeger (Java) 也能做到这一点:

String regex = "[ab]{4,6}c";
Xeger generator = new Xeger(regex);
String result = generator.generate();
assert result.matches(regex);

我在飞机上,刚刚看到的问题: 我写了最简单,但效率低下和不完整的解决方案。我希望它能帮助您开始编写自己的解析器:

public static void main(String[] args) {


String line = "[A-Z0-9]{16}";
String[] tokens = line.split(line);
char[] pattern = new char[100];
int i = 0;
int len = tokens.length;
String sep1 = "[{";
StringTokenizer st = new StringTokenizer(line, sep1);


while (st.hasMoreTokens()) {
String token = st.nextToken();
System.out.println(token);


if (token.contains("]")) {
char[] endStr = null;


if (!token.endsWith("]")) {
String[] subTokens = token.split("]");
token = subTokens[0];


if (!subTokens[1].equalsIgnoreCase("*")) {
endStr = subTokens[1].toCharArray();
}
}


if (token.startsWith("^")) {
String subStr = token.substring(1, token.length() - 1);
char[] subChar = subStr.toCharArray();
Set set = new HashSet<Character>();


for (int p = 0; p < subChar.length; p++) {
set.add(subChar[p]);
}


int asci = 1;


while (true) {
char newChar = (char) (subChar[0] + (asci++));


if (!set.contains(newChar)) {
pattern[i++] = newChar;
break;
}
}
if (endStr != null) {
for (int r = 0; r < endStr.length; r++) {
pattern[i++] = endStr[r];
}
}


} else {
pattern[i++] = token.charAt(0);
}
} else if (token.contains("}")) {
char[] endStr = null;


if (!token.endsWith("}")) {
String[] subTokens = token.split("}");
token = subTokens[0];


if (!subTokens[1].equalsIgnoreCase("*")) {
endStr = subTokens[1].toCharArray();
}
}


int length = Integer.parseInt((new StringTokenizer(token, (",}"))).nextToken());
char element = pattern[i - 1];


for (int j = 0; j < length - 1; j++) {
pattern[i++] = element;
}


if (endStr != null) {
for (int r = 0; r < endStr.length; r++) {
pattern[i++] = endStr[r];
}
}
} else {
char[] temp = token.toCharArray();


for (int q = 0; q < temp.length; q++) {
pattern[i++] = temp[q];
}
}
}


String result = "";


for (int j = 0; j < i; j++) {
result += pattern[j];
}


System.out.print(result);
}

现在帮助原来的海报已经太晚了,但是它可以帮助一个新来的人。通用是一个非常有用的 Java 库,它提供了许多使用正则表达式生成字符串的特性(随机生成,根据索引生成字符串,生成所有字符串...)。

例如:

Generex generex = new Generex("[0-3]([a-c]|[e-g]{1,2})");


// generate the second String in lexicographical order that matches the given Regex.
String secondString = generex.getMatchedString(2);
System.out.println(secondString);// it print '0b'


// Generate all String that matches the given Regex.
List<String> matchedStrs = generex.getAllMatchedStrings();


// Using Generex iterator
Iterator iterator = generex.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
// it prints 0a 0b 0c 0e 0ee 0e 0e 0f 0fe 0f 0f 0g 0ge 0g 0g 1a 1b 1c 1e
// 1ee 1e 1e 1f 1fe 1f 1f 1g 1ge 1g 1g 2a 2b 2c 2e 2ee 2e 2e 2f 2fe 2f 2f 2g
// 2ge 2g 2g 3a 3b 3c 3e 3ee 3e 3e 3f 3fe 3f 3f 3g 3ge 3g 3g 1ee


// Generate random String
String randomStr = generex.random();
System.out.println(randomStr);// a random value from the previous String list

披露

本帖中提到的项目属于用户回答(Mifmif)问题。根据 规矩,这个需要被提出来。

如果想要生成“关键”字符串,可能需要考虑:

EGRET http://elarson.pythonanywhere.com/ 生成覆盖正则表达式的“邪恶”字符串

穆特雷克斯 http://cs.unibg.it/MUTREX/ 通过正则表达式变异生成故障检测字符串

两者都是学术工具(我是后者的作者之一) ,工作相当不错。

这个问题非常古老,但是我在自己的搜索中偶然发现了它,所以我将包含一些链接,以供其他人可能在其他语言中搜索相同的功能。

这个问题真的很老了,尽管这个问题对我来说是实际存在的。 我试过 Xeger通用,但它们似乎不符合我的要求。 它们实际上不能处理某些正则表达式模式(如 a{60000})或其他模式(如 (A|B|C|D|E|F)) ,它们只是不能产生所有可能的值。由于我没有找到任何其他合适的解决方案-我已经创建了自己的库。

Https://github.com/curious-odd-man/rgxgen

此库可用于生成匹配字符串和非匹配字符串。

Maven 中心也有藏物。

用法例子:

RgxGen rgxGen = new RgxGen(aRegex);                     // Create generator
String s = rgxGen.generate();                           // Generate new random value