2 ms·
Another way of doing it is to use variables and helper functions, particularly if you're going to be creating lots of regexps from similar components. This is w
by to3m 11y ago
Another way of doing it is to use variables and helper functions, particularly if you're going to be creating lots of regexps from similar components. This is what I usually do in Python. For example, while making no promises about the value of this code specifically:
def any(x): return x+"*"
def many(x): return x+"+"
def capture(x): return "("+x+")"
def lit(x): return re.escape(x) # shorthand
bol="^"; eol="$"
ident="[A-Za-z_][A-Za-z0-9_]*";
find_function=(bol+any(" ")+lit("def")+many(" ")+
capture(ident)+any(" ")+lit(":")+
any(" ")+eol)
You can handle more or less stuff this way according to how much you and/or your readers like regexp syntaxp. The above is probably further than I'd take it in practice; I'm familiar with the regular expression syntax, but I'd still probably at least use something like the `ident' variable just to keep clutter out of the regexp.
(A nice demonstration of this sort of thing is emacs's rx module (see, e.g., http://emacswiki.org/emacs/rx http://emacswiki.org/emacs/rx). I couldn't find any good non-emacs documentation about this, nor much that would make sense to people unfamiliar with lisp, but when you're in emacs you can get help on it using C-h f rx RET.)
- TeMPOraL 11y agoI agree. In terms of variables, I think a good strategy is assigning names to meanings, e.g. PRODUCT_ID = "[0-9]{2}[A-Z]{1,5}" ... CUSTOMER_ID = "[0-9]{2}[A-Z]{1,5}" ... ... regexp = "(" + PRODUCT_ID + ")" // capture product ID in group 1 + "something something" // something something + "(" + CUSTOMER_ID + ")"; // capture customer ID in group 2 In this example, even though the two constants contain the same regular expresison, they refer to two different concepts. Part of the problem with understanding regexp-based code is connecting parts of the expression with what they mean. Above strategy addresses this. I also like assigning names to capture groups I depend on. So instead of, later in code, asking for e.g. matcher.group(2), I ask for matcher.group(GROUP_CUSTOMER_ID). Makes for a much more readable code. Speaking of Emacs's rx, it's absolutely amazing and I'm sad that I only discovered it just few days ago :(. Another similar concept, from the other side of "code = data" equality is Common Lisp's (of course it's Lisp again) CL-PPCRE and its internal representation of regular expressions: * (parse-string "(ab)*") (:GREEDY-REPETITION 0 NIL (:REGISTER "ab")) * (parse-string "(a(b))") (:REGISTER (:SEQUENCE #\a (:REGISTER #\b))) * (parse-string "(?:abc){3,5}") (:GREEDY-REPETITION 3 5 (:GROUP "abc")) You can encode any regexp you want as an S-expression, trading off conciseness for legibility. See http://weitz.de/cl-ppcre/#create-scanner2 http://weitz.de/cl-ppcre/#create-scanner2 for more.