← 学习库 Speech and Language Processing 本册目录

2.1.2 Disjunction, Grouping, and Precedence

Suppose we need to search for texts about pets; perhaps we are particularly interested in cats and dogs. In such a case we might want to search for either the string cat or the string dog. Since we can't use the square-brackets to search for "cat or dog" (why not?) we need a new operator, the disjunction operator, also called the pipe symbol |. The pattern /cat | dog/ matches either the string cat or the string dog.

Sometimes we need to use this disjunction operator in the midst of a larger sequence. For example, suppose I want to search for information about pet fish for my cousin David. How can I specify both guppy and guppies? We cannot simply say /guppy|ies/, because that would match only the strings guppy and ies. This is because sequences like guppy take precedence over the disjunction operator |. In order to make the disjunction operator apply only to a specific pattern, we need to use the parenthesis operators ( and ). Enclosing a pattern in parentheses makes it act like a single character for the purposes of neighboring operators like the pipe | and the Kleene*. So the pattern /gupp(y|ies)/ would specify that we meant the disjunction only to apply to the suffixes y and ies.

The parenthesis operator ( is also useful when we are using counters like the Kleene*. Unlike the | operator, the Kleene* operator applies by default only to a single character, not a whole sequence. Suppose we want to match repeated instances of a string. Perhaps we have a line that has column labels of the form Column 1 Column 2 Column 3. The expression /Column_[0-9]+_*/ will not match any column; instead, it will match a column followed by any number of spaces! The star here applies only to the space _ that precedes it, not the whole sequence. With the parentheses, we could write the expression / (Column_[0-9]+_*) * / to match the word Column, followed by a number and optional spaces, the whole pattern repeated any number of times.

This idea that one operator may take precedence over another, requiring us to sometimes use parentheses to specify what we mean, is formalized by the operator precedence hierarchy for regular expressions. The following table gives the order of RE operator precedence, from highest precedence to lowest precedence:

Parenthesis ()

Counters * + ? { }

Sequences and anchors the ^my end$

Disjunction |

Thus, because counters have a higher precedence than sequences, /the*/ matches theeeeee but not thethe. Because sequences have a higher precedence than disjunction, /the|any/ matches the or any but not theny.

Patterns can be ambiguous in another way. Consider the expression / [a-z]*/ when matching against the text once upon a time. Since / [a-z]*/ matches zero or more letters, this expression could match nothing, or just the first letter o, or on, or onc, or once. In these cases regular expressions always match the largest string they can; we say that patterns are greedy, expanding to cover as much of a string as they can.

原书第 26 页
← 2.1.1 Basic Regular Expression Patterns2.1.3 A Simple Example →