gawk: Computed Regexps
3.6 Using Dynamic Regexps
=========================
The righthand side of a '~' or '!~' operator need not be a regexp
constant (i.e., a string of characters between slashes). It may be any
expression. The expression is evaluated and converted to a string if
necessary; the contents of the string are then used as the regexp. A
regexp computed in this way is called a "dynamic regexp" or a "computed
regexp":
BEGIN { digits_regexp = "[[:digit:]]+" }
$0 ~ digits_regexp { print }
This sets 'digits_regexp' to a regexp that describes one or more digits,
and tests whether the input record matches this regexp.
NOTE: When using the '~' and '!~' operators, be aware that there is
a difference between a regexp constant enclosed in slashes and a
string constant enclosed in double quotes. If you are going to use
a string constant, you have to understand that the string is, in
essence, scanned _twice_: the first time when 'awk' reads your
program, and the second time when it goes to match the string on
the lefthand side of the operator with the pattern on the right.
This is true of any string-valued expression (such as
'digits_regexp', shown in the previous example), not just string
constants.
What difference does it make if the string is scanned twice? The
answer has to do with escape sequences, and particularly with
backslashes. To get a backslash into a regular expression inside a
string, you have to type two backslashes.
For example, '/\*/' is a regexp constant for a literal '*'. Only one
backslash is needed. To do the same thing with a string, you have to
type '"\\*"'. The first backslash escapes the second one so that the
string actually contains the two characters '\' and '*'.
Given that you can use both regexp and string constants to describe
regular expressions, which should you use? The answer is "regexp
constants," for several reasons:
* String constants are more complicated to write and more difficult
to read. Using regexp constants makes your programs less
error-prone. Not understanding the difference between the two
kinds of constants is a common source of errors.
* It is more efficient to use regexp constants. 'awk' can note that
you have supplied a regexp and store it internally in a form that
makes pattern matching more efficient. When using a string
constant, 'awk' must first convert the string into this internal
form and then perform the pattern matching.
* Using regexp constants is better form; it shows clearly that you
intend a regexp match.
Using '\n' in Bracket Expressions of Dynamic Regexps
Some older versions of 'awk' do not allow the newline character to be
used inside a bracket expression for a dynamic regexp:
$ awk '$0 ~ "[ \t\n]"'
error-> awk: newline in character class [
error-> ]...
error-> source line number 1
error-> context is
error-> $0 ~ "[ >>> \t\n]" <<<
But a newline in a regexp constant works with no problem:
$ awk '$0 ~ /[ \t\n]/'
here is a sample line
-| here is a sample line
Ctrl-d
'gawk' does not have this problem, and it isn't likely to occur often
in practice, but it's worth noting for future reference.