Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[PL] (4dev, JS) Nie ma nic prostszego niż napisanie wolnego regexpa

mrzasa
April 09, 2018

[PL] (4dev, JS) Nie ma nic prostszego niż napisanie wolnego regexpa

Slajdy z prezentacji podczas 4 Developers 2018 o wydajności regexpów, odmiana JavaScript.

W prezentacji: o tym, jak działają silniki regexpów, jak to wpływa na czas działania regexpa. Oraz o tym, co złego może się stać, jeśli nie dbamy o wydajność regexpów.

mrzasa

April 09, 2018
Tweet

More Decks by mrzasa

Other Decks in Programming

Transcript

  1. NIE MA NIC PROSTSZEGO NIŻ
    NIE MA NIC PROSTSZEGO NIŻ
    NAPISANIE WOLNEGO
    NAPISANIE WOLNEGO
    REGEXPA
    REGEXPA
    MACIEK RZĄSA
    MACIEK RZĄSA
    4Developers, 09.04.2018
    @mjrzasa

    View full-size slide

  2. I'm definitely guilty of this. When I throw a regex
    together, I never worry about performance;
    I know the target strings will generally be
    far too small to ever cause a problem.
    Jeff Atwood, 2006

    View full-size slide

  3. JEŚLI JEFF ATWOOD NIE DBA
    JEŚLI JEFF ATWOOD NIE DBA
    OD WYDAJNOŚĆ REGEXPÓW,
    OD WYDAJNOŚĆ REGEXPÓW,
    DLACZEGO JA POWINIENEM?
    DLACZEGO JA POWINIENEM?

    https://regex-performance.github.io/input.html

    View full-size slide

  4. CO DALEJ?
    CO DALEJ?
    jak właściwie działają regexpy?
    wydajność podstawowych
    elementów
    zastosowania
    co może pójść nie tak?
    czy istnieją szybkie regexpy?

    View full-size slide

  5. RUBY DEVELOPER
    RUBY DEVELOPER
    @ TEXTMASTER
    @ TEXTMASTER
    w pracy:
    Ruby, Java, mongodb, elastic search
    automatyczne przygotowanie tekstu do
    tłumaczeń
    DDD, software that matters, agile
    dzielenie się wiedzą:
    Rzeszów Ruby User Group ( )
    Politechnika Rzeszowska
    rrug.pl

    View full-size slide

  6. JAK WŁAŚCIWIE
    JAK WŁAŚCIWIE
    DZIAŁAJĄ
    DZIAŁAJĄ
    REGEXPY?
    REGEXPY?

    View full-size slide

  7. TEORIA...
    TEORIA...
    gramatyka regularna
    wyrażenie regularne: abab|abbb
    automat skończony
    a b a
    a
    b
    b b b
    źródło:
    A -> abB
    B -> bb
    B -> ab
    https://swtch.com/~rsc/regexp/regexp1.html

    View full-size slide

  8. ...SPOTYKA PRAKTYKĘ
    ...SPOTYKA PRAKTYKĘ
    w teorii języków formalnych
    w silnikach wyrażeń
    regularnych
    a* a+ a|b a? a(a|b)
    a* a+ a|b a? a(a|b) a*? \d
    \W (/(\w+)\1/ -> papa WikiWiki
    /\(((?R)|\w+)\)/ -> (((12)))

    View full-size slide

  9. DWA RODZAJE SILNIKÓW
    DWA RODZAJE SILNIKÓW
    REGEXPÓW
    REGEXPÓW
    1. Text-directed
    Thompson 1968, 400 linii w C
    grep, awk, sed, go
    oparte na DFA
    2. Regex-directed
    Larry Wall, perl, 1987
    Perl-Compatible Regular Expressions
    (JavaScript, Ruby, .Net,...)
    oparte na NFA

    View full-size slide

  10. PRZYKŁAD
    PRZYKŁAD
    a b a
    a
    b
    b b b
    źródło ilustracji na tym i kolejnych slajdach:
    /abab|abbb/.exec('abbb')
    https://swtch.com/~rsc/regexp/regexp1.html

    View full-size slide

  11. a b a
    a
    b
    b b b
    •abbb
    a b a
    a
    b
    b b b
    a•bbb
    a b a
    a
    b
    b b b
    ab•bb
    a b a
    a
    b
    b b b
    abb•b
    a b a
    a
    b
    b b b
    abbb•

    View full-size slide

  12. a b a
    a
    b
    b b b
    •abbb
    a b a
    a
    b
    b b b
    •abbb
    a b a
    a
    b
    b b b
    a•bbb
    a b a
    a
    b
    b b b
    ab•bb
    a b a
    a
    b
    b b b
    •abbb
    a b a
    a
    b
    b b b
    a•bbb
    a b a
    a
    b
    b b b
    ab•bb
    a b a
    a
    b
    b b b
    abb•b
    a b a
    a
    b
    b b b
    abbb•
    failure, backtracking

    View full-size slide

  13. CO JUŻ WIEMY?
    CO JUŻ WIEMY?
    regexpy - osobny język programowania
    dwa rodzaje silników (maszyn wirtualnych) - text-directed,
    regex-directed
    istotna jest ilość kroków i powrotów

    View full-size slide

  14. POWTÓRZENIA
    POWTÓRZENIA

    View full-size slide

  15. POWTÓRZENIA
    POWTÓRZENIA
    .* greedy (zachłanne)
    .*? lazy (leniwe)
    /<.*>/=~"
    regexp text "
    => "
    " # so far so good
    /<.*>/=~" regexp text "
    => " regexp text " #hmmm...
    /<[^>]*>/=~" regexp text "
    => "" # great!
    /<.*?>/=~" regexp text "
    => "" # great!

    View full-size slide

  16. WARTO BYĆ LENIWYM?
    WARTO BYĆ LENIWYM?
    " regexp text "
    /<[^>]*>/ /<.*?>/

    View full-size slide

  17. LICZY SIĘ KONTEKST
    LICZY SIĘ KONTEKST
    "
    some really long text"
    <.*> 27 kroków
    <.*?> 7 kroków
    <[^>]*> 4 kroki
    "some really long text

    "
    <.*> 5 kroków
    <.*?> 7 kroków
    <[^>]*> 4 kroki

    View full-size slide

  18. POWTÓRZENIA
    POWTÓRZENIA
    wydajność zależna od kontekstu
    zachłanne .* .+ - wydajność zależna od długości
    nadmiarowo znalezionego tekstu
    leniwe .*? .+? - wydajność zależna od długości
    szukanego tekstu
    testy pozytywne: szukany string w różnych miejscach
    tekstu
    testy negatywne: napis bardzo podobny do szukanego

    View full-size slide

  19. TO WSZYSTKO TO DROBIAZG
    TO WSZYSTKO TO DROBIAZG
    To nie po to Was tu trzymam

    View full-size slide

  20. CATASTROPHIC
    CATASTROPHIC
    BACKTRACKING
    BACKTRACKING

    View full-size slide

  21. POWTÓRZENIE W POWTÓRZENIU
    POWTÓRZENIE W POWTÓRZENIU
    ..ale kto pisze takie regexy?
    /(a+)*b/
    aaaaaaaaaab
    aaaaaaaaaa

    View full-size slide

  22. DZIAŁANIA ARYTMETYCZNE
    DZIAŁANIA ARYTMETYCZNE
    320-12=
    430-
    32+1=
    /\d+[-+]\d+=/ # v1
    /(\d+[-+])+=/ # v1.0.1
    /(\d+[-+]?)+=/ #v2
    /(\d+|[-+])+=/
    "320-12=" # 12 kroków
    "32-12+230=" # 18 kroków
    "32+12-320-2132+32123=" # 28 kroków
    "32+12-320-2132+32123" # 95 854 kroki

    View full-size slide

  23. COPY-PASTING
    COPY-PASTING
    (email validation)
    , Java Classname
    RegExLib, id=1757
    ^([a-zA-Z0-9])(([\-.]|[_]+)?
    ([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}
    (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$
    OWASP Validation Regex Repository
    ^(([a-z])+.)+[A-Z]([a-z])+$
    'aaaaaaaaaaaaaaa'

    View full-size slide

  24. CZEGO UNIKAĆ?
    CZEGO UNIKAĆ?
    nachodzące się zakresy /\d+\w*/
    nachodzace się alternatywy
    /(\d+|\w+)/
    odległe, krzyżujące się powtórzenia
    /.*-some text-.*;/
    zagnieżdżone powtórzenia /(\d+)*\w/

    View full-size slide

  25. KOMPUTERY TERAZ SĄ TAK
    KOMPUTERY TERAZ SĄ TAK
    SZYBKIE, ŻE NAWET 100 000
    SZYBKIE, ŻE NAWET 100 000
    KROKÓW NIE MA ZNACZENIA!
    KROKÓW NIE MA ZNACZENIA!
    kilka słów o zastosowaniach

    View full-size slide

  26. ZLICZANIE LICZB W TEKŚCIE
    ZLICZANIE LICZB W TEKŚCIE
    co może być prostszego?
    // liczba
    // 1, 3243, 4323
    var pattern = /\d+/
    // liczba z częścią dziesiętną i minusem
    // -1, 1, 32.32, -2.2324
    var pattern = /-?(\d+(\.\d+)?/
    // liczba z częścią dziesiętną (kropka albo przecinek)
    // -23,23 4323.23
    var pattern = /-?(\d+([.,]\d+)?)/

    View full-size slide

  27. ZLICZANIE LICZB W TEKŚCIE
    ZLICZANIE LICZB W TEKŚCIE
    // liczba z częścią dziesiętną i separatorami tysięcy
    // -21,321,321.1111 433.233,12
    var greedy = /(-?(\d+[,.]?)+)/
    // j.w., lazy
    var lazy = /(-?((\d+?[,.])+?)/
    // j.w., z ograniczeniem backtrackingu
    var unrolled = /(-?(\d+[,.])*\d+)/

    View full-size slide

  28. TESTY
    TESTY
    greedy lazy unrolled
    countWhole 191 ops/sec 220 ops/sec 6,689 ops/sec
    countSplit 227 ops/sec 231 ops/sec 1,782 ops/sec
    var greedy = /(-?(\d+[,.]?)+)/
    var lazy = /(-?(\d+?[,.]?)+?)/
    var unrolled = /(-?\d+([,.]\d+)*)/
    var string = "..." // ~11000 chars
    function countWhole(string, regex) {
    // count how many times regex is matched on a string
    }
    function countSplit(string, regex) {
    // split string to words,
    // then check which word is a number
    }

    View full-size slide

  29. REDOS - CZYLI CO MOŻE
    REDOS - CZYLI CO MOŻE
    PÓJŚĆ NIE TAK?
    PÓJŚĆ NIE TAK?

    View full-size slide

  30. JAK ZAMULIĆ FRONTEND?
    JAK ZAMULIĆ FRONTEND?
    vue.js

    View full-size slide

  31. JAK ZAJĄĆ 100% PROCESORA?
    JAK ZAJĄĆ 100% PROCESORA?
    Witaj! → ¡Hola! → Salut !
    # Ruby
    # Źródła funkcji
    ::Typography.to_html_french
    # Wstaw cienką spację przed znaki interpunkcyjne
    text.gsub(/(\s|)+([!?;]+(\s|\z))/, ' \2\3')
    # Dane
    # <-58 spacji ->
    GET /wp-login.php HTTP/1.1 69
    GET /show.aspx HTTP/1.1 15
    klient Discourse, opisane przez Sama Saffrona

    View full-size slide

  32. POZWÓLMY UŻYTKOWNIKOM PISAĆ
    POZWÓLMY UŻYTKOWNIKOM PISAĆ
    REGEXPY
    REGEXPY
    feature request
    (<.*>\s*)*

    View full-size slide

  33. DOBRE PRAKTYKI
    DOBRE PRAKTYKI
    .* => [^X]*
    .*? => [^X]*
    (A*|B?)+ => (A*B)*A
    (pre-d1|pre-e2|...) => pre-(d1|e2|...)
    (,|;|\.) => [,.;]
    \w+-\d+ => \w+-\d++, \w+-(?>\d+), \w+-(?
    =(\d+))\1

    View full-size slide

  34. WNIOSKI
    WNIOSKI
    optymalizacja regexpów: minimalizacja ilości kroków i
    powrotów
    główne problemy: nachodzące się zakresy lub alternatywy,
    zagnieżdżone powtórzenia
    testy: poprawny, niepoprawny, prawie poprawny napis,
    różne konfiguracje
    każdy silnik jest inny - testuj wydajność na swoim

    View full-size slide

  35. MATERIAŁY
    MATERIAŁY
    Mastering Regular Expressions, 3rd Edition, Jefferey Friedl,
    2009
    i kolejne części (1-4)
    podziękowania dla kszubrycht
    :)
    http://www.rexegg.com
    https://www.regular-expressions.info
    https://regex101.com/
    Russ Cox
    aplikacja testowa - oryginał
    OWASP ReDoS
    Loggly: 5 techniquess
    Loggly: regexes bad better...

    View full-size slide