2015-07-24 7 views
8

Rebol2 имеет/уточняющий на функции FIND, которая может сделать поиск подстановочного:У кого-нибудь есть эффективная функция R3, которая имитирует поведение find/any в R2?

>> find/any "here is a string" "s?r" 
== "string" 

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

Каков наиболее эффективный способ сделать это в Rebol3? (Я угадал parse решения какого-то.)

+0

Относительно эффективности и PARSE, [«Какой самый быстрый/наиболее эффективный способ подсчета строк в Rebol] (http://stackoverflow.com/questions/14765993/whats-the-fastest-most-efficient-way- to-count-lines-in-rebol) может дать некоторые общие сведения. – HostileFork

+0

Я думаю, у вас уже есть решение. Вы можете ответить на свои вопросы, и другие пользователи могут проголосовать за него. – sqlab

+0

Для справки: подстановочные знаки не включены в словарное определение FIND для [Rebol 3] (http://www.rebol.com/r3/docs/functions/find.html) или [Rebol 2] (http://www.rebol.com/docs/words/ wfind.html), а также в [Основное руководство пользователя] (http://www.rebol.com/docs/core23/rebolcore-6.html#section-7.8). – rgchris

ответ

3

Вот удар при работе с «*» случая:

like: funct [ 
    series [series!] 
    search [series!] 
][ 
    rule: copy [] 
    remove-each s b: parse/all search "*" [empty? s] 
    foreach s b [ 
     append rule reduce ['to s] 
    ] 
    append rule [to end] 
    all [ 
     parse series rule 
     find series first b 
    ] 
] 

используется следующим образом:

>> like "abcde" "b*d" 
== "bcde" 
2

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

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

Вы ищете шаблоны в строках ... так что если вы ограничены использованием строки, чтобы указать этот шаблон, вы попадаете в «мета» проблемы. Предположим, я хочу извлечь слово *Rebol* или ?Red?, теперь должно быть ускользание, и все снова становится уродливым. Вернитесь в RegEx. : -/

Итак, что вы может на самом деле хотите не STRING! узор как s?r, но БЛОК! рисунок как ["s" ? "r"]. Это позволило бы построить такие конструкции, как ["?" ? "?"] или [{?} ? {?}]. Это лучше, чем перефразировать хакерство строк, которое использует каждый другой язык.

И это то, что делает PARSE, хотя и в слегка менее декларативном виде. Он также использует слова вместо символов, как любит Rebol. [{?} skip {?}] является правилом совпадения, где skip - это инструкция, которая перемещает позицию синтаксического анализа за любой элемент цикла анализа между вопросительными знаками. Он также мог бы сделать это, если бы он разбирал блок как входной сигнал и соответствовал бы [{?} 12-Dec-2012 {?}].

Я не знаю полностью, что поведение/ALL должно быть или должно быть с чем-то вроде «ab? C d e? * F» ... если он предоставил альтернативную логику шаблона или что. Я предполагаю, что реализация Rebol2 краткая? Вероятно, это соответствует только одному шаблону.

Чтобы установить базовый уровень, вот, возможно, хромой решение PARSE для s?r намерения:

>> parse "here is a string" [ 
     some [    ; match rule repeatedly 
      to "s"   ; advance to *before* "s" 
      pos:    ; save position as potential match 
      skip    ; now skip the "s" 
      [     ;  [sub-rule] 
       skip   ; ignore any single character (the "?") 
       "r"   ; match the "r", and if we do... 
       return pos ; return the position we saved 
      |     ;  | (otherwise) 
       none   ; no-op, keep trying to match 
      ] 
     ] 
     fail     ; have PARSE return NONE 
    ] 
== "string" 

Если вы хотите, чтобы это было s*r вы бы изменить skip "r" return pos в to "r" return pos.

В примечании об эффективности я упомянул, что на самом деле символы сопоставляются с символами быстрее, чем строки. Таким образом, to #"s" и #"r" to end делают измеримую разницу в скорости при анализе строк в целом. Помимо этого, я уверен, что другие могут сделать лучше.

Правило, безусловно, превышает "s?r". Но это не , что долго, когда комментарии вынимают:

[some [to #"s" pos: skip [skip #"r" return pos | none]] fail] 

(Примечание: Это делает утечки поз:.? как написано Есть USE в PARSE, реализованы или планируются)

Однако приятная вещь в том, что он предлагает точки крючка во все моменты принятия решения, и без устранения дефектов имеет наивное строковое решение. (я соблазн дать свою обычную "Bad LEGO alligator vs. Good LEGO alligator" речь.)

Но если вы не хотите, чтобы закодировать в PARSE непосредственно, кажется, реальный ответ был бы какой-то "Glob Expression" -в-PARSE компилятором. Это может быть лучшей интерпретацией Glob Rebol бы, потому что вы могли бы сделать одноразовый:

>> parse "here is a string" glob "s?r" 
== "string" 

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

s?r-rule: glob ["s" one "r"] 

pos-1: parse "here is a string" s?r-rule 
pos-2: parse "reuse compiled RegEx string" s?r-rule 

Было бы интересно увидеть такой компилятор для регулярных выражений, а также. Они также могут принимать не только строку ввода, но и блокировать вход, так что оба "s.r" и ["s" . "r"] были легальными ... и если вы использовали форму блока вам не нужно бежать и мог бы написать ["." . "."], чтобы соответствовать ".A."

Довольно интересно все будет возможно. Учитывая, что в RegEx:

(abc|def)=\g{1} 
matches abc=abc or def=def 
but not abc=def or def=abc 

Rebol может быть изменен, чтобы принять либо форму строки или скомпилировать в правило PARSE с формой, как:

regex [("abc" | "def") "=" (1)] 

Тогда вы получите вариацию диалект, который не делает нужно ускользнуть. Проектирование и запись таких компиляторов остается в качестве упражнения для читателя. :-)

2

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

expand-wildcards: use [literal][ 
    literal: complement charset "*?" 

    func [ 
     {Creates a PARSE rule matching VALUE expanding * (any characters) and ? (any one character)} 
     value [any-string!] "Value to expand" 
     /local part 
    ][ 
     collect [ 
      parse value [ 
       ; empty search string FAIL 
       end (keep [return (none)]) 
       | 

       ; only wildcard return HEAD 
       some #"*" end (keep [to end]) 
       | 

       ; everything else... 
       some [ 
        ; single char matches 
        #"?" (keep 'skip) 
        | 

        ; textual match 
        copy part some literal (keep part) 
        | 

        ; indicates the use of THRU for the next string 
        some #"*" 

        ; but first we're going to match single chars 
        any [#"?" (keep 'skip)] 

        ; it's optional in case there's a "*?*" sequence 
        ; in which case, we're going to ignore the first "*" 
        opt [ 
         copy part some literal (
          keep 'thru keep part 
         ) 
        ] 
       ] 
      ] 
     ] 
    ] 
] 

like: func [ 
    {Finds a value in a series and returns the series at the start of it.} 
    series [any-string!] "Series to search" 
    value [any-string! block!] "Value to find" 
    /local skips result 
][ 
    ; shortens the search a little where the search starts with a regular char 
    skips: switch/default first value [ 
     #[none] #"*" #"?" ['skip] 
    ][ 
     reduce ['skip 'to first value] 
    ] 

    any [ 
     block? value 
     value: expand-wildcards value 
    ] 

    parse series [ 
     some [ 
      ; we have our match 
      result: value 

      ; and return it 
      return (result) 
      | 

      ; step through the string until we get a match 
      skips 
     ] 

     ; at the end of the string, no matches 
     fail 
    ] 
] 

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

Я пошел с PARSE, как даже если *?, казалось бы, простые правила, нет ничего столь же выразительного и быстро в PARSE для эффективного осуществления такого поиска.

Возможно, в связи с тем, что @HostileFork может рассматривать диалект вместо строк с подстановочными знаками - действительно, до тех пор, пока Regex не заменяется диалектом компиляции для разбора, но, возможно, выходит за рамки вопроса.