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

StackOverflow https://stackoverflow.com/questions/22115

  •  09-06-2019
  •  | 
  •  

Вопрос

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

Спасибо

Это было полезно?

Решение

Редактировать:

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

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

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

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

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

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

Другие советы

Ксегер (Ява) тоже способен это сделать:

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

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

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

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

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

Спольский:Ага.Также есть новый продукт: если вы не хотите использовать Team System, у наших друзей из 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

Это какой-то большой секретный алгоритм, который разгадал 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, который берет строку, подобную регулярному выражению, и создает ее вариацию.(Для языковой 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

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

Если вы хотите генерировать «критические» строки, вы можете рассмотреть возможность:

ЦАПЛЯ http://elarson.pythonanywhere.com/который генерирует «злые» строки, охватывающие ваши регулярные выражения

МУТРЕКС http://cs.unibg.it/mutrex/который генерирует строки обнаружения ошибок путем мутации регулярного выражения

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top