5 ms·
Personally, I've found it really helps to limit the patterns as much as possible to best match the valid input. My own rules of thumb: - Prefer character class
by shdon 6y ago
Personally, I've found it really helps to limit the patterns as much as possible to best match the valid input. My own rules of thumb:
- Prefer character classes like \d, \s or \w over .
- Prefer non-greedy .*? over greedy .*
- Exclude a delimiter from the search space, like using [^>]*?> rather than .*?> or worse yet .*>
- Prefer {count specifiers} over unbounded repeats. Not \d+ but \d{,3} instead
- zwp 6y agoGreat list. I would add - Anchor when possible (^, $)
- Y_Y 6y ago(If I understand correctly) This "(^,$)" should be parsed as a list of useful "anchor" symbols (resp. start and end of string) rather than a regexep itself. I wasted some time before I realised this.
- zwp 6y agoYes, that's essentially what I was trying to communicate. Since we are engine agnostic here be careful interpreting ^ or $ as start/end of _string_ though. In some regex engines this means start/end of _line_. If that's the case and if a regex validates input up to $ an attacker might be able to sneak in extra data after a newline. In Python you'd need multiline enabled but Ruby matches by default: irb(main):001:0> /^okay$/ =~ "okay\noops" => 0 # matches from position 0 (Ruby has \A and \Z for start and end of string to address this).
- Jenk 6y ago> - Exclude a delimiter from the search space, like using [^>]*?> rather than .*?> or worse yet .*> Or indeed: (?!>).*?
- rstuart4133 6y agoNot quite. This works: (?:(?!>).)*>? But that is a very long winded way of writing: [^>]*?> which is long way of writing: [^>]*>
- Jenk 6y agoI was missing the trailing > in my pattern but you are still right (as is the article) It's been fun to note the benchmarks: all tested against the string: <a href="sdfsdf">sefsefsefsef</a> 1. (?!>).*?> 2 matches, 41 steps 2. (?:(?!>).)*>? 3 matches, 142 steps 3. (typo?) (?:(?!>).)*?> 2 matches, 161 steps 4. [^>]*?> 2 matches, 6 steps 5. [^>]*> 2 matches, 6 steps
- epr 6y agoAgreed on all points. It is very frustrating that greedy is the default behavior.
- slaymaker1907 6y agoThe most important trait to avoid exponential behavior is to avoid nesting ?, *, +, etc.