Блог пользователя PanZverski

Автор PanZverski, 13 лет назад, По-русски

Привет.
Наверняка, кто-нибудь тут сталкивался с задачей проверки строки на соответсвие шаблона заданного Wildcard, на манер имен файлов (c:\dir\*\????la*.txt). То есть: * - любое количество символов, ? - один любой символ.
Первое, что мне пришло в голову - это жадный алгоритм решения.

Разделяем всю строку на группы между которыми стоят *. Ищем каждую группу, как можно ближе к началу строки.

Ситуации типа: *??*?*  - обрабатываем как одну *, но пропускаем 3 символа в строке.
При поиске последней группы требуем чтобы она находилась в конце строки.

Вот код: http://pastebin.com/ALQa7WmE

И вроде бы, я не могу найти контр-примера. Но в интернете везде лежит либо, некорректный жадный алгоритм, не обрабатывающий ситуации a*? или же динамика.  Может кто-нибудь привести контр-пример?

  • Проголосовать: нравится
  • +1
  • Проголосовать: не нравится

»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Такая задача была на первом этапе Московской олимпиады школьников, написал жадник - ОК (задача D http://olympiads.ru/mosolymp/2011-12/tour1/statements.pdf).

  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Спасибо. Это придает уверенности, а то меня часто глючит)
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ах да, там в условии только одна звездочка. Думаю, что мое решение не очень сложно будет переделать на общий случай.
      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Ну мое решение (http://pastebin.com/ALQa7WmE), вроде, работает. Я пока не нашел контр-примера. Но не факт, что оно верно)
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    http://paste.pocoo.org/show/532776/
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
А Вы хотите уметь обрабатывать абсолютно любые ситуации со звёздочками, т.е. вроде *a*i* (чтобы совпало с именем maksitime, скажем), или только с одной звёздочкой?
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Да, любые. Типа таких: "xxayyxx", "xx*?*yy*?" (должно совпасть)...
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Если это не для спортивной задачи/интереса, то может через регэкспы:

      pattern = pattern.replaceAll("\\?", ".").replaceAll("\\*", ".*");
      for (String filename : directory) {
      if (filename.matches(pattern)) {
          process(filename);
      } // if
      } // for
      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Да, я вначале так и делал. Там только еще проэскейпить паттерн надо, чтобы  другие управляющие симполы не попались.
        Но, сейчас у меня нет возможности линковать boost::regex, а включать другую библиотеку ради такой мелочи не хочется.
        Кроме того, при использовании регулярных выражений,  в зависимоти от типа автомата, ситуации типа *?* могут привести к экспоненциальному времени поиска.
        • »
          »
          »
          »
          »
          13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          (хм, аналогичная ситуация - я потом тоже переделал, именно для скорости - только на динамику, поскольку дальше хотел научиться нечётко сравнивать... правда в конце всё равно пришлось сравнение по кускам сделать)
          • »
            »
            »
            »
            »
            »
            13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Дык да, меня тоже квадратная динамика в текущей ситуации вполне устраивает (длины строк и шаблонов не большие).
            Просто уже интересно, верный у меня жадный алгоритм получился или нет. Плюс, он будет работать без дополнительной памяти при любых размерах строк, и время, в отличие от динамики, может быть значительно меньше квадрата в большинстве случаев.
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Так а что за жадный алгоритм то? К чему контр-пример искать?
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Разделяем всю строку на группы, между которыми стоят *.
    Ситуации типа: *??*?*  - обрабатываем как одну *, но пропускам 3 символа в строке.
    Ищем каждую группу, как можно ближе к началу строки. При поиске последней группы требуем чтобы она находилась в конце строки.
    Вот код:
    http://pastebin.com/ALQa7WmE
»
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Если количество звёздочек и вопросиков не очень большое, то можно сходу написать маленькую рекурсию:

Код на Питоне в первой правке

  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну это понятно, можно и динамику сделать. Сейчас меня больше всего интересует, работает ли во всех случаях жадный алгоритм, который я привел. Меня в нем смущает подпорка для последней группы.
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Да не, это не "подпорка"... Это просто следствие того что нам надо с обоими концами совпасть... Вроде уж пора алгоритм доказать.

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

      Т.е. либо он совпал со строкой, с которой не должен -это значит, нашёл в ней лишнюю группу, либо одна из групп ошибочно совпала с чем-то, с чем не должна была (что видимо противоречит предположению о корректной реализации).

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

      Надо формализовать это дело, получится красивый и наукообразный пост. ;-)