题
我正在编写一个 Java 实用程序,它可以帮助我生成大量数据以进行性能测试。这将是 真的 能够为字符串指定正则表达式真是太酷了,这样我的生成器就可以输出与此匹配的内容。有没有已经烤好的东西可以用来做这个?或者有没有一个图书馆可以让我大部分时间到达那里?
谢谢
解决方案
编辑:
正如评论中提到的,Google Code 中有一个库可以实现此目的:http://code.google.com/p/xeger
也可以看看 https://github.com/mifmif/Generex 正如建议的 米夫米夫
原始信息:
首先,对于足够复杂的正则表达式,我相信这是不可能的。但您应该能够为简单的正则表达式组合一些东西。
如果您查看 java.util.regex.Pattern 类的源代码,您会发现它使用 Node 实例的内部表示。每个不同的模式组件都有自己的 Node 子类实现。这些节点被组织成一棵树。
通过生成遍历该树的访问者,您应该能够调用重载的生成器方法或某种将某些内容拼凑在一起的构建器。
其他提示
赛格 (Java) 也有能力做到这一点:
String regex = "[ab]{4,6}c";
Xeger generator = new Xeger(regex);
String result = generator.generate();
assert result.matches(regex);
虽然对原发帖者有帮助为时已晚,但它可以帮助新人。 杰纳雷克斯 是一个有用的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
我已经连根拔起 自己的 库(在 C# 中,但对于 Java 开发人员来说应该很容易理解)。
Rxrdg 最初是为了解决为现实项目创建测试数据的问题。基本思想是利用现有(正则表达式)验证模式来创建符合此类模式的随机数据。这样就创建了有效的随机数据。
为简单的正则表达式模式编写解析器并不困难。使用抽象语法树生成字符串应该更容易。
在 stackoverflow 播客 11 上:
斯波尔斯基:是的。还有一个新产品,如果你不想使用团队系统,我们 Redgate 的朋友有一个名为 SQL Data Generator 的产品 [http://www.red-gate.com/products/sql_data_generator/index.htm]. 。它的价格是 295 美元,它只是生成一些真实的测试数据。它会做一些事情,比如在城市列中实际生成实际存在的真实城市,然后当它生成这些城市时,它会得到正确的状态,而不是得到错误的状态,或者将状态放入德国城市之类的东西......你知道,它会生成看起来非常真实的数据。我不太确定所有功能是什么。
这可能不是您正在寻找的,但它可能是一个很好的起点,而不是创建您自己的。
我似乎在谷歌中找不到任何东西,所以我建议通过将给定的正则表达式解析为最小的工作单元(\w、[x-x]、\d 等)并编写一些基本方法来支持来解决问题那些正则表达式短语。
因此,对于 \w,您将有一个 getRandomLetter() 方法,它返回任何随机字母,并且您还将有 getRandomLetter(char startLetter, char endLetter) ,它为您提供两个值之间的随机字母。
我知道已经有一个被接受的答案,但我一直在使用 RedGate 的数据生成器 (克雷格的回答中提到的那个)它对于我扔给它的所有东西都非常有效。它很快,这让我想使用相同的正则表达式来生成真实数据,例如这个东西吐出的注册码。
它需要一个正则表达式,例如:
[A-Z0-9]{3,3}-[A-Z0-9]{3,3}
它会生成大量独特的代码,例如:
LLK-32U
这是 RedGate 发现的一些大秘密算法,而我们都运气不好,还是我们凡人实际上可以做到的?
我在飞机上,刚刚看到这个问题:我写了最简单但效率低下且不完整的解决方案。我希望它可以帮助您开始编写自己的解析器:
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);
}
您必须编写自己的解析器,就像 String::Random (Perl) 的作者所做的那样。事实上,他在该模块的任何地方都没有使用正则表达式,这只是 perl 编码人员所习惯的。
另一方面,也许你可以看看 来源, ,以获得一些指示。
编辑:该死,布莱尔比我领先 15 秒。
它远未支持完整的 PCRE 正则表达式,但我编写了以下 Ruby 方法来获取类似正则表达式的字符串并生成其变体。(对于基于语言的验证码。)
# 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
这个问题很老了,但我在自己的搜索中偶然发现了它,因此我将为可能正在其他语言中搜索相同功能的其他人提供几个链接。
- 这里有一个 Node.js 库: https://github.com/fent/randexp.js
- 这里有一个 PHP 库: https://github.com/icomefromthenet/ReverseRegex
- PHP faker 包包含一个“regexify”方法来完成此操作: https://packagist.org/packages/fzaninotto/faker
如果您想生成“关键”字符串,您可能需要考虑:
白鹭 http://elarson.pythonanywhere.com/生成覆盖正则表达式的“邪恶”字符串
互通 http://cs.unibg.it/mutrex/通过正则表达式突变生成故障检测字符串
两者都是学术工具(我是后者的作者之一)并且工作得相当好。