Використання Regex для створення рядків, а не їх узгодження


108

Я пишу утиліту Java, яка допомагає мені генерувати безліч даних для тестування продуктивності. Було б дуже здорово мати можливість вказати регулярний вираз для Strings, щоб мій генератор виплюнув речі, які відповідають цьому. Чи є щось там вже запечене, що я можу використати для цього? Або є бібліотека, яка переносить мене більшу частину шляху?

Дякую


1
Ось корисна бібліотека Java , які надають безліч можливостей для використання регулярних виразів для створення String (випадкова генерація, генерувати рядки на основі це індекс, генерувати всі рядки ..) перевірити його тут
Mifmif

Іншою альтернативою може бути така
Владислав Варславанс

Відповіді:


40

Редагувати: Як згадувалося в коментарях, у Google Code доступна бібліотека для досягнення цього: https://code.google.com/archive/p/xeger/

Дивіться також https://github.com/mifmif/Generex, як запропонував Mifmif

Оригінальне повідомлення:

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

Якщо ви подивитесь на вихідний код класу java.util.regex.Pattern, ви побачите, що він використовує внутрішнє представлення екземплярів Node. Кожен з різних компонентів шаблону має власну реалізацію підкласу Node. Ці Вузли організовані в дерево.

Виробляючи відвідувача, який перетинає це дерево, ви повинні мати можливість викликати метод перевантаженого генератора або якийсь будівельник, який щось зближує.


2
Я не впевнений, що Ксегер - це добре. Він не може обробляти класи символів. Він не в змозі розпізнати простий [\w]. Погляд на останній рядок їх вікі говорить нам про це.
Джон Ред

2
Зауважте також, що вони залежать від dk.brics.automatonтого, будьте готові до додання сторонніх залежностей від пом. Більшість людей не проти цього, але мені б хотілося, щоб було щось більш компактне.
Шрідхар Сарнобат

Існує альтернатива для xeger і generex. У ньому відсутні всі ці недоліки і не застаріла. Прокрутіть, будь ласка, вниз до моєї відповіді.
Владислав Варславанс

"По-перше, з досить складним регулярним виразком я вважаю, що це може бути неможливим". - це не зовсім вірно : будь-який регулярний вираз, який переходить проти чогось, також може генерувати дійсний вклад. Пояснення: регулярні вирази - це тип 3 в Ієрархії Хомських, тобто вони можуть бути виражені як FSM. Під час переходу через FSM кожен край інтерпретується як правило для наступного символу, таким чином, FSM може бути використаний для розбору або генерації послідовностей. Якщо FSM має шлях до терміналу, може бути визначена дійсна послідовність. Отже, "неможливо" лише якщо немає шляху до терміналу (що було б марним регулярним виразом).
Лоуренс Вагерфілд

22

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


11
Схоже, Generex - це ваш власний проект. Чи проти зауважити у своєму дописі, що це ваш власний проект, відповідно до правил тут ?
Брайан МакКучон


5

Я вийшов з цього корінця, щоб запустити свою власну бібліотеку (In c #, але це має бути зрозумілим для розробника Java).

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

Не так складно написати парсер для простих виразних шаблонів. Використання абстрактного синтаксичного дерева для створення рядків повинно бути ще простішим.


посилання більше не вказує на сховище. Я б пішов з openhub.net/p/rxrdg . Однак рішення не створюється?
Веверке

4

На підкасті 11 stackoverflow:

Спольський: Так. Також є новий продукт, якщо ви не хочете використовувати командну систему там, у наших друзів у 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), який дає вам випадкову літеру між двома значеннями.


4

Це питання справді старе, хоча проблема була актуальною для мене. Я спробував 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

3

Я знаю, що вже прийнята відповідь, але я використовував Генератор даних RedGate (той, що згадується у відповіді Крейга), і він працює ДУЖЕ добре для всього, що я на нього кинув. Це швидко, і це дозволяє мені використовувати той же регулярний вираз для створення реальних даних для речей, таких як реєстраційні коди, які ця річ випльовує.

Він займає регулярний вираз, як:

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

і він генерує багато унікальних кодів, таких як:

LLK-32U

Це якийсь великий секретний алгоритм, який з'ясував RedGate, і нам всі не пощастило, чи це щось, що нас насправді можуть зробити просто смертні?


3

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

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

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

2

Вам доведеться написати власний парсер, як це робив автор String :: Random (Perl). Насправді він ніде в цьому модулі не використовує регулярні вирази, це просто те, до чого звикли пердельні кодери.

З іншого боку, можливо, ви можете поглянути на джерело , щоб отримати деякі вказівки.


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


1

Це далеко не підтримка повного PCRE regexp, але я написав наступний метод 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

1

Це запитання дуже старе, але я натрапив на нього під час власного пошуку, тому я включу пару посилань для інших, які, можливо, шукають ту саму функціональність іншими мовами.


0

Якщо ви хочете генерувати "критичні" рядки, ви можете врахувати:

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

MUTREX http://cs.unibg.it/mutrex/, який генерує рядки з виявленням несправностей шляхом мутації згенерації

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.