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

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

Спасибо

Вот полезный библиотека Java, который предоставляет множество функций для использования регулярного выражения для генерации String (случайная генерация, генерация String на основе его индекса, генерация всей String ..), проверьте здесь

Mifmif 09.07.2014 20:57

Другой альтернативой может быть это

Vladislav Varslavans 15.11.2019 22:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
117
2
85 195
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

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

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


Обновлено: Черт, Блэр опередила меня на 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/

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

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

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

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

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

Я не уверен, что Xeger настолько хорош. Он не может обрабатывать классы символов. Он не может распознать простой [\w]. Об этом говорит последняя строка их вики.

John Red 13.02.2017 15:38

Также обратите внимание, что они зависят от dk.brics.automaton, поэтому будьте готовы добавить сторонние зависимости pom. Большинство людей не возражают против этого, но я бы хотел, чтобы было что-то более компактное.

Sridhar Sarnobat 24.07.2018 00:32

Есть альтернатива xeger и generex. Он лишен всех этих недостатков и не устарел. Прокрутите вниз до моего ответа.

Vladislav Varslavans 24.04.2020 18:17

«Во-первых, я считаю, что с достаточно сложным регулярным выражением это может быть невозможно». - это не совсем верно: любое регулярное выражение, которое проходит через что нибудь, также может генерировать допустимый ввод. Объяснение: регулярные выражения относятся к типу 3 в иерархии Хомского, что означает, что они могут быть выражены как конечные автоматы. При пошаговом прохождении конечного автомата каждое ребро интерпретируется как правило для следующего символа, поэтому конечный автомат можно использовать для последовательностей разбирать или генерировать. Если у конечного автомата есть путь к терминалу, можно определить допустимую последовательность. Таким образом, это «невозможно», только если нет пути к терминалу (что было бы бесполезным регулярным выражением).

Lawrence Wagerfield 07.06.2020 17:49

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

Spolsky: Yep. There's a new product also, if you don't want to use the Team System there our friends at Redgate have a product called SQL Data Generator [http://www.red-gate.com/products/sql_data_generator/index.htm]. It's 5, and it just generates some realistic test data. And it does things like actually generate real cities in the city column that actually exist, and then when it generates those it'll get the state right, instead of getting the state wrong, or putting states into German cities and stuff like... you know, it generates pretty realistic looking data. I'm not really sure what all the features are.

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

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

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

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

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

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

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

LLK-32U

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

Он далек от поддержки полного регулярного выражения 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!( /\(([^())?]+)\)(\?)?/ ){
      (  && ( 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

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

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

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

ссылка больше не указывает на репозиторий. Я бы пошел с openhub.net/p/rxrdg. Однако решение не построить?

Veverke 22.07.2015 10:51

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

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

Ксегер прекрасно работает. НО убедитесь, что у вас есть автоматная банка на пути к классу или в вашем pom / gradle

Delicia Brummitt 07.09.2016 22:31

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

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

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

Maarten Bodewes 25.11.2012 19:39

StringTokenizer - это устаревший класс, который сохранен по соображениям совместимости, хотя его использование в новом коде не рекомендуется. Рекомендуется, чтобы любой, кто ищет эту функциональность, использовал вместо этого метод разделения String или пакет java.util.regex.

Rohit 02.03.2014 06:57

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

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

Brian McCutchon 03.06.2016 00:22

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

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

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

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

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

Вопрос действительно старый, хотя для меня проблема была актуальна. Я пробовал Xeger и Generex, и, похоже, они не соответствуют моим требованиям. Они фактически не могут обрабатывать некоторые шаблоны регулярных выражений (например, 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

Я попробовал RxGen, и он работал намного лучше, чем Xeger и Generex

spacether 08.11.2020 23:35

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