Подтвердить что ты не робот

Учитывая строку, сгенерируйте регулярное выражение, которое может анализировать * похожие * строки

Например, учитывая строку "2009/11/12", я хочу получить регулярное выражение ( "\ d {2}/d {2}/d {4}" ), поэтому я смогу сопоставить "2001/01/02" тоже.

Есть ли что-то такое? Что-то похожее? Любая идея "как это сделать?"

4b9b3361

Ответ 1

Существует text2re, бесплатный веб-генератор "regex by example".

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


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

Например, строка "2009/11/12" будет распознана как шаблон yyyymmdd, что полезно. Инструмент преобразует его в этого монстра с 125 символами:

((?:(?:[1]{1}\d{1}\d{1}\d{1})|(?:[2]{1}\d{3}))[-:\/.](?:[0]?[1-9]|[1][012])[-:\/.](?:(?:[0-2]?\d{1})|(?:[3][01]{1})))(?![\d])

Ручной эквивалент займет всего две пятых этого (50 символов):

([12]\d{3})[-:/.](0?\d|1[0-2])[-:/.]([0-2]?\d|3[01])\b

Ответ 2

Невозможно написать общее решение для вашей проблемы. Проблема в том, что любой генератор, вероятно, не знал бы, что вы хотите проверить, например. следует ли допускать "2312/45/67"? Что относительно "2009.11.12"?

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

Ответ 3

Я пробовал очень наивный подход:

class RegexpGenerator {

    public static Pattern generateRegexp(String prototype) {
        return Pattern.compile(generateRegexpFrom(prototype));
    }

    private static String generateRegexpFrom(String prototype) {
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < prototype.length(); i++) {
            char c = prototype.charAt(i);

            if (Character.isDigit(c)) {
                stringBuilder.append("\\d");
            } else if (Character.isLetter(c)) {
                stringBuilder.append("\\w");
            } else { // falltrought: literal
                stringBuilder.append(c);
            }
        }

        return stringBuilder.toString();
    }

    private static void test(String prototype) {
        Pattern pattern = generateRegexp(prototype);
        System.out.println(String.format("%s -> %s", prototype, pattern));

        if (!pattern.matcher(prototype).matches()) {
            throw new AssertionError();
        }
    }

    public static void main(String[] args) {
        String[] prototypes = {
            "2009/11/12",
            "I'm a test",
            "me too!!!",
            "124.323.232.112",
            "ISBN 332212"
        };

        for (String prototype : prototypes) {
            test(prototype);
        }
    }
}

выход:

2009/11/12 → \d\d\d\d/\ d\d/\ d\d
Я тест → \w '\ w\w\w\w\w\w
я тоже!!! → \w\w\w\w\w!!!
124.323.232.112 → \d\d\d.\D\d\d.\D\d\d.\D\d\d
ISBN 332212 → \w\w\w\w\d\d\d\d\d\d

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

Ответ 4

Извините, но то, что вы все называете невозможным, явно достижимо. Он не сможет дать результаты для ВСЕХ примеров и, возможно, не лучших результатов, но вы можете дать ему различные подсказки, и это облегчит жизнь. Приведем несколько примеров.

Также полезен читаемый вывод, переводящий результат. Что-то вроде:

  • "Искать: слово, начинающееся с нечисловой буквы и заканчивающееся строкой:" ing ".
  • или: Искать: текст, в котором есть bbb, а затем где-то zzz
  • или: * Искать: шаблон, который выглядит так "aa/bbbb/cccc", где "/" является разделителем, "aa" - две цифры, "bbbb" - это слово любой длины, а "cccc" - четыре цифры между 1900 и 2020 годами.

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

Вот несколько примеров, которые можно выполнить:

class Hint: 
  Properties: HintType, HintString
  enum HintType { Separator, ParamDescription, NumberOfParameters }
  enum SampleType { FreeText, DateOrTime, Formatted, ... }
  public string RegexBySamples( List<T> samples, 
         List<SampleType> sampleTypes, 
         List<Hint> hints, 
         out string GeneralRegExp, out string description, 
         out string generalDescription)...

regex = RegExpBySamples( {"11/November/1999", "2/January/2003"}, 
                     SampleType.DateOrTime, 
                     new HintList( HintType.NumberOfParameters, 3 ));

regex = RegExpBySamples( "123-aaaaJ-1444", 
                         SampleType.Format, HintType.Seperator, "-" );

Графический интерфейс, в котором вы помечаете образец текста или вводите его, добавление в регулярное выражение также возможно. Сначала вы отмечаете дату ( "образец" ) и выбираете, был ли этот текст уже отформатирован или вы строите формат, а также тип формата: свободный текст, форматированный текст, дата, идентификатор GUID или выберите... из существующих форматов (которые вы можете хранить в библиотеке).

Позволяет создать спецификацию для этого и сделать его открытым исходным кодом... Кто-нибудь хочет присоединиться?

Ответ 5

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

Ответ 6

Я не уверен, возможно ли это, по крайней мере, не без множества строк примеров и некоторого алгоритма обучения.

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

Ответ 7

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

Ответ 8

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

Ответ 9

Я не помню названия, но если моя теория вычислительных ячеек мне в правильном смысле верна, это невозможно:)

Ответ 10

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

Спасибо всем, кто ответил (парень с исключенным (. *) - шутки замечательные, но этот был sssssssssoooo lame:))

Ответ 11

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