#include <qregexp.h>
Regular expressions, "regexps", provide a way to find patterns within text. This is useful in many contexts, for example:
We present a very brief introduction to regexps, a description of Qt's regexp language, some code examples, and finally the function documentation. QRegExp is modelled on Perl's regexp engine and fully supports Unicode. QRegExp may also be used in the weaker 'wildcard' (globbing) mode which works in a similar way to command shells. A good text on regexps is Mastering Regular Expressions: Powerful Techniques for Perl and Other Tools by Jeffrey E. Friedl, ISBN 1565922573.
Experienced regexp users may prefer to skip the introduction and go directly to the relevant information:
Introduction
Regexps are built up from expressions, quantifiers and assertions. The simplest form of expression is simply a character, e.g. x or 5. An expression can also be a set of characters. For example, [ABCD], will match an A or a B or a C or a D. As a shorthand we could write this as [A-D]. If we want to match any of the captital letters in the English alphabet we can write [A-Z]. A quantifier tells the regexp 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. We'll look at assertions and more complex expressions later. Note that regexps cannot be used to check for balanced brackets or tags (unless you know the maximum level of nesting).
We'll start by writing a regexp to match integers in the range 0 to 99. We will require at least one digit so we will start with [0-9]{1,1} which means match a digit exactly once. This regexp alone will match integers in the range 0 to 9. To match one or two digits we can increase the maximum number of occurrences so the regexp becomes [0-9]{1,2} meaning match a digit at least once and at most twice. However, this regexp as it stands will not match correctly. This regexp will match one or two digits within a string. To ensure that we match against the whole string we must use the anchor assertions. We need ^ (caret) which when it is the first character in the regexp means that the regexp must match from the beginning of the string. And we also need $ (dollar) which when it is the last character in the regexp means that the regexp must match until the end of the string. So now our regexp is ^[0-9]{1,2}$. Note that assertions do not match any characters.
If you've seen regexps elsewhere they may have looked different from the one 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 . The quantifier to match exactly one occurrence, {1,1}, can be replaced with the expression itself. This means that x{1,1} is exactly the same as x alone. So our 0 to 99 matcher could be written: ^{1,2}$, although most people would write it ^?$. The ? is the same as the quantifier {0,1}, i.e. a minimum of no occurrences a maximum of one occurrence. This is used to make an expression optional. The regexp ^?$ means "from the beginning of the string match one digit followed by zero or one digits and then the end of the string".
Our second example is matching the words 'mail', 'letter' or 'correspondence' but without matching 'email', 'mailman', 'mailer', 'letterbox' etc. We'll start by just matching 'mail'. In full the regexp is, m{1,1}a{1,1}i{1,1}l{1,1}, but since an 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 regexp now becomes mail|letter|correspondence which means match 'mail' or 'letter' or 'correspondence'. Whilst this regexp will find the words we want it will also find words we don't want such as 'email'. We will start by putting our regexp in parenthesis (mail|letter|correspondence). Parenthesis have two effects, firstly they group expressions together and secondly they identify parts of the regexp that we wish to capture. Our regexp still matches any of the three words but now they are grouped together as a unit. This is useful for building up more complex regexps. It is also useful because it allows us to examine which of the words actually matched. We need to use another assertion, this time
"word boundary": (mail|letter|correspondence)
. This regexp means "match a word boundary followed by the expression in parenthesis followed by another word boundary". The
assertion matches at a position in the regexp not a character in the regexp. A word boundary is any non-word character such as a space a newline or the beginning or end of the string.
For our third example we want to replace ampersands with the HTML entity '&'. The regexp to match is simple: &, i.e. match one ampersand. Unfortunately this will mess up 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 and our regexp becomes: &(?!amp;). The negative lookahead assertion is introduced with '(?!' and finishes at the ')'. It means that the text it contains, 'amp;' in our example, must not follow the expression that preceeds it.
Regexps 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 regexps to match these are \b(Eric|Eirik)\b and \bEi?ri[ck]\b. We need the word boundary '' so we don't get 'Ericsson' etc. The second regexp actually matches more than we want, 'Eric', 'Erik', 'Eiric' and 'Eirik'.
We will implement some the examples above in the code examples section.
Characters and Abbreviations for Sets of Characters
Note that the C++ compiler transforms backslashes in strings so to include a \ in a regexp you will need to enter it twice, i.e. \\.
Square brackets are used to match any character in the set of characters contained within the square brackets. 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.
Using the predefined character set abbreviations is more portable than using character ranges across platforms and languages. For example, [0-9] matches a digit in Western alphabets but matches a digit in any alphabet.
Note that in most regexp literature sets of characters are called "character classes".
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 or an abbreviation for a set of characters or a set of characters in square brackets or any parenthesised expression.
(MAXINT is implementation dependent but will not be smaller than 16384.)
If we wish to apply a quantifier to more than just the preceeding character we can use parenthesis 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 that 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, e.g. '2.<u>000</u>5'. Quantifiers can be made non-greedy, see setMinimal().
Capturing Text
Parenthesis allow us to group elements together so that we can quantify and capture them. For example if we have the expression mail|letter|correspondence that matches a string we know that one of the words matched but not which one. Using parenthesis allows us to "capture" whatever is matched within their bounds, so if we used (mail|letter|correspondence) and matched this regexp against the string "I sent you some email" we can use the cap() or capturedTexts() functions to extract the matched characters, in this case 'mail'.
We can use captured text within the regexp itself. To refer to the captured text we use backreferences which are indexed from 1 the same as for cap(). For example we could search for duplicate words in a string using (+)+
which means match a word boundary followed by one or more word characters followed by one or more non-word characters followed by the same text as the first parenthesised expression followed by a word boundary.
If we want to use parenthesis purely for grouping and not for capturing we use the non-capturing syntax, e.g. (?:green|blue). Non-capturing parenthesis begin '(?:' and end ')'. In this example we match either 'green' or 'blue' but we do not capture the match so we can only know whether or not we matched but not which color we actually found. Using non-capturing parenthesis is more efficient than using capturing parenthesis since the regexp engine has to do less book-keeping.
Both capturing and non-capturing parenthesis may be nested.
Assertions make some statement about the text at the point where they occur in the regexp but they do not match any characters. In the following list E stands for any expression.
Most command shells such as bash or cmd support "file globbing", the ability to identify a group of files by using wildcards. Wildcard matching is much simpler than full regexps and has only four features:
For example if we are in wildcard mode and have strings which contain filenames we could identify HTML files with *.html. This will match zero or more characters followed by a dot followed by 'h', 't', 'm' and 'l'.
Most of the character class abbreviations supported by Perl are supported by QRegExp, see characters and abbreviations for sets of characters.
QRegExp's quantifiers are the same as Perl's greedy quantifiers. Non-greedy matching cannot be applied to individual quantifiers, but can be applied to all the quantifiers in the pattern. For example, to match the Perl regex ro+?m requires:
The equivalent of Perl's /i option is setCaseSensitive(FALSE).
Perl's /g option can be emulated using a loop.
In QRegExp . matches any character, therefore all QRegExp regexps have the equivalent of Perl's /s option. QRegExp does not have an equivalent to Perl's /m option, but this can be emulated in various ways for example by splitting the input into lines or by looping with a regexp that searches for newlines.
Because QRegExp is string oriented there are no , or assertions. The assertion is not supported but can be emulated in a loop.
Perl's $& is cap(0) or capturedTexts()[0]. There are no QRegExp equivalents for $`, $' or $+. $1, $2 etc correspond to cap(1) or capturedTexts()[1], cap(2) or capturedTexts()[2], etc.
To substitute a pattern use QString::replace().
Perl's extended /x syntax is not supported, nor are regexp comments (?#comment) or directives, e.g. (?i).
Both zero-width positive and zero-width negative lookahead assertions (?=pattern) and (?!pattern) are supported with the same syntax as Perl. Perl's lookbehind assertions, "independent" subexpressions and conditional expressions are not supported.
Non-capturing parenthesis are also supported, with the same (?:pattern) syntax.
See QStringList::split() and QStringList::join() for equivalents to Perl's split and join functions.
Note: because C++ transforms \'s they must be written twice in code, e.g. \b must be written \\b.
QRegExp rx( "^\\d\\d?$" ); // Match integers 0 to 99
rx.search( "123" ); // Returns -1 (no match)
rx.search( "-6" ); // Returns -1 (no match)
rx.search( "6" ); // Returns 0 (matched as position 0)
The third string matches '<u>6</u>'. This is a simple validation regexp for integers in the range 0 to 99.
QRegExp rx( "^\\S+$" ); // Match strings which have no whitespace
rx.search( "Hello world" ); // Returns -1 (no match)
rx.search( "This_is-OK" ); // Returns 0 (matched at position 0)
The second string matches '<u>This_is-OK</u>'. We've used the character set abbreviation '' (non-whitespace) and the anchors to match strings which contain no whitespace.
In the following example we match strings containing 'mail' or 'letter' or 'correspondence' but only match whole words i.e. not 'email'
QRegExp rx( "\\b(mail|letter|correspondence)\\b" );
rx.search( "I sent you an email" ); // Returns -1 (no match)
rx.search( "Please write the letter" ); // Returns 17 (matched at position 17)
The second string matches "Please write the <u>letter</u>". The word 'letter' is also captured (because of the parenthesis). We can see what text we've captured like this:
QString captured = rx.cap( 1 ); // captured contains "letter"
This will capture the text from the first set of capturing parenthesis (counting capturing left parenthesis from left to right). The parenthesis are counted from 1 since cap( 0 ) is the whole matched regexp (equivalent to '&' in most regexp engines).
Here we've passed the QRegExp to QString's replace() function to replace the matched text with new text.
QString str = "One Eric another Eirik, and an Ericsson. How many Eiriks, Eric?";
QRegExp rx( "\\b(Eric|Eirik)\\b" ); // Match Eric or Eirik
int pos = 0; // Where we are in the string
int count = 0; // How many Eric and Eirik's we've counted
while ( pos >= 0 ) {
pos = rx.search( str, pos );
if ( pos >= 0 ) {
pos++; // Move along in str
count++; // Count our Eric or Eirik
}
}
We've used the search() function to repeatedly match the regexp in the string. Note that instead of moving forward by one character at a time pos++ we could have written pos += rx.matchedLength() to skip over the already matched string. The count will equal 3, matching 'One <u>Eric</u> another <u>Eirik</u>, and an Ericsson. How many Eiriks, <u>Eric</u>?'; it doesn't match 'Ericsson' or 'Eiriks' because they are not bounded by non-word boundaries.
One common use of regexps is to split lines of delimited data into their component fields.
str = "Trolltech AS\twww.trolltech.com\tNorway";
QString company, web, country;
rx.setPattern( "^([^\t]+)\t([^\t]+)\t([^\t]+)$" );
if ( rx.search( str ) != -1 ) {
company = rx.cap( 1 );
web = rx.cap( 2 );
country = rx.cap( 3 );
}
In this example our input lines have the format company name, web address and country. Unfortunately the regexp is rather long and not very versatile -- the code will break if we add any more fields. A simpler and better solution is to look for the separator, '' in this case, and take the surrounding text. The QStringList split() function can take a separator string or regexp as an argument and split a string accordingly.
QStringList field = QStringList::split( "\t", str );
Here field[0] is the company, field[1] the web address and so on.
To immitate the matching of a shell we can use wildcard mode.
Wildcard matching can be convenient because of its simplicity, but any wildcard regex can be defined using full regexps, e.g. .*\.html$. Notice that we can't match both .html and .htm files with a wildcard unless we use *.htm* which will also match 'test.html.bak'. A full regexp gives us the precision we need, .*\.html?$.
QRegExp can match case insensitively using setCaseSensitive(), and can use non-greedy matching, see setMinimal(). By default QRegExp uses full regexps but this can be changed with setWildcard(). Searching can be forward with search() or backward with searchRev(). Captured text can be accessed using capturedTexts() which returns a string list of all captured strings, or using cap() which returns the captured string for the given index. The pos() function takes a match index and returns the position in the string where the match was made (or -1 if there was no match).
<a name="member-function-documentation"/>
1.4.2