2015-07-24 20 views
8

Rebol2 ma ŻADNYCH/dystynkcję na funkcję okaże się, że można zrobić wyszukiwań wieloznacznych:Czy ktoś ma wydajną funkcję R3, która naśladuje zachowanie find/any w R2?

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

Używam tego obszernie w ciasnych pętli, które muszą wykonywać dobrze. Ale wyrafinowanie zostało usunięte w Rebol3.

Jaki jest najskuteczniejszy sposób robienia tego w Rebol3? (Zgaduję się parse rozwiązanie pewnego rodzaju.)

+0

Związany z wydajnością i PARSE, ["Jaki jest najszybszy/najbardziej efektywny sposób liczenia linii w Rebolu] (http://stackoverflow.com/questions/14765993/whats-the-fastest-most-efficient-way- to-count-lines-in-rebol) może dostarczyć ogólnych informacji: – HostileFork

+0

Sądzę, że masz już rozwiązanie, możesz odpowiedzieć na własne pytania, a inni użytkownicy mogą na nie głosować: – sqlab

+0

Dla odniesienia: symbole wieloznaczne nie są zawarte w słownikowa definicja FIND dla [Rebol 3] (http://www.rebol.com/r3/docs/functions/find.html) lub [Rebol 2] (http://www.rebol.com/docs/words/ wfind.html), a raczej w [Core User Manual] (http://www.rebol.com/docs/core23/rebolcore-6.html#section-7.8). – rgchris

Odpowiedz

3

Oto stab w pracy z "*" przypadek:

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

wykorzystane w następujący sposób:

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

miałem edytowano pytanie o "jasność" i zmieniono to na "usunięto". To sprawiło, że zabrzmiało to jak celowa decyzja. Jednak okazuje się, że nie zostało to zaimplementowane.

ALE jeśli ktoś mnie pyta, nie sądzę, że powinien być w pudełku ... i nie tylko dlatego, że jest kiepskim użyciem słowa "WSZYSTKO". Oto dlaczego:

Poszukujesz wzorów w ciągach ... więc jeśli jesteś zmuszony do używania ciągu znaków, aby określić ten wzór, dostaniesz się do problemów "meta". Powiedzmy, że chcę wydobyć słowo *Rebol* lub ?Red?, teraz musi być ucieczka i wszystko staje się brzydkie od nowa. Powrót do RegEx. : -/

To, co może może rzeczywiście chce nie jest STRING! wzór taki jak s?r, ale BLOK! wzór taki jak ["s" ? "r"]. Umożliwiłoby to konstruktom takim jak ["?" ? "?"] lub . To lepsze niż ponowne użycie sznurka, którego używa każdy inny język.

I to właśnie robi PARSE, choć w nieco mniej deklaratywny sposób. Używa także słów zamiast symboli, jak lubi to Rebol. [{?} skip {?}] jest regułą dopasowania, w której skip jest instrukcją, która przesuwa pozycję analizy o dowolny element serii analizowania między znakami zapytania. Mogłoby to również zrobić, jeśli analizowałby blok jako dane wejściowe i pasowałoby do [{?} 12-Dec-2012 {?}].

Nie wiem do końca, jakie zachowanie/ALL powinno być lub powinno być z czymś takim jak "ab ?? c d e? * F" ... jeśli dostarczono alternatywną logikę wzoru lub co. Zakładam, że implementacja Rebol2 jest krótka? Prawdopodobnie pasuje tylko do jednego wzoru.

Aby ustawić punkt odniesienia, tutaj jest możliwe rozwiązanie PARSE-lame dla s?r intencji:

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

Jeśli chciał go mieć s*r byś zmienić skip "r" return pos w to "r" return pos.

W notatce dotyczącej efektywności wspomnę, że w rzeczywistości jest tak, że postacie są porównywane z postaciami szybszymi niż ciągi. Tak więc to #"s" i #"r" to end dają mierzalną różnicę w prędkości podczas ogólnego analizowania łańcuchów. Poza tym jestem pewien, że inni mogą robić lepiej.

Zasada jest z pewnością dłuższa niż "s?r". Ale to nie jest że długo gdy komentarze są wyjęte:

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

(Uwaga: To nie wycieka poz.? jak napisane jest tam USE w zanalizować, realizowane lub planowane)

Jednak zaletą jest to, że oferuje punkty zaczepienia we wszystkich momentach decyzji, a bez uciekających wad ma naiwne rozwiązanie. (Kusi mnie, aby dać mój zwykły "Bad LEGO alligator vs. Good LEGO alligator" mowy.)

Ale jeśli nie chcesz, aby kod w analizowania bezpośrednio, wydaje się realna odpowiedź byłaby jakaś "Glob Expression" -to-analizowania kompilator. To może być najlepsza interpretacja glob REBOL musiałby, bo można zrobić jednorazowo:

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

Lub jeśli masz zamiar robić meczu często cache skompilowany wyrażenie. Ponadto, wyobraźmy sobie nasz formularz blok używa słów do czytania:

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 

To może być interesujące, aby taki kompilator regex również. Są również może zaakceptować nie tylko wejście ciąg ale także blokować wejście, dzięki czemu zarówno "s.r" i ["s" . "r"] były legalne ... i jeśli użyto formę bloku, który nie musiałby uciec i mógł napisać ["." . "."] dopasować ".A."

Dość ciekawy wszystko byłoby możliwe. Biorąc pod uwagę, że w RegEx:

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

REBOL może być zmodyfikowany tak, aby wziąć albo formę sznurka lub skompilować do reguły analizowania z postaci jak:

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

Wtedy masz odmianę dialektu, który nie potrzebujesz ucieczki. Projektowanie i pisanie takich kompilatorów pozostawia się jako ćwiczenie dla czytelnika. :-)

2

Złamałem to na dwie funkcje: jedną, która tworzy regułę pasującą do podanej wartości wyszukiwania, a drugą do wyszukiwania. Oddzielającej dwa pozwala używać tego samego wygenerowany blok parsującej gdzie jedna wartość wyszukiwania jest stosowane na wielu iteracji:

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

Dzielenie funkcja daje również podstawę do optymalizacji dwa różne problemy: ze znalezieniem start i dopasowując wartość.

poszedłem z zanalizować jak chociaż *? są pozornie proste zasady, nie ma nic aż tak wyraziste i szybkie jak PARSE do skutecznego wdrożenia takiego wyszukiwania.

Może jeszcze jako @HostileFork rozważyć dialekt zamiast ciągów z symbolami wieloznacznymi - w rzeczy samej do punktu, w którym Regex jest zastąpiony przez dialekt kompilacji do parsowania, ale być może wykracza poza zakres pytania.