文章目录
-
第五章 疯狂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
- 第一个
“.E”
匹配子字符串“/”
,1U
匹配“A”
,第二个“.E”
匹配子字符串“#####B$$$$$”
。 - 第一个
“.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命令来中断模式执行,从而导致错误