- Print
- PDF
Lasernet supports regular expressions in several modules. They are mostly used in the Text Filter modifier and engine and the Binary Filter modifier; however, regular expressions can also be very useful in JavaScript.
Regular expressions are built up from expressions, quantifiers and assertions. The simplest form of expression is simply a character, for example, x or 5. An expression can also be a set of characters. For example [ABCD] will match an A, B, C or D. In shorthand it could be written as [A-D]. If we want to match any of the capital letters in the English alphabet we can write [A-Z]. A quantifier tells the regular expression engine how many occurrences of the expression we want e.g., x{1,1} means match an x which occurs at least once and at most once. Assertions and more complex expressions will be discussed later.
In general, regular expressions cannot be used to check for balanced brackets or tags. For example, if you want to match an opening html <b> and its closing </b> you can only use a regular expression if you know that these tags are not nested; the html fragment, <b>bold <b>bolder</b></b> will not match as expected. If you know the maximum level of nesting it is possible to create a regular expression that will match correctly, but for an unknown level of nesting, regular expressions will fail.
Example 1
We will start by writing a regular expression to match integers in the range 0 to 99. We require at least one digit, so we start with [0-9]{1,1} which means match a digit just once. This regular expression matches integers in the range 0 to 9. To match one or two digits we can increase the maximum number of occurrences. The regular expression then becomes [0-9]{1,2} meaning match a digit at least once and at most twice.
However, this regular expression will not match correctly as its scope needs to be properly defined. To ensure that we match against the whole string we must use anchor assertions. By placing a ^ (caret) symbol first, the regular expression must match from the beginning of the string. By placing a $ (dollar) symbol last, the regular expression must match until the end of the string. So our regular expression now looks like this ^[0-9]{1,2}$. Note that assertions such as ^ and $, do not match any actual characters.
If you have seen regular expressions elsewhere, they may have looked different from the ones above. This is because some sets of characters and some quantifiers are so common that they have special symbols to represent them. [0-9] can be replaced with the symbol \d. The quantifier to match exactly one occurrence, {1,1}, can be replaced with the symbol itself. This means that x{1,1} is the equivalent of just using x. So our 0 to 99 matcher could be written ^\d{1,2}$. Another way of writing it could be ^\d\d{0,1}$; in other words, from the start of the string, match a digit followed by zero or one digits. In practice, most people would write it ^\d\d?$. The ? is a shorthand for the quantifier {0,1}, i.e., a minimum of no occurrences and a maximum of one occurrence. This is used to make an expression optional. The regular expression ^\d\d?$ means “from the beginning of the string match one digit followed by zero or one digit and then the end of the string”.
Example 2
Our second example matches the words 'mail', 'letter' or 'correspondence' without matching 'email', 'mailman', 'mailer', 'letterbox', and so on. We'll start by just matching 'mail'. In full, the regular expression is m{1,1}a{1,1}i{1,1}l{1,1}, but since each expression itself is automatically quantified by {1,1} we can simply write this as mail; an 'm' followed by an 'a' followed by an 'i' followed by an 'l'. The symbol '|' (bar) is used for alternation, so our regular expression now becomes mail|letter|correspondence which means match 'mail' or 'letter' or 'correspondence'.
Whilst this regular expression will find the words we want, it will also find words we don't want such as 'email'. We will start by putting our regular expression in parentheses (mail|letter|correspondence). Parentheses have two effects: firstly, they group expressions together, and secondly, they identify parts of the regular expression that we wish to capture. Our regular expression still matches any of the three words but now they are grouped together as a unit. This is useful for building up more complex regular expressions. It is also useful because it allows us to examine which of the words actually matched.
We need to use another assertion, this time \b “word boundary”: \b(mail|letter|correspondence)\b. This regular expression means “match a word boundary followed by the expression in parentheses followed by another word boundary”. The \b assertion matches a position in the regular expression not a character in the regular expression. A word boundary is any non-word character such as a space, a newline or the beginning or end of the string.
Example 3
For our third example we want to replace ampersands with the HTML entity '&'. The regular expression to match is simple: &, i.e. match one ampersand. Unfortunately, this will ruin our text if some of the ampersands have already been turned into HTML entities. So what we really want to say is ‘replace an ampersand providing it is not followed by 'amp;'’. For this we need the negative lookahead assertion. Our regular expression now becomes: &(?!amp;). The negative lookahead assertion is introduced with '(?!' and finishes with ')'. It means that the text it contains, 'amp;' in our example, must not follow the expression that precedes it.
Regular expressions provide a rich language that can be used in a variety of ways. For example, suppose we want to count all the occurrences of 'Eric' and 'Eirik' in a string. Two valid regular expressions to match these are \b(Eric|Eirik)\b and \bEi?ri[ck]\b. We need the word boundary '\b' so we don't get 'Ericsson' etc. The second regular expression actually matches more than we want, 'Eric', 'Erik', 'Eiric' and 'Eirik'.
Characters and Abbreviations for Sets of Characters
Meaning | |
|---|---|
c | Most characters represent themselves unless they have a regular expression function. Thus c matches the character c. |
\c | A character that follows a backslash matches the character itself except where mentioned below. For example if you wished to match an actual caret at the beginning of a string you would write \^. |
\a | This matches the ASCII bell character (BEL, 0x07). |
\f | This matches the ASCII form feed character (FF, 0x0C). |
\n | This matches the ASCII line feed character (LF, 0x0A, Unix newline). |
\r | This matches the ASCII carriage return character (CR, 0x0D). |
\t | This matches the ASCII horizontal tab character (HT, 0x09). |
\v | This matches the ASCII vertical tab character (VT, 0x0B). |
\xhhhh | This matches the Unicode character corresponding to the hexadecimal number hhhh (between 0x0000 and 0xFFFF). \0ooo (i.e., \zero ooo) matches the ASCII/Latin-1 character corresponding to the octal number ooo (between 0 and 0377). |
. (dot) | This matches any character (including newline). |
\d | This matches a digit (QChar::isDigit()). |
\D | This matches a non-digit. |
\s | This matches a whitespace (QChar::isSpace()). |
\S | This matches a non-whitespace. |
\w | This matches a word character (QChar::isLetterOrNumber() or '_'). |
\W | This matches a non-word character. |
\n | The n-th back reference, e.g. \1, \2, etc. |
Sets of Characters
Square brackets are used to match any character in the character set that is contained within them. All the character set abbreviations described above can be used within square brackets. Apart from the character set abbreviations and the following two exceptions, no characters have special meanings in square brackets.
Set | Description |
|---|---|
^ | The caret negates the character set if it occurs as the first character, i.e., immediately after the opening square bracket. For example, [abc] matches 'a', 'b' or 'c', but [^abc] matches anything except 'a', 'b' or 'c'. |
- | The dash is used to indicate a range of characters, for example [W-Z] matches 'W', 'X', 'Y' or 'Z'. |
The predefined character set abbreviations are more universal than using character ranges across platforms and languages. For example, [0-9] matches a digit in Western alphabets but \d matches a digit in any alphabet.
Note
In most regular expression literature, sets of characters are called “character classes”.
Quantifiers
By default, an expression is automatically quantified by {1,1}, i.e. it should occur exactly once. In the following list E stands for any expression. An expression is a character, an abbreviation for a set of characters, a set of characters in square brackets or any parenthesized expression.
Quantifier | Description |
|---|---|
E? | Matches zero or one occurrence of E. This quantifier means “the previous expression is optional” since it will match whether or not the expression occurs in the string. It is the same as E{0,1}. For example dents? will match 'dent' and 'dents'. |
E+ | Matches one or more occurrences of E. This is the same as E{1,MAXINT}. For example, 0+ will match '0', '00', '000', etc. |
E* | Matches zero or more occurrences of E. This is the same as E{0,MAXINT}. The * quantifier is often used by mistake. Since it matches zero or more occurrences, it will match when there are no occurrences at all. For example if we want to match strings that end in whitespace and use the regular expression \s*$ we would get a match on every string. This is because we have said ‘find zero or more whitespace followed by the end of string’, so even strings that don't end in whitespace will match. The regular expression we want in this case is \s+$ to match strings that have at least one whitespace at the end. |
E{n} | Matches exactly n occurrences of the expression. This is the same as repeating the expression n times. For example, x{5} is the same as xxxxx. It is also the same as E{n,n} e.g., x{5,5}. |
E{n,} | Matches at least n occurrences of the expression. This is the same as E{n,MAXINT}. |
E{,m} | Matches at most m occurrences of the expression. This is the same as E{0,m}. |
E{n,m} | Matches at least n occurrences of the expression and at most m occurrences of the expression. |
(MAXINT is implementation dependent, but will not be smaller than 1024.)
If we wish to apply a quantifier to more than just the preceding character, we can use parentheses to group characters together in an expression. For example, tag+ matches a 't' followed by an 'a' followed by at least one 'g', whereas (tag)+ matches at least one occurrence of 'tag'.
Note
Quantifiers are “greedy”. They will match as much text as they can. For example, 0+ will match as many zeros as it can from the first zero it finds; for example, 2.0005. Quantifiers can be made non-greedy.
Assertions
Assertions make a statement about the text at the point where they occur in the regular expression, but they do not match any characters. In the following list E stands for any expression.
Assertion | Description |
|---|---|
^ | The caret signifies the beginning of the string. If you wish to match an actual ^ you must escape it by writing \^. For example, ^#include will only match strings which begin with the characters '#include'. (When the caret is the first character of a character set it has a special meaning, see Sets of Characters.) |
$ | The dollar signifies the end of the string. For example, \d\s*$ will match strings which end with a digit optionally followed by whitespace. If you wish to match an actual $ you must escape it by writing \$. |
\b | A word boundary. For example, the regular expression \bOK\b means match immediately after a word boundary (e.g. start of string or whitespace) the letter 'O' then the letter 'K' immediately before another word boundary (e.g. end of string or whitespace). However, note that the assertion does not actually match any whitespace so if we write (\bOK\b) and we have a match, it will only contain 'OK' even if the string is “Its OK now”. |
\B | A non-word boundary. This assertion is true wherever \b is false. For example if we searched for \Bon\B in “Left on” the match would fail (space and end of string are not non-word boundaries), but it would match in “tonne”. |
(?=E) | Positive lookahead. This assertion is true if the expression matches at this point in the regular expression. For example, const(?=\s+char) matches 'const' whenever it is followed by 'char', as in 'static const char *'. (Compare with const\s+char, which matches 'static const char *'.) |
(?!E) | Negative lookahead. This assertion is true if the expression does not match at this point in the regular expression. For example, const(?!\s+char) matches 'const' except when it is followed by 'char'. |