正规表达式
正规表达式由一个或多个字元型文字和/或元字元组成。在最简单的格式下,正规表达式仅由字元文字组成,如正规表达式 cat。它被读作字母 c,接着是字母 a 和 t,这种模式匹配 cat、location 和 catalog 之类的字元串。可以用它们验证数据、识别重複关键字的出现、检测不必要的空格、分析字元串、验证电话号码、邮政编码、电子邮件地址、社会安全号码、IP 地址、档案名称和路径名等的格式,也可以查找如 HTML 标记、数字、日期之类的模式,或任意文本数据中符合任意模式的任何事物,并用其它的模式来替换它们。
基本介绍
- 中文名:正规表达式
定义及介绍
正规表达式由一个或多个字元型文字和/或元字元组成。在最简单的格式下,正规表达式仅由字元文字组成,如正规表达式 cat。它被读作字母 c,接着是字母 a 和 t,这种模式匹配 cat、location 和 catalog 之类的字元串。元字元提供算法来确定 Oracle 如何处理组成一个正规表达式的字元。当您了解了各种元字元的含义时,您将体会到正规表达式用于查找和替换特定的文本数据是非常强大的。
验证数据、识别重複关键字的出现、检测不必要的空格,或分析字元串只是正规表达式的许多套用中的一部分。您可以用它们来验证电话号码、邮政编码、电子邮件地址、社会安全号码、IP 地址、档案名称和路径名等的格式。此外,您可以查找如 HTML 标记、数字、日期之类的模式,或任意文本数据中符合任意模式的任何事物,并用其它的模式来替换它们。
正规表达式
您可以使用最新引进的 Oracle SQL REGEXP_LIKE 操作符和 REGEXP_INSTR、REGEXP_SUBSTR 以及 REGEXP_REPLACE 函式来发挥正规表达式的作用。您将体会到这个新的功能如何对 LIKE 操作符和 INSTR、SUBSTR 和 REPLACE 函式进行了补充。实际上,它们类似于已有的操作符,但现在增加了强大的模式匹配功能。被搜寻的数据可以是简单的字元串或是存储在资料库字元列中的大量文本。正规表达式让您能够以一种您以前从未想过的方式来搜寻、替换和验证数据,并提供高度的灵活性。
基本例子
在使用这个新功能之前,您需要了解一些元字元的含义。句号 (.) 匹配一个正规表达式中的任意字元(除了换行符)。例如,正规表达式 a.b 匹配的字元串中首先包含字母 a,接着是其它任意单个字元(除了换行符),再接着是字母 b。字元串 axb、xaybx 和 abba 都与之匹配,因为在字元串中隐藏了这种模式。如果您想要精确地匹配以 a 开头和以 b 结尾的一条三个字母的字元串,则您必须对正规表达式进行定位。脱字元号 (^) 元字元指示一行的开始,而美元符号 ($) 指示一行的结尾(参见表1:附表见第4页)。因此, 正规表达式 ^a.b$ 匹配字元串 aab、abb 或 axb。将这种方式与 LIKE 操作符提供的类似的模式匹配 a_b 相比较,其中 (_) 是单字元通配符。
默认情况下,一个正规表达式中的一个单独的字元或字元列表只匹配一次。为了指示在一个正规表达式中多次出现的一个字元,您可以使用一个量词,它也被称为重複操作符。.如果您想要得到从字母 a 开始并以字母 b 结束的匹配模式,则您的正规表达式看起来像这样:^a.*b$。* 元字元重複前面的元字元 (.) 指示的匹配零次、一次或更多次。LIKE 操作符的等价的模式是 a%b,其中用百分号 (%) 来指示任意字元出现零次、一次或多次。
表 2 给出了重複操作符的完整列表。注意它包含了特殊的重複选项,它们实现了比现有的 LIKE 通配符更大的灵活性。如果您用圆括弧括住一个表达式,这将有效地创建一个可以重複一定次数的子表达式。例如,正规表达式 b(an)*a 匹配 ba、bana、banana、yourbananasplit 等。
Oracle 的正规表达式实施支持 POSIX (可移植作业系统接口)字元类,参见表 3 中列出的内容。这意味着您要查找的字元类型可以非常特别。假设您要编写一条仅查找非字母字元的 LIKE 条件 — 作为结果的 WHERE 子句可能不经意就会变得非常複杂。
POSIX 字元类必须包含在一个由方括弧 ([]) 指示的字元列表中。例如,正规表达式 [[:lower:]] 匹配一个小写字母字元,而 [[:lower:]] 匹配五个连续的小写字母字元。
除 POSIX 字元类之外,您可以将单独的字元放在一个字元列表中。例如,正规表达式 ^ab[cd]ef$ 匹配字元串 abcef 和 abdef。必须选择 c 或 d。
除脱字元 (^) 和连字元 (-) 之外,字元列表中的大多数元字元被认为是文字。正规表达式看起来很複杂,这是因为一些元字元具有随上下文环境而定的多重含义。^ 就是这样一种元字元。如果您用它作为一个字元列表的第一个字元,它代表一个字元列表的非。因此,[^[:digit:]] 查找包含了任意非数字字元的模式,而 ^[[:digit:]] 查找以数字开始的匹配模式。连字元 (-) 指示一个範围,正规表达式 [a-m] 匹配字母 a 到字母 m 之间的任意字母。但如果它是一个字元行中的第一个字元(如在 [-afg] 中),则它就代表连字元。
之前的一个例子介绍了使用圆括弧来创建一个子表达式;它们允许您通过输入更替元字元来输入可更替的选项,这些元字元由竖线 (|) 分开。
例如,正规表达式 t(a|e|i)n 允许字母 t 和 n 之间的三种可能的字元更替。匹配模式包括如 tan、ten、tin 和 Pakistan 之类的字,但不包括 teen、mountain 或 tune。作为另一种选择,正规表达式 t(a|e|i)n 也可以表示为一个字元列表 t[aei]n。表 4 汇总了这些元字元。虽然存在更多的元字元,但这个简明的概述足够用来理解这篇文章使用的正规表达式。
后向引用
正规表达式的一个有用的特性是能够存储子表达式供以后重用;这也被称为后向引用(在表 10 中对其进行了概述)。它允许複杂的替换功能,如在新的位置上交换模式或显示重複出现的单词或字母。子表达式的匹配部分保存在临时缓冲区中。缓冲区从左至右进行编号,并利用 \digit 符号进行访问,其中 digit 是 1 到 9 之间的一个数字,它匹配第 digit 个子表达式,子表达式用一组圆括弧来显示。
接下来的例子显示了通过按编号引用各个子表达式将姓名 Ellen Hildi Smith 转变为 Smith, Ellen Hildi。
SELECT REGEXP_REPLACE(
'Ellen Hildi Smith',
'(.*) (.*) (.*)', '\3, \1 \2')
FROM dual
REGEXP_REPLACE('EL
------------------
Smith, Ellen Hildi
该 SQL 语句显示了用圆括弧括住的三个单独的子表达式。每一个单独的子表达式包含一个匹配元字元 (.),并紧跟着 * 元字元,表示任何字元(除换行符之外)都必须匹配零次或更多次。空格将各个子表达式分开,空格也必须匹配。圆括弧创建获取值的子表达式,并且可以用 \digit 来引用。第一个子表达式被赋值为 \1 ,第二个 \2,以此类推。这些后向引用被用在这个函式的最后一个参数 (\3, \1 \2) 中,这个函式有效地返回了替换子字元串,并按期望的格式来排列它们(包括逗号和空格)。表 11 详细说明了该正规表达式的各个组成部分。
后向引用对替换、格式化和代替值非常有用,并且您可以用它们来查找相邻出现的值。接下来的例子显示了使用 REGEP_SUBSTR 函式来查找任意被空格隔开的重複出现的字母数字值。显示的结果给出了识别重複出现的单词 is 的子字元串。
SELECT REGEXP_SUBSTR(
'The final test is is the implementation',
'([[:alnum:]]+)([[:space:]]+)\1') AS substr
FROM dual
SUBSTR
------
is is
匹配参数选项
您可能已经注意到了正规表达式操作符和函式包含一个可选的匹配参数。这个参数控制是否区分大小写、换行符的匹配和保留多行输入。
实际套用
您不仅可以在伫列中使用正规表达式,还可以在使用 SQL 操作符或函式的任何地方(比如说在 PL/SQL 语言中)使用正规表达式。您可以编写利用正规表达式功能的触发器,以验证、生成或提取值。
接下来的例子演示了您如何能够在一次列检查约束条件中套用 REGEXP_LIKE 操作符来进行数据验证。它在插入或更新时检验正确的社会保险号码格式。如 123-45-6789 和 123456789 之类格式的社会保险号码对于这种列约束条件是可接受的值。有效的数据必须以三个数字开始,紧跟着一个连字元,再加两个数字和一个连字元,最后又是四个数字。另一种表达式只允许 9 个连续的数字。竖线符号 (|) 将各个选项分开。
ALTER TABLE students
ADD CONSTRAINT stud_ssn_ck CHECK
(REGEXP_LIKE(ssn,
'^([[:digit:]]-[[:digit:]]-[[:digit:]]|[[:digit:]])$'))
由 ^ 和 $ 指示的开头或结尾的字元都是不可接受的。确保您的正规表达式没有分成多行或包含任何不必要的空格,除非您希望格式如此并相应地进行匹配。表 12 说明了该正规表达式示例的各个组成部分。
功能比较
正规表达式有几个优点优于常见的 LIKE 操作符和 INSTR、SUBSTR 及 REPLACE 函式的。这些传统的 SQL 函式不便于进行模式匹配。只有 LIKE 操作符通过使用 % 和 _ 字元匹配,但 LIKE 不支持表达式的重複、複杂的更替、字元範围、字元列表和 POSIX 字元类等等。此外,新的正规表达式函式允许检测重複出现的单词和模式交换。这里的例子为您提供了正规表达式领域的一个概览,以及您如何能够在您的应用程式中使用它们。
丰富工具包
因为正规表达式有助于解决複杂的问题,所以它们是非常强大的。正规表达式的一些功能难于用传统的 SQL 函式来仿效。当您了解了这种稍显神秘的语言的基础构建程式块时,正规表达式将成为您的工具包的不可缺少的一部分(不仅在 SQL 环境下也在其它的程式语言环境下)。为了使您的各个模式正确,虽然尝试和错误有时是必须的,但正规表达式的简洁和强大是不容置疑的。
正规表达式详细定义
正规表达式(regular expression)描述了一种字元串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
列目录时, dir *.txt或ls *.txt中的*.txt就不是一个正规表达式,因为这里*与正规式的*的含义是不同的。
正规表达式是由普通字元(例如字元 a 到 z)以及特殊字元(称为元字元)组成的文字模式。正规表达式作为一个模板,将某个字元模式与所搜寻的字元串进行匹配。
1. 普通字元
由所有那些未显式指定为元字元的列印和非列印字元组成。这包括所有的大写和小写字母字元,所有数字,所有标点符号以及一些符号。
2. 非列印字元 字元 含义
\cx 匹配由x指明的控制字元。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字元。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字元,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字元。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
3. 特殊字元
所谓特殊字元,就是一些有特殊含义的字元,如上面说的"*.txt"中的*,简单的说就是表示任何字元串的意思。如果要查找档案名称中有*的档案,则需要对*进行转义,即在其前加一个\。ls \*.txt。正规表达式有以下特殊字元。
特别字元 说明
$ 匹配输入字元串的结尾位置。如果设定了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字元本身,请使用 \$。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字元,请使用 \( 和 \)。
* 匹配前面的子表达式零次或多次。要匹配 * 字元,请使用 \*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字元,请使用 \+。
. 匹配除换行符 \n之外的任何单字元。要匹配 .,请使用 \。
[ 标记一个中括弧表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字元,请使用 \?。
\ 将下一个字元标记为或特殊字元、或原义字元、或向后引用、或八进制转义符。例如, 'n' 匹配字元 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字元串的开始位置,除非在方括弧表达式中使用,此时它表示不接受该字元集合。要匹配 ^ 字元本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。
构造正规表达式的方法和创建数学表达式的方法一样。也就是用多种元字元与操作符将小的表达式结合在一起来创建更大的表达式。正规表达式的组件可以是单个的字元、字元集合、字元範围、字元间的选择或者所有这些组件的任意组合。
4. 限定符
限定符用来指定正规表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或或{n,}或{n,m}共6种。
*、+和?限定符都是贪婪的,因为它们会儘可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。
正规表达式的限定符有:
字元 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
n 是一个非负整数。匹配确定的 n 次。例如,'o' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
5. 定位符
用来描述字元串或单词的边界,^和$分别指字元串的开始与结束,\b描述单词的前或后边界,\B表示非单词边界。不能对定位符使用限定符。
6. 选择
用圆括弧将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括弧会有一个副作用,是相关的匹配会被快取,此时可用?:放在第一个选项前来消除这种副作用。
其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括弧内的正规表达式模式的位置来匹配搜寻字元串,后者为负向预查,在任何开始不匹配该正规表达式模式的位置来匹配搜寻字元串。
7. 后向引用
对一个正规表达式模式或部分模式两边添加圆括弧将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正规表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。
可以使用非捕获元字元 '?:', '?=', or '?!' 来忽略对相关匹配的保存。