Получив строку, сгенерируйте регулярное выражение, которое может анализировать * похожие * строки - PullRequest
25 голосов
/ 22 апреля 2009

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

Есть ли что-то, что делает это? Что-то похожее? Есть идеи, как это сделать?

Ответы [ 11 ]

25 голосов
/ 22 апреля 2009

Существует 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
11 голосов
/ 22 апреля 2009

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

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

4 голосов
/ 21 июля 2009

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

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

  • "Поиск: слово, начинающееся с нецифровой буквы и заканчивающееся строкой:" 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, "-" );

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

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

3 голосов
/ 22 апреля 2009

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

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

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

1 голос
/ 21 июля 2009

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

1 голос
/ 22 апреля 2009

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

1 голос
/ 22 апреля 2009

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

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

1 голос
/ 22 апреля 2009

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

0 голосов
/ 17 июня 2011

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

0 голосов
/ 27 апреля 2009

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

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

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