第六章 疯狂Caché 正则表达式(一)

第六章 Caché正则表达式(一)

Caché支持正则表达式与以下CachéObjectScript函数$LOCATE$MATCH以及%Regex.Matcher类的方法一起使用。

所有其他Caché子字符串匹配操作都使用Caché模式匹配运算符。

本章介绍正则表达式的以下功能:

  • 通配符和限定符。示例:.*匹配任意数量的任意类型的字符。
  • 文字和字符范围。示例:[A-Z]匹配A到Z范围内的单个大写字符。
  • 字符类型元字符是与一组字符匹配的序列:
    • 单字母字符类型。示例:\d匹配任何数字字符。
    • Unicode属性字符类型。示例:\P{LL}匹配任何小写字母。
    • POSIX字符类型。示例:[:Print:]匹配任何可打印字符。
  • GROUPING构造使用括号重复应用正则表达式。示例:(\P{LL})+检查每个字符以确定它是否为小写字母。
  • 限制匹配位置的锚点。示例:\B(Day)仅匹配在单词边界出现的那些“day”
  • 逻辑运算符。示例:[[:UPPER:]&&[:希腊语:]]匹配大写希腊字母。
  • 字符表示元字符是与单个字符匹配的序列。
    • 十六进制、八进制和Unicode表示法。示例:\x5A是字母Z的十六进制表示法。
    • 控制字符表示。示例:\cM是回车控制字符。
    • 符号名称表示法。示例:\n{等号}是=字符。
  • 模式。示例:(?i)使所有后续匹配不区分大小写。
  • 注释。示例:(?#日期和24小时制)将此注释插入正则表达式字符串。
  • 错误消息。

正则表达式的Caché实现基于正则表达式的国际Unicode组件(ICU)标准。熟悉Perl正则表达式的用户会发现它与Caché实现有许多相似之处。

通配符和限定符

通配符和限定符 描述
. 通配符。匹配任何类型的任何单个字符,行距字符$CHAR(10)$CHAR(11)$CHAR(12)$CHAR(13)$CHAR(133)除外。可以通过指定(?s)单行模式(如本参考页后面所述)来覆盖这种行距字符的排除。可以单独使用“..”=任意两个字符,或组合使用“\d..”=数字字符后跟任意类型的任意两个字符。可以与后缀组合(具有相同的行距字符限制):.?=零个或一个任意类型的字符。.*=任何类型的零个或多个字符。.+=任意类型的一个或多个字符。.{3}=恰好3个任意类型的字符。要结束通配符序列,请使用反斜杠(\)前缀对下一个文字进行转义。例如,regexp\“. * \H\d{2}\”匹配以字母“H”后跟两位数字结尾的任意类型字符的字符串。
? 单字符后缀(0或1)。对字符串应用regexp 1次或0次。正则表达式“\d?”、“[0-9]?”或“[[:digit:]]?”全部匹配到单个数字或空字符串。正则表达式“.?(Log)”可以匹配“blog”(1次)或“log”(0次)。正则表达式“abc?”可以匹配“abc”或“ab”。
+ 重复后缀(1个或更多)。对字符串应用regexp一次或多次。例如,“A+”与字符串“AAAAA匹配。“.+”匹配任何字符类型的任意长度的字符串,但与空字符串不匹配。正则表达式“\d+”、“[0-9]+”或“[[:digit:]]+”都匹配任意长度的数字字符串。可以对复杂的重复模式使用括号。例如,(AB)+“匹配字符串”ABABABAB“;”(\d\s)+“匹配一个空格交替的任意长度的三个数字的序列。
* 重复后缀(0或更多)。对字符串应用regexp零次、一次或多次。例如,“A*”匹配字符串“A”、“AAAAA”和空字符串。“. *”匹配任何字符类型的任意长度的字符串,包括空字符串。正则表达式“\d *”、“[0-9] *”或“[[:digit:]] *”都匹配任意长度的数字字符串或空字符串。可以对复杂的重复模式使用括号。例如,(AB) *“与字符串”ABABABAB“匹配;”(\d\s) *“与一个空格交替的任意长度的三个数字的序列匹配。
{n} 量化后缀(n倍)。{n}后缀恰好应用regexp n次。例如,“\d{5}”匹配任何五位数字。
{n,} 量化后缀(至少n次)。后缀{n,}应用regexp n次或更多次。例如,“\d{5,}”匹配具有五位或五位以上数字的任何数字。
{n,m} 量化后缀(范围)。后缀{n,m}最少应用regexp n次,最多应用m次(含)。例如,“\d{7,10}”匹配至少7位但不超过10位的任意数字。

文字和字符范围

大多数文字字符可以简单地包含在正则表达式中。例如,正则表达式\“.*G*\”指定字符串必须包含字母G。

一些文字字符也用作正则表达式元字符。必须在要被视为文字字符的元字符之前使用转义前缀(反斜杠字符)。以下文字字符需要转义前缀:美元符号\$;星号\*;加号\+;句点\.;问号\?;反斜杠\\;脱字符\^;竖线\|;左括号和右方括号\[\];左花括号和右花括号\{\}。右方括号]并不总是需要转义前缀;为清晰和一致起见,应使用转义前缀。

引号字符不带转义前缀;要指定单引号字符,请使用双引号“”

以下是为文字指定多个正则表达式匹配的方法:

代码 描述
[x] 指定的字符或字符列表。因此,[A]表示只有大写字母字符“A”匹配,而[ACE]匹配字母ACE中的任何一个。字符可以按任意顺序列出。允许重复字符。可以使用脱字符(^)指定反转;例如,[^A]表示除“A”之外的任何字符都是匹配的;[^XYZ]表示除了XYZ之外的任何字符都是匹配的。默认情况下,这些字符匹配区分大小写。通过在字符匹配前面加上(?i)模式修饰符,可以使字符匹配不区分大小写。要将插入符号(^)指定为文字匹配字符,它不能是列表中的第一个字符。要将连字符($CHAR(45))指定为文字匹配字符,它必须是列表中的第一个或最后一个字符。要将右括号(])指定为文字匹配字符,它必须是列表中的第一个字符。(第一个字符可以表示^逆运算符之后的第一个字符)。也可以使用反斜杠转义前缀文字;例如,[\\AB\[CD]匹配反斜杠(\)、左方括号([)以及字母ABCD
[x-z] x开始,以z结束的指定字符范围(包括xz)。虽然通常用于字母或数字,但任何升序ASCII序列都可以用作范围。因此,[A-Z]是所有大写字母的范围。[A-z]是一个范围,它不仅包括所有大小写字母,还包括字母之间的六个ASCII标点字符。指定不在ASCII升序中的范围会生成<正则表达式>错误。还可以指定多个范围。因此,[A-Za-z]是所有大小写字母的范围。可以使用脱字符(^)作为左方括号后的第一个字符来指定反转;例如,[^A-F]表示除AF之外的所有字符。插入符号指定所有指定范围的反转;因此[^A-Za-z]表示除字母之外的任何字符。字符范围和单个字符列表可以按任意顺序组合。因此,[abca-fXYZ0-9]匹配指定的字符和指定范围内的字符。
(str) (str1 str2) OR逻辑运算符(` )分隔的指定字符串或字符串列表。因此,(William)在字符串中匹配这个完全相同的子字符串,并且(William Willy Wm. Bill)匹配这些子字符串中的任何一个。可以使用转义前缀|将竖线指定为字符串中的文字。默认情况下,这些子字符串匹配区分大小写。通过在子字符串前面加上(?i)模式修饰符,可以使子字符串匹配不区分大小写。默认情况下,这些子字符串匹配可以出现在字符串中的任何位置。通过在单词边界前面加上\b`,可以将匹配的子字符串限制为出现在单词边界处。

字符类型元字符

Caché正则表达式支持三组字符类型元字符集:

  • 单字母字符类型。例如:\d
  • Unicode属性字符类型。例如:\P{LL}
  • POSIX字符类型。例如[:Alpha:]
    这些字符类型元字符可以在任何正则表达式中以任意组合使用。

单字母字符类型

单字母字符类型的元字符由反斜杠(\)字符后跟字母表示。字符类型由小写字母指定(\d=数字:0到9)。对于那些支持反转的字符类型,大写字母指定字符类型的反转(\D=除数字之外的任何字符)。

单字母字符类型 描述
\a bell形字符$CHAR(7)。不支持反转。
\d 数字字符。数字0到9。倒数是\D
\e 转义字符$CHAR(27)。不支持反转。
\f 换页字符$CHAR(12)。不支持反转。
\n 换行符$CHAR(10)。不支持反转。
\r 回车字符$CHAR(13)。不支持反转。
\s 空格字符。空格、制表符或行距字符,包括以下字符:$CHAR(9)$CHAR(10)$CHAR(11)$CHAR(12)$CHAR(13)$CHAR(32)$CHAR(133)$CHAR(160)。倒数是\S
\t 制表符$CHAR(9)。不支持反转。
\w 一个单词字符。单词字符可以是字母、数字或下划线字符。有效字母包括大写和小写字母,包括Unicode字母。它们包括以下扩展ASCII字符:$CHAR(170)$CHAR(181)$CHAR(186)$CHAR(192)$CHAR(214)$CHAR(216)$CHAR(246)$CHAR(248)$CHAR(256)。相反的是\W。

\d\s\w元字符还匹配$CHAR(256)以外的相应Unicode字符。

Unicode属性字符类型

Unicode属性字符类型匹配将单个字符与使用以下语法指定的字符类型匹配:

\p{prop} 

例如,\p{LL}匹配任何小写字母。道具关键字由一个或两个字母字符组成;道具关键字不区分大小写。单字母道具关键字是最具包容性的;两个字母道具关键字指定一个子集。

反之为\P{prop}。例如,\P{LL}匹配任何不是小写字母的字符。

下表显示了与前256个字符的每个道具关键字匹配的字符(为与256个字符中的任何字符都不匹配的道具关键字提供了一个示例Unicode字符):

  • C:控制字符和其他字符0-31、127-159、173
    -CC:控制字符0-31、127-1593
  • CF:格式化字符173
  • CN:未分配的代码点(例如,888)
  • CO:专用字符(例如,57344)
  • S:代理(例如,55296)
  • L:字母65-90、97-122、170、181、186、192-214、216-246、248-255
  • LH:原来是小写字母97-122,170,181,186,223-246,248-255
  • LM:修饰符(例如,688)
  • LO:不是LL、LU、LT或LM的其他字母(例如,443)
  • LT:大小写字母(例如453) 大写字母 65-90, 192–214, 216–222
  • M:标记(例如,768)

  • MC:修改字符(例如,2307)

  • ME:括起来的标记(例如,1160)

  • MN:重音符号(例如,768)

  • N:48-57,178-179,185,188-190

  • ND:十进制数48-57
    -NL:代表数字的字母(例如,5870)

  • NO:数字下标和分数178-179、185、188-190

  • P:标点符号33-35、37-42、44-47、58-59、63-64、91-93、95、123、125、161、171、183、187、191
  • PC:连接标点符号95
  • PD:破折号45
  • PE:结束标点符号41,93,125
  • PS:开始标点符号40,91,1235
  • PI:首标171
  • PF:尾标1875
  • PO:其他标点符号33-35,37-39,42,44,46-47,58-59,63-64,92,161,183,1915
  • S:36、43、60-62、94、96、124、126、162-169、172、174-177、180、182、184、215、247
  • SC:货币符号36、162-165
  • SK:组合符号94、96、168、175、180、184
  • SM:数学符号43,60-62,124,126,172,177,215,247
  • SO:其他符号166-167,169,174,176,182
  • Z:分隔符32、160
  • ZL:行分隔符(例如,8232)
  • ZP:段落分隔符(例如,8233)
  • ZS:空格字符32,160

可以使用以下代码来确定哪些字符与道具关键字匹配:
java

  READ prop#2:10
  READ rangefrom:10
  READ rangeto:10
  FOR i=rangefrom:1:rangeto {
      IF $MATCH($CHAR(i),"\p{"_prop_"}")=1 {
         WRITE i,"=",$CHAR(i),!} }

POSIX字符类型

POSIX语法使用以下语法形式之一将单个字符与ptype关键字指定的字符类型进行匹配:

\p{ptype}
[:ptype:]

例如,[:lower:]\p{lower}匹配任何小写字母。可以按如下方式指定反转(匹配除小写字母以外的任何字母):[:^lower:]\P{lower}

ptype关键字不区分大小写。一般的ptype关键字有:

  • alnum — 字母和数字。
  • alpha — 字母
  • blank — 制表符$CHAR(9)或空格$CHAR(32)$CHAR(160)
  • cntrl — 控制字符:$CHAR(0)$CHAR(31)$CHAR(127)$CHAR(159)
  • digit — 数字0到9。
  • graph — 可打印字符,不包括空格字符:$CHAR(33)$CHAR(126)$CHAR(161)至$CHAR(156)
  • lower — 小写字母
  • math — 数学字符(符号的子集)。包括以下字符: +<=>^|~¬±×÷
  • print — 可打印字符,包括空格字符:$CHAR(32)$CHAR(126)$CHAR(160)$CHAR(156)
  • punct — 标点符号(不包括符号字符)。包括以下字符: !"#%&'()*,-./:;?@[\]_{}¡«·»¿
  • space — 间距字符,包括空格、制表符和行距字符,包括以下字符:$CHAR(9)$CHAR(10)$CHAR(11)$CHAR(12)$CHAR(13)$CHAR(32)$CHAR(133)$CHAR(160)
  • symbol — 符号字符(不包括标点符号字符)。包括以下字符: $+<=>^``|~¢£¤¥¦§¨©¬®¯°±´¶¸×÷
  • upper — 大写字母
    -xdigit — 十六进制数字:数字0到9,大写字母A到F,小写字母a到f。

此外,还可以使用ptype指定Unicode类别。

例如, [:greek:]匹配Unicode希腊语类别中的任何字符(这包括在$CHAR(900)$CHAR(974)范围内找到的希腊字母)。这些POSIX Unicode类别的部分列表包括[:arabic:], [:cyrillic:], [:greek:], [:hebrew:], [:hiragana:], [:katakana:], [:latin:], [:thai:]。例如,这些Unicode类别也可以表示为 [:script=greek:]

下面的示例使用POSIX匹配来比较前256个字符中的[:Letter:]字符集和[:latin:] 字符集。它们只有一个字符不同,即$CHAR(181)

   FOR i=0:1:255 {
     SET letr="foo"
     IF 1=$MATCH($CHAR(i),"[:letter:]") {
      SET letr=$CHAR(i)}
     IF 1=$MATCH($CHAR(i),"[:latin:]") {
          SET lat=$CHAR(i)}
      ELSE {SET lat="foo"}
     IF letr '= lat {WRITE i," ",$CHAR(i),!}
   }

分组构造

可以使用圆括号指定重复应用的文字或元字符序列。例如,正则表达式([0-9])+测试字符串中的每个连续字符以确定它是否是数字。

以下示例显示了此用法:

  WRITE $MATCH("4567683285759","([0-9])+"),!
      // 测试所有数字,没有空字符串
  WRITE $MATCH("4567683285759","([0-9])*"),!
      // 测试所有数字或空字符串
  WRITE $MATCH("Now is the time","\p{LU}(\p{L}|\s)+"),!
      // 测试首字母大写,然后测试所有字母或空格
  WRITE $MATCH("MAboston-9a","\p{LU}{2}(\p{LL}|\d|\-)*"),!
      // 测试2个大写字母,然后测试所有小写字母、数字、破折号或“”
  WRITE $MATCH("1^23^456^789","([0-9]+\^?)+"),!
      // 测试后跟0或1^个字符的一个或多个数字,重复应用测试
  WRITE $MATCH("$1,234,567,890.99","\$([0-9]+,?)+\.\d\d")
      // 测试$,然后是数字,然后是0或1逗号,然后是小数点,最后是2个小数位
1
1
1
1
1
1

下面的警示性示例显示重复应用的分组构造的执行时间如何根据模式匹配错误在字符串中的位置快速增加。在声明不匹配之前必须测试的排列越多,执行时间就越长:

  SET a=$ZHOROLOG
    WRITE $MATCH("1111111111,2222222222,3333333333","([0-9]+,?)+")
    SET b=$ZHOROLOG-a
    WRITE " duration: ",b,!
  SET a=$ZHOROLOG
    WRITE $MATCH("11111x11111,2222222222,3333333333","([0-9]+,?)+")
    SET b=$ZHOROLOG-a
    WRITE " duration: ",b,!
  SET a=$ZHOROLOG
    WRITE $MATCH("1111111111,22x22222222,3333333333","([0-9]+,?)+")
    SET b=$ZHOROLOG-a
    WRITE " duration: ",b,!
  SET a=$ZHOROLOG
    WRITE $MATCH("1111111111,2222222x222,3333333333","([0-9]+,?)+")
    SET b=$ZHOROLOG-a
    WRITE " duration: ",b,!
  SET a=$ZHOROLOG
    WRITE $MATCH("1111111111,22222222x22,3333333333","([0-9]+,?)+")
    SET b=$ZHOROLOG-a
    WRITE " duration: ",b
1 duration: .000023
0 duration: .000017
0 duration: .007313
0 duration: .702768
0 duration: 1.89103

锚元字符

锚点是一个元字符,它将与其关联的正则表达式匹配限制到匹配字符串中的特定位置。例如,匹配只能出现在字符串的开头或结尾,或字符串中的空格字符之后。

字符串开始或结束

这些锚点将匹配限制在字符串的开头或结尾。

  • ^\A 字符串锚定前缀的开始。指示正则表达式匹配必须出现在字符串的开头。
  • $ 字符串末尾锚定后缀。指示正则表达式匹配必须出现在字符串末尾。行尾字符(ASCII 10、11、12或13)将被忽略。与\Z相同。
  • \Z 字符串末尾锚定后缀。指示正则表达式匹配必须出现在字符串末尾。行尾字符(ASCII 10、11、12或13)将被忽略。和$一样。
  • \z 字符串末尾锚定后缀。指示正则表达式匹配必须出现在字符串末尾。行尾字符(ASCII 10、11、12或13)被视为字符串字符进行匹配。

以下示例显示字符串锚点开头如何限制$LOCATE匹配:

   SET str="ABCDEFG"
   WRITE $LOCATE(str,"A"),!   
   WRITE $LOCATE(str,"D"),!   
   WRITE $LOCATE(str,"^A"),!  
   WRITE $LOCATE(str,"^D"),!  
1
4
1
0

以下示例显示字符串尾锚点如何限制$LOCATE匹配:

   SET str="ABCDABCD"
   WRITE $LOCATE(str,"(ABC)"),!   
   WRITE $LOCATE(str,"D"),!       
   WRITE $LOCATE(str,"(ABC)$"),!  
   WRITE $LOCATE(str,"(ABCD)$"),! 
   WRITE $LOCATE(str,"D$"),!      
1
4
0
5
8

以下示例显示字符串尾锚点如何处理换行符:

   SET str="ABCDEFG"_$CHAR(10)

   WRITE $LOCATE(str,"G$"),!                   
   WRITE $LOCATE(str,"G"_$CHAR(10)_"$"),!      
   WRITE $LOCATE(str,$CHAR(10)_"$"),!!         

   WRITE $LOCATE(str,"G\Z"),!                 
   WRITE $LOCATE(str,"G"_$CHAR(10)_"\Z"),!     
   WRITE $LOCATE(str,$CHAR(10)_"\z"),!!        

   WRITE $LOCATE(str,"G\z"),!                  
   WRITE $LOCATE(str,"G"_$CHAR(10)_"\z"),!     
   WRITE $LOCATE(str,$CHAR(10)_"\z"),!         s
7
7
8

7
7
8

0
7
8

/// d ##class(PHA.TEST.ObjectScript).TestStartEnd()
ClassMethod TestStartEnd()
{
   SET str="ABCDEFG"
   WRITE $LOCATE(str,"G$"),! 
   WRITE $LOCATE(str,"FG$"),!    
   WRITE $LOCATE(str,"EF$"),!   
   WRITE $LOCATE(str,"^A"),!  
   WRITE $LOCATE(str,"^AB"),! 
   WRITE $LOCATE(str,"^CD"),!
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestStartEnd()
7
6
0
1
1
0
 

字词边界

可以将匹配限制为单词边界处的匹配项。单词边界由非单词字符旁边的单词字符或字符串开头的单词字符标识。单词字符是与\w字符类型匹配的字符:字母、数字和下划线字符。通常,这是位于字符串开头或空格字符或其他标点符号之后的单词的第一个字母。单词边界的正则表达式语法为:

  • \b匹配位于非单词字符/单词字符边界的匹配项,或匹配字符串开头的单词字符。
  • \B(相反)匹配单词字符/单词字符边界或非单词字符/非单词字符边界的匹配项。

下面的示例使用\b匹配以子字符串“in”“un”开头的单词边界:

  SET str(1)="unlucky"          // match: "un" is at start of string
  SET str(2)="highly unlikely"  // match: "un" follows a space character
  SET str(3)="fall in place"    // match: "in" can be followed by a space
  SET str(4)="the %integer"     // match: % is a non-word character
  SET str(5)="down-under"       // match: - is a non-word character
  SET str(6)="winning"          // no match: "in" preceded by word character
  SET str(7)="the 4instances"   // no match: a number is a word character
  SET str(8)="down_under"       // no match: an underscore is a word character
  FOR i=1:1:8 {
      WRITE $MATCH(str(i),".*\b[iu]n.*")," string",i,!
      }
1 string1
1 string2
1 string3
1 string4
1 string5
0 string6
0 string7
0 string8

下面的示例在正则表达式不在单词边界时使用\B查找该正则表达式:

   SET str(1)="the thirteenth item"
   WRITE $LOCATE(str(1),"\Bth")   // returns 13 ("th" preceded by a word character)
   SET str(2)="the^thirteenth^item"
13

以下示例显示如何在未指定单词字符的正则表达式中使用\b\B

   SET str(1)="this##item"
   WRITE $LOCATE(str(1),"\b#"),!   // returns 5 (the first # at a word boundary)
   WRITE $LOCATE(str(1),"\B#")     // returns 6 (the first # not at a word boundary)
5
6

你可能感兴趣的:(第六章 疯狂Caché 正则表达式(一))