第五章 疯狂Caché 运算符和表达式(四)
模式匹配

Caché支持两种模式匹配系统:

  • 这里描述的Caché模式匹配是一种用问号()分隔模式字符串开头的语法。或(‘?)。
  • 正则表达式,许多软件供应商支持的模式匹配语法。正则表达式可以与$LOCATE$MATCH函数以及%Regex.Matcher类的方法一起使用。

这些模式匹配系统是完全独立的,不能组合。

Caché Pattern Match运算符测试其左操作数中的字符是否由右操作数中的模式正确指定。它返回一个布尔值。当模式正确指定左操作数中的字符模式时,模式匹配运算符会产生TRUE(1)结果。如果模式没有正确指定左操作数中的字符模式,则生成FALSE(0)结果。

例如,以下测试字符串SSN是否包含有效的美国社会保险号(3位、连字符、2位、连字符和4位):

 SET ssn="123-45-6789"
 SET match = ssn    ?3N1"-"2N1"-"4N
 WRITE match
1

左操作数(测试值)和右操作数(模式)可以用一个或多个空格分隔,也可以不用空格分隔,如以下等效程序示例所示:

 SET ssn="123-45-6789"
 SET match = ssn?3N1"-"2N1"-"4N
 WRITE match
1

操作符后面不允许有空格。模式中的空格必须在带引号的字符串内,并被解释为模式的一部分。

模式匹配操作的一般格式如下:

operand?pattern
  • operand 计算结果为字符串或数字的表达式,要测试其字符是否具有模式。
  • pattern 以字符开头的模式匹配序列。(或与‘?用于不匹配测试)。模式序列可以是以下之一:一个或多个模式元素的序列;计算为一个或多个模式元素的序列的间接引用

模式元素由以下内容之一组成:

  • 重复匹配代码repeat-count pattern-codes
  • 重复字符串repeat-count literal-string
  • 重复替换repeat-count alternation
名称 描述
repeat-count 重复计数-要匹配的确切实例数。重复计数的计算结果可以是整数或句点通配符(.)。使用句点指定任意数量的实例。
pattern-codes 一个或多个模式代码。如果指定了多个代码,则通过匹配任何一个代码来满足该模式。
literal-string 用双引号括起来的文字字符串。
alternation 一组可供选择的模式元素序列(以便对操作数字符串的一段执行模式匹配)。这在模式规范中提供了逻辑OR功能。

如果要匹配特定的一个或多个字符,请在模式中使用双引号括起来的文字字符串。在其他情况下,请使用CachéObjectScript提供的特殊模式代码。与特定模式代码相关联的字符(在某种程度上)依赖于区域设置。下表显示了可用的模式代码及其含义:

代码 含义
A 匹配任何大写或小写字母字符。区域设置的8位字符集定义了什么是字母字符。对于英语区域设置(基于拉丁文-1字符集),这包括ASCII值65到90(A到Z)、97到122(a到z)、170、181、186、192到214、216到246和248到255。
C 匹配任何ASCII控制字符(ASCII值0到31和扩展ASCII值127到159)。
E 匹配任何字符,包括非打印字符、空格字符和控制字符。
L 匹配任何小写字母字符。区域设置的8位字符集定义了什么是小写字符。对于英语区域设置(基于拉丁文-1字符集),这包括ASCII值97到122(a到z)、170、181、186、223到246和248到255。
N 匹配10个数字字符0到9(ASCII 48到57)中的任何一个。
P 匹配任何标点符号。区域设置的字符集定义扩展(8位)ASCII字符集的标点符号。对于英语区域设置(基于拉丁文-1字符集),这包括ASCII值32到47、58到64、91到96、123到126、160到169、171到177、180、182到184、187、191、215和247。
U 匹配任何大写字母字符。区域设置的8位字符集定义了什么是大写字符。对于英语区域设置(基于拉丁文-1字符集),这包括ASCII值65到90(A到Z)、192到214和216到222。
R,B,M 匹配西里尔8位字母字符映射。R匹配任何西里尔字符(ASCII值192到255)。B匹配大写西里尔字符(ASCII值192到223)。M匹配小写西里尔字符(ASCII值为224到255)。这些模式代码仅在俄语8位Windows区域设置(Ruw8)中有意义。在其他地区,它们可以成功执行,但无法匹配任何字符。
ZFWCHARZ 匹配日语ZENKAKU字符集中的任何字符。ZFWCHARZ匹配全角字符,例如汉字范围中的字符,以及在某些终端仿真器显示时占用双倍单元格的许多非汉字字符。ZFWCHARZ还匹配JIS2004标准中定义的303个代理项对字符,将每个代理项对视为单个字符。例如,代理项对字符$WC(131083)?1ZFWCHARZ匹配。此模式匹配代码需要日语区域设置。
ZHWKATAZ 匹配日文汉字假名字符集中的任何字符。这些是Unicode值65377(FF61)到65439(FF9F)。此模式匹配代码需要日语区域设置。

模式代码不区分大小写;可以用大写或小写指定它们。例如,?5N等同于?5n。可以指定多个模式代码以匹配特定字符或字符串。例如,?1NU匹配数字或大写字母。

正如Caché术语表中所述,ASCII字符集是指扩展的8位字符集,而不是更有限的7位字符集。

注意:使用双引号字符的模式匹配可能会产生不一致的结果,特别是当数据是从使用不同NLS区域设置的Caché实现提供的时候。直双引号字符($CHAR(34)=“)匹配为标点符号。方向双引号字符(大引号)与标点符号字符不匹配。8位定向双引号字符($CHAR(147)= “$CHAR(148)=”)作为控制字符匹配。Unicode定向双引号字符($CHAR(8220)=“$CHAR(8221)=”)作为标点符号或控制字符不匹配。

模式匹配运算符与二元包含([)运算符不同。即使只有左操作数的子字符串与右操作数匹配,二进制CONTAINS运算符也会返回TRUE(1)。此外,BINARY CONTAINS表达式不提供模式匹配运算符提供的选项范围。在BINARY CONTAINS表达式中,只能使用单个字符串作为右操作数,没有任何特殊代码。

例如,假设变量var2包含值“abc”。模式匹配表达式:

 SET match = var2?2L

这会将Match设置为false(0),因为var2包含三个小写字符,而不仅仅是两个。

以下是一些基本模式匹配的示例:

/// d ##class(PHA.TEST.ObjectScript).TestPatternMatch()
ClassMethod TestPatternMatch(params)
{
 SET var = "O"
 WRITE "是字母O",!

 WRITE "...字母字符? "
 WRITE var?1A,!

 WRITE "...数字字符? "
 WRITE var?1N,!

 WRITE "...是字母或 ",!,"  是数字? "
 WRITE var?1AN,!

 WRITE "...是字母或 ",!," A Zenkaku汉字字符? "
 WRITE var?1AZFWCHARZ,!

 WRITE "...是数字或 ",!,"  汉字假名字符? "
 WRITE var?1ZHWKATAZN
}
DHC-APP>w ##class(PHA.TEST.ObjectScript).TestPatternMatch()
是字母O
...字母字符? 1
...数字字符? 0
...是字母或
  是数字? 1
...是字母或
 A Zenkaku汉字字符? 1
...是数字或
  汉字假名字符? 0

可以通过指定以下内容来扩展模式代码的范围:

指定模式可以出现的次数

要定义模式可在目标操作数中出现的次数范围,请使用以下格式:

n.n

第一个n定义出现范围的下限;第二个n定义上限。

例如,假设变量var3包含字符串“ABABAB”。在下面的表达式中,1.4表示识别出1到4次“AB”

SET match = var3?1.4"AB"

即使var3只包含三次出现的“AB”,表达式也会返回TRUE(1)结果。

作为另一个示例,请考虑以下表达式:

SET match = var3?1.6A

此表达式检查var3是否包含1到6个字母字符。下面的表达式:只有当var3包含零个或六个以上字符时,才返回FALSE(0)结果。

如果省略任一n,则CachéObjectScript将提供默认值。第一个n的默认值为零(0)。第二个n的默认值是任何数字。考虑以下示例:

 SET match = var3?1."AB"

只要var3至少包含模式字符串“AB”的一个匹配项,此示例就会返回TRUE(1)结果。

指定多个模式

要定义多个模式,可以将n和Pattern组合成任意长度的序列。考虑以下示例:

SET match = date?2N1"/"2N1"/"2N

此表达式检查格式为mm/dd/yy的日期值。以任意长度的顺序排列的图案。考虑以下示例:字符串“4/27/98”将返回FALSE,因为月份只有一个数字。要同时检测一位数和两位数月份,可以将表达式修改为:

SET match = date?1.2N1"/"2N1"/"2N

现在,第一个模式匹配(1.2N)接受1或2个数字。它使用可选句点(.)。要定义上一节中描述的可接受事件范围,请执行以下操作。

指定组合模式

要定义组合模式,请使用以下表单:

Pattern1Pattern2

使用组合模式时,将对照目标操作数检查由pattern1后跟pattern2组成的序列。例如,考虑以下表达式:

 SET match = value?3N.4L

此表达式检查三个数字后跟零到四个小写字母字符的模式。仅当目标操作数正好包含组合模式的一个匹配项时,表达式才返回TRUE(1)。例如,字符串“345g”“345gfij”将符合条件,但“345gfijhkbc”``“345gfij276hkbc”不符合条件。

DHC-APP>w "345g"?3N.4L
1
DHC-APP>w "345"?3N.4L
1

指定不确定模式

要定义不确定模式,请使用以下形式:

.pattern

对于不确定模式,将检查目标操作数是否出现模式,但接受任意数量的出现(包括零出现)。例如,请考虑以下表达式:

SET match = value?.N

如果目标操作数包含零个、一个或多个数字字符,并且不包含任何其他类型的字符,则此表达式返回TRUE(1)

DHC-APP>w "A"?.U
1
DHC-APP>w "Aa"?.U
0

指定交替模式(逻辑或)

交替允许测试操作数是否与一组指定模式序列中的一个或多个匹配。它为模式匹配提供了逻辑或功能。

替换具有以下语法:

( pattern-element sequence {, pattern-element sequence }...)

因此,如果val包含字母“A”的一个匹配项或字母“B”的一个匹配项,则以下模式返回TRUE(1)

 SET match = value?1(1"A",1"B")

可以具有嵌套的替换模式,如以下模式匹配表达式所示:

 SET match = value?.(.(1A,1N),1P)

例如,可能想要验证一个美国电话号码。电话号码至少必须是用连字符(-)分隔第三位和第四位的7位电话号码。例如:

nnn-nnnn

电话号码还可以包括三位数的区号,该区号必须用圆括号括起来,或者用连字符与号码的其余部分隔开。例如:

(nnn) nnn-nnnn
nnn-nnn-nnnn

以下模式匹配表达式描述了美国电话号码的三种有效形式:

 SET match = phone?3N1"-"4N
 SET match = phone?3N1"-"3N1"-"4N
 SET match = phone?1"("3N1") "3N1"-"4N

如果没有替换,将需要以下复合布尔表达式来验证任何形式的美国电话号码。

  SET match = 
     (
     (phone?3N1"-"4N) || 
     (phone?3N1"-"3N1"-"4N) || 
     (phone?1"("3N1") "3N1"-"4N)
     )

通过替换,以下单一模式可以验证任何形式的美国电话号码:

 SET match = phone?.1(1"("3N1") ",3N1"-")3N1"-"4N

本例中的交替允许电话号码的区号分量由1"("3N1") "3N1"-"满足。交替计数范围0到1表示操作数电话可以有0或1区号分量。

重复计数大于一(1)的交替可以产生许多可接受模式的组合。以下替换与显示的字符串匹配,并与其他26个三字符串匹配

DHC-APP>w "CAT"?3(1"C",1"A",1"T")
1
DHC-APP>w "CAT"?3(1"C",1"A",2"T")
0
DHC-APP>w "CATT"?3(1"C",1"A",2"T")
1

使用不完整的模式

如果模式匹配成功地仅描述了字符串的一部分,则模式匹配将返回FALSE(0)结果。也就是说,当模式完成时不能有任何剩余的字符串。以下表达式的计算结果为FALSE(0),因为该模式与最后的“R”不匹配:

DHC-APP>w "RAW BAR"?.U1P2U
0
DHC-APP>w "RAW BAR"?.U1P3U
1
DHC-APP>w "RAW BAR"?.U1P4U
0

解释多重模式

当模式与操作数匹配时,可以有多个模式解释。例如,可以用两种方式解释以下表达式:

DHC-APP>w "/A#####B$$$$$"?.E1U.E
1
  1. 第一个“.E”匹配子字符串“/”1U匹配“A”,第二个“.E”匹配子字符串“#####B$$$$$”
  2. 第一个“.E”匹配子字符串“/A#####”1U匹配字符“B”,第二个“.E”匹配子字符串“$$$$$”

只要表达式的至少一个解释为TRUE(1),则该表达式的值为TRUE。

不匹配运算符

可以通过将一元NOT运算符()与模式匹配一起使用来生成不匹配操作:

operand'?pattern

Not Match反转模式匹配的真值。如果操作数中的字符不能由模式描述,则NOT MATCH返回结果TRUE(1)。如果模式与操作数中的所有字符匹配,则NOT MATCH返回FALSE(0)结果。

下面的示例使用不匹配运算符:

  WRITE !,"abc" ?3L
  WRITE !,"abc" '?3L
  WRITE !,"abc" ?3N
  WRITE !,"abc" '?3N
  WRITE !,"abc" '?3E
1
0
0
1
0

模式复杂性

具有多个交替和不确定模式的模式匹配在应用于长字符串时,可能会递归到系统堆栈中的多个级别。在极少数情况下,这种递归可能会上升到几千个级别,从而威胁到堆栈溢出和进程崩溃。当这种极端情况发生时,Caché会发出<Complex Pattern>错误,而不是冒当前进程崩溃的风险。

如果出现此类错误,建议简化模式,或将其应用于原始字符串的较短子单元。

可以通过发出Crtl-C key命令来中断模式执行,从而导致错误