2015-07-24 10 views
8

Rebol2 hat eine/ANY Verfeinerung auf der FIND-Funktion, die Wildcard Durchsuchung tun können:Hat jemand eine effiziente R3-Funktion, die das Verhalten von find/any in R2 nachahmt?

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

Ich benutze diese ausführlich in engen Schleifen, die gut durchführen müssen. Aber die Verfeinerung wurde in Rebol3 entfernt.

Was ist der effizienteste Weg, dies in Rebol3 zu tun? (Ich vermute, eine parse Lösung irgendeine Art.)

+0

Bezogen auf Effizienz und PARSE, ["Was ist der schnellste/effizienteste Weg, Zeilen in Rebol zu zählen] (http://stackoverflow.com/questions/14765993/whats-the-fastest-most-efficient-way- to-count-lines-in-rebol) kann einige allgemeine Einblicke liefern. – HostileFork

+0

Ich denke, Sie haben bereits eine Lösung. Sie können Ihre eigenen Fragen beantworten und andere Benutzer können auch dafür stimmen. – sqlab

+0

Als Referenz: Wildcards sind nicht in der enthalten Wörterbuchdefinition von FIND für [Rebol 3] (http://www.rebol.com/r3/docs/functions/find.html) oder [Rebol 2] (http://www.rebol.com/docs/words/ wfind.html), eher im [Kernbenutzerhandbuch] (http://www.rebol.com/docs/core23/rebolcore-6.html#section-7.8). – rgchris

Antwort

3

Hier ist ein Stich im Umgang mit dem "*" Fall:

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 
    ] 
] 

wie folgt verwendet:

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

Ich hatte bearbeitet Ihre Frage nach "Klarheit" und änderte es zu sagen "wurde entfernt". Das klang nach einer bewussten Entscheidung. Es stellt sich jedoch heraus, dass es möglicherweise nicht implementiert wurde.

ABER wenn jemand mich fragt, ich denke nicht, dass es in der Box sein sollte ... und nicht nur, weil es eine miese Verwendung des Wortes "ALLES" ist. Hier ist warum:

Sie suchen nach Mustern in Strings ... also, wenn Sie eine Zeichenfolge verwenden müssen, um dieses Muster anzugeben, geraten Sie in "Meta" -Probleme. Lassen Sie uns sagen, ich möchte das Wort *Rebol* oder ?Red? extrahieren, jetzt muss es entkommen und die Dinge werden wieder hässlich. Zurück zu RegEx. : -/

Also was Sie möglicherweise eigentlich wollen, ist kein STRING! Muster wie s?r aber ein BLOCK! Muster wie ["s" ? "r"]. Dies würde Konstrukte wie ["?" ? "?"] oder [{?} ? {?}] erlauben. Das ist besser, als die String-Hackerei, die jede andere Sprache verwendet, erneut zu verwenden.

Und das ist, was PARSE tut, wenn auch in einer weniger deklarativen Weise. Es verwendet auch Wörter anstelle von Symbolen, wie Rebol es gerne tut. [{?} skip {?}] ist eine Übereinstimmungsregel, in der skip eine Anweisung ist, die die Analyseposition nach jedem einzelnen Element der Parse-Reihe zwischen den Fragezeichen verschiebt. Dies könnte auch der Fall sein, wenn ein Block als Eingabe analysiert würde und [{?} 12-Dec-2012 {?}] entspricht.

Ich weiß nicht ganz, was das Verhalten von/ALL würde or sollte so etwas wie „ab ?? c d e? * F“ ... wenn es vorgesehen, alternative Muster Logik oder was. Ich nehme an, die Rebol2-Implementierung ist kurz? Wahrscheinlich stimmt es nur mit einem Muster überein.

eine Basislinie zu setzen, ist hier eine möglicherweise-lame PARSE Lösung für die s?r Absicht:

>> 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" 

Wenn Sie es sein s*r wollte würden Sie die skip "r" return pos in eine to "r" return pos ändern.

Auf eine Effizienznote, ich werde erwähnen, dass es in der Tat der Fall ist, dass Zeichen mit Zeichen schneller als Strings verglichen werden. So to #"s" und #"r" to end machen einen messbaren Unterschied in der Geschwindigkeit beim Parsen von Strings im Allgemeinen. Darüber hinaus bin ich mir sicher, dass andere es besser können.

Die Regel ist sicherlich länger als "s?r". Aber es ist nicht dass lang, wenn Kommentare herausgenommen werden:

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

(Hinweis: Es tut pos auslaufen.? wie geschrieben wird eine Verwendung in PARST, umgesetzt oder geplant)

Noch eine schöne Sache ist, dass es Hook-Punkte in allen Momenten der Entscheidung bietet, und ohne die austretenden Defekte eine naive String-Lösung hat. (ich bin versucht, meine übliche "Bad LEGO alligator vs. Good LEGO alligator" Rede zu halten.)

Aber wenn Sie nicht direkt in PARST codieren wollen, so scheint es, die wirkliche Antwort eine Art "Glob Expression" -bis-SYNTAX-Compiler sein würde. Es könnte die beste Interpretation glob sein Rebol haben würde, weil Sie eine einmalige tun könnte:

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

Oder wenn Sie das Spiel oft gehen zu tun, zwischenspeichern die kompilierte Ausdruck. Außerdem stellen wir uns unsere Blockform Worte für die Alphabetisierung verwendet:

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 

Es wird interessant sein könnte, eine solche Compiler für regex als auch zu sehen. Diese könnten auch akzeptieren, nicht nur String-Eingang, sondern auch Eingang blockieren, so dass beide "s.r" und ["s" . "r"] legal waren ... und wenn Sie die Blockform verwendet würden Sie nicht brauchen, zu entkommen und ["." . "."] schreiben konnte ".A."

Ziemlich interessant entsprechen Dinge wären möglich. Da in RegEx:

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

Rebol modifiziert werden könnte, entweder die Form einer Zeichenfolge oder kompilieren in eine PARSE Regel mit einer Form, wie zu nehmen:

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

Dann Sie einen Dialekt Variation erhalten, die nicht der Fall ist muss entkommen. Entwerfen und Schreiben solcher Compiler ist eine Übung für den Leser. :-)

2

Ich habe dies in zwei Funktionen aufgeteilt: eine, die eine Regel erstellt, um den angegebenen Suchwert zu entsprechen, und die andere, um die Suche durchzuführen. die beiden Trenn können Sie die gleiche erzeugt Parse-Block, in dem ein Suchwert über mehrere Iterationen angelegt wird, wieder zu verwenden:

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 
    ] 
] 

Splitting die Funktion gibt Ihnen auch eine Basis, um die zwei verschiedenen Anliegen zu optimieren: Suche nach dem Anfang und passend die Wert.

ging ich mit PARSE als obwohl *? sind scheinbar einfache Regeln, gibt es nichts ganz so ausdrucks und schnell als PARSE effektiv eine solche Suche Umsetzung zu.

Es könnte noch nach @HostileFork einen Dialekt anstelle von Zeichenfolgen mit Platzhaltern in Betracht ziehen - in der Tat bis zu dem Punkt, wo Regex durch einen kompilieren-zu-parsen Dialekt ersetzt wird, aber vielleicht über den Rahmen der Frage.