Использование Regex для генерации строк вместо их соответствия

Я пишу утилиту Java, которая помогает мне генерировать множество данных для тестирования производительности. Было бы здорово иметь возможность задавать регулярное выражение для строк, чтобы мой генератор выплевывал вещи, которые соответствуют этому. Есть ли что-то там уже испеченное, что я могу использовать для этого? Или есть библиотека, которая мне больше всего нравится?

Спасибо

Ответ 1

Изменить:

Как уже упоминалось в комментариях, в Google Code есть библиотека, позволяющая добиться этого: http://code.google.com/p/xeger

Смотрите также https://github.com/mifmif/Generex как предложено Mifmif

Исходное сообщение:

Во-первых, с достаточно сложным регулярным выражением, я считаю, что это может быть невозможно. Но вы должны быть в состоянии собрать что-то вместе для простых регулярных выражений.

Если вы посмотрите на исходный код класса java.util.regex.Pattern, вы увидите, что он использует внутреннее представление экземпляров Node. Каждый из различных компонентов шаблона имеет свою собственную реализацию подкласса Node. Эти узлы организованы в дерево.

Создав посетителя, который пересекает это дерево, вы сможете вызывать перегруженный генераторный метод или какой-то тип Строителя, который что-то объединяет.

Ответ 2

Xeger (Java) также может сделать это:

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

Ответ 3

Уже слишком поздно, чтобы помочь оригинальному постеру, но это может помочь новичку. 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

Раскрытие

Проект, упомянутый в этом посте, принадлежит пользователю, отвечающему (Mifmif) на вопрос. В соответствии с правилами, это необходимо поднять.

Ответ 4

В Visual Studio Team System есть что-то вроде этого. Проверьте это

Не очень помогает Java, но извините.

Ответ 5

Я ушел из корня отката моей собственной библиотеки для этого (в С#, но должен быть понятен для Java-разработчика).

Rxrdg началось как решение проблемы создания тестовых данных для проекта реальной жизни. Основная идея состоит в том, чтобы использовать существующие шаблоны проверки (регулярного выражения) для создания случайных данных, которые соответствуют таким шаблонам. Таким образом создаются действительные случайные данные.

Не так сложно написать парсер для простых шаблонов регулярных выражений. Использование абстрактного синтаксического дерева для генерации строк должно быть еще проще.

Ответ 6

В подкасте stackoverflow 11:

Спольский: Да. Там также есть новый продукт, если вы не хотите использовать Team Team там, у наших друзей в Redgate есть продукт под названием SQL Data Generator [http://www.red-gate.com/products/sql_data_generator/index.htm]. Это $295, и он просто генерирует некоторые реалистичные тестовые данные. И он делает такие вещи, как фактическое создание реальных городов в столбце города, которые на самом деле существуют, а затем, когда он генерирует их, он получит право штата, вместо того, чтобы заставить государство ошибочно или поставить государства в немецкие города и прочее, как... вы знаете, он генерирует довольно реалистичные данные. Я не совсем уверен, что все функции.

Это, вероятно, не то, что вы ищете, но это может быть хорошей отправной точкой, а не создавать свои собственные.

Я не могу найти что-либо в google, поэтому я бы предложил решить эту проблему, проанализировав данное регулярное выражение на наименьшие единицы работы (\ w, [xx],\d и т.д.) и написав некоторые основные методы поддержки этих выражений.

Итак, для \w у вас будет метод getRandomLetter(), который возвращает любую случайную букву, и у вас также будет getRandomLetter (char startLetter, char endLetter), который дает вам случайную букву между двумя значениями.

Ответ 7

Я знаю, что уже есть принятый ответ, но я использовал RedGate Data Generator (тот, что упоминается в ответе Крейга), и он работает ДЕЙСТВИТЕЛЬНО хорошо для всего, что я выбрал. Это быстро, и это оставляет мне желание использовать одно и то же регулярное выражение для генерации реальных данных для таких вещей, как регистрационные коды, которые эта штука выплевывает.

Требуется регулярное выражение:

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

и генерирует множество уникальных кодов, таких как:

LLK-32U

Это какой-то большой секретный алгоритм, который RedGate выяснил, и нам все не повезло или это то, что мы могли бы сделать, просто смертные?

Ответ 8

Я нахожусь в полете и только что увидел вопрос: я написал простейшее, но неэффективное и неполное решение. Надеюсь, это поможет вам начать писать собственный парсер:

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);
}

Ответ 9

Вам придется написать собственный парсер, как это сделал автор String:: Random (Perl). Фактически, он не использует регулярные выражения нигде в этом модуле, это просто то, что используют perl-кодировщики.

С другой стороны, возможно, вы можете посмотреть источник, чтобы получить некоторые указатели.


EDIT: Черт, Блэр избил меня до удара на 15 секунд.

Ответ 10

Это далеко не поддержка полного регулярного выражения PCRE, но я написал следующий метод Ruby, чтобы взять строку, похожую на regexp, и создать вариацию на ней. (Для языкового CAPTCHA.)

# 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

Ответ 11

Добавление другого инструмента, который я не видел здесь, который работал у меня. (Я попробовал решение С# от Goran - Rxrdg - но со мной решение не строится).

Ссылка ниже довольно проста и легка, и я сделал для меня работу: http://uttool.com/text/regexstr/default.aspx

Ответ 12

Этот вопрос очень старый, но я наткнулся на него в своем собственном поиске, поэтому я включу пару ссылок для других, которые могут искать ту же функциональность на других языках.

Ответ 13

Если вы хотите генерировать "критические" строки, вы можете подумать:

EGRET http://elarson.pythonanywhere.com/ который генерирует "злые" строки, покрывающие ваши регулярные выражения

MUTREX http://cs.unibg.it/mutrex/ который генерирует строки обнаружения ошибок с помощью мутации regex

Оба являются академическими инструментами (я один из авторов последних) и работают достаточно хорошо.