Использование регулярных выражений для создания строк, а не для их сопоставления
Я пишу утилиту Java, которая помогает мне генерировать нагрузки данных для тестирования производительности. Это было бы действительно здорово, чтобы иметь возможность указать регулярное выражение для строк, так что мой генератор выдает вещи, которые соответствуют этому. Есть ли что-то там уже испеченное, что я могу использовать для этого? Или есть библиотека, которая доставляет меня большую часть пути туда?
спасибо
11 ответов:
Edit:
Как уже упоминалось в комментариях, есть библиотека, доступная в Google Code, чтобы достичь этого: http://code.google.com/p/xeger
Смотрите также https://github.com/mifmif/Generex как предложил Mifmif
исходное сообщение:
во-первых, с достаточно сложным регулярным выражением, я считаю, что это может быть невозможно. Но вы должны быть в состоянии положить что-то вместе простые регулярные выражения.
Если вы посмотрите на исходный код класса java.утиль.регулярное выражение.Шаблон, вы увидите, что он использует внутреннее представление экземпляров узлов. Каждый из различных компонентов шаблона имеет свою собственную реализацию подкласса узла. Эти узлы организованы в дерево.
создавая посетителя, который пересекает это дерево, вы должны быть в состоянии вызвать перегруженный метод генератора или какой-то строитель, который что-то объединяет.
Xeger (Java) способен делать это так же:
String regex = "[ab]{4,6}c"; Xeger generator = new Xeger(regex); String result = generator.generate(); assert result.matches(regex);
слишком поздно, чтобы помочь оригинальному плакату, но это может помочь новичку. Generex это полезная библиотека 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, и он просто генерирует некоторые реалистичные тестовые данные. И он делает такие вещи, как фактически генерирует реальные города в столбце "город", которые действительно существуют, а затем, когда он генерирует их, он будет получить государство правильно, вместо того, чтобы получить государство неправильно, или положить государства в немецкие города и тому подобное... вы знаете, он генерирует довольно реалистичные данные. Я не совсем уверен, что все функции.
Это, вероятно, не то, что вы ищете, но это может быть хорошей отправной точкой, а не создавать свой собственный.
Я не могу найти ничего в google, поэтому я бы предложил решить проблему, проанализировав данное регулярное выражение в наименьшие единицы работы (\w, [x-x], \d и т. д.) и написание некоторых основных методов для поддержки этих фраз регулярных выражений.
таким образом, для \w у вас будет метод getRandomLetter (), который возвращает любую случайную букву, и у вас также будет getRandomLetter(char startLetter, char endLetter), который дает вам случайную букву между двумя значениями.
Я знаю, что уже есть принятый ответ, но я использую генератор данных RedGate (тот, который упоминается в ответе Крейга), и он работает очень хорошо для всего, что я бросил на него. Это быстро, и это оставляет мне желание использовать одно и то же регулярное выражение для генерации реальных данных для таких вещей, как регистрационные коды, которые эта вещь выплевывает.
Он принимает регулярное выражение как:
[A-Z0-9]{3,3}-[A-Z0-9]{3,3}и он генерирует тонны уникальных кодов например:
LLK-32U
Я нахожусь в полете и просто увидел вопрос: я написал Самое простое, но неэффективное и неполное решение. Я надеюсь, это может помочь вам начать писать свой собственный парсер:
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-кодеры.
с другой стороны, может быть, вы можете взглянуть на источник, чтобы получить некоторые указатели.
EDIT: блин, Блэр опередил меня на 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!( /\(([^())?]+)\)(\?)?/ ){ ( && ( rand > 0.5 ) ) ? '' : .split( '|' ).random }; end out.gsub!( /:(#{values.keys.join('|')})\b/ ){ values[.intern] } out.gsub!( /\s{2,}/, ' ' ) out end end class Array def random self[ rand( self.length ) ] end end
Если вы хотите создать "критические" строки, вы можете рассмотреть:
цапля http://elarson.pythonanywhere.com/ это генерирует" злые " строки, покрывающие ваши регулярные выражения
MUTREX http://cs.unibg.it/mutrex/ это генерирует строки обнаружения неисправностей путем мутации регулярных выражений
оба являются академическими инструментами (я один из авторов последнего) и работают достаточно хорошо.
этот вопрос очень старый, но я наткнулся на него в своем собственном поиске, поэтому я включу пару ссылок для других, которые могут искать ту же функциональность на других языках.
- есть узел.библиотека js здесь:https://github.com/fent/randexp.js
- здесь есть библиотека PHP:https://github.com/icomefromthenet/ReverseRegex
- пакет PHP faker включает в себя метод "regexify", который выполняет это: https://packagist.org/packages/fzaninotto/faker
Comments