文章目录



第十二章 Caché 字符串操作

基本字符串操作和函数

ObjectScript基本字符串操作允许对字符串执行各种操作。它们包括:

  • ​$LENGTH​​函数返回字符串中的字符数:例如,代码:
WRITE $LENGTH("How long is this?")
17
  • ​$JUSTIFY​​返回右对齐的字符串,左边用空格填充(还可以对数值执行操作)。例如,代码:
WRITE "one",!,$JUSTIFY("two",8),!,"three"

对齐八个字符内的字符串“​​Two​​”并返回:

DHC-APP>WRITE "one",!,$JUSTIFY("two",8),!,"three"
one
two
three
  • ​$ZCONVERT​​将字符串从一种形式转换为另一种形式。它支持大小写转换(到大写、到小写或到标题)和编码转换(在各种字符编码样式之间)。例如,代码:
WRITE $ZCONVERT("cRAZy cAPs","t")
DHC-APP> WRITE $ZCONVERT("cRAZy cAPs","t")
CRAZY CAPS
  • ​$find​​函数搜索字符串的子字符串,并返回子字符串后面的字符位置。例如,代码:
WRITE $FIND("Once upon a time...", "upon")
DHC-APP> WRITE $FIND("Once upon a time...", "upon")
10
  • ​$Translate​​函数在字符串中执行逐个字符的替换。例如,代码:
SET text = "11/04/2008"
WRITE $TRANSLATE(text,"/","-")
DHC-APP>WRITE $TRANSLATE(text,"/","-")
11-04-2008

将日期的斜杠替换为连字符。

  • ​$REPLACE​​函数执行字符串内的逐个字符串替换;该函数不更改其操作的字符串的值。例如,代码:
/// d ##class(PHA.TEST.ObjectScript).TestReplace()
ClassMethod TestReplace()
{
SET text = "green leaves, brown leaves"
WRITE text,!
WRITE $REPLACE(text,"leaves","eyes"),!
WRITE $REPLACE(text,"leaves","hair",15),!
WRITE text,!
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestReplace()
green leaves, brown leaves
green eyes, brown eyes
brown hair
green leaves, brown leaves

执行两个不同的操作。在第一个调用中,​​$REPLACE​​​用字符串 ​​eyes​​​替换字符串​​leaves​​​。在第二次调用中,​​$REPLACE​​​将丢弃第15个字符(由第四个参数指定)之前的所有字符,并将字符串 ​​leaves​​​替换为字符串​​hair​​​。这两个​​$REPLACE​​调用都不会更改文本字符串的值。

  • ​$Extract​​函数,返回字符串中指定位置的子字符串。例如,代码:
DHC-APP> WRITE $EXTRACT("Nevermore"),$EXTRACT("prediction",5),$EXTRACT("xon/xoff",1,3)
Nixon

返回三个字符串。第一个参数形式返回字符串的第一个字符;第二个参数形式返回字符串中的指定字符;三参数形式返回以指定字符(包括指定字符)开始和结束的子字符串。在上面的示例中,没有换行符,因此返回值为:

​$Extract​​的高级功能

可以将​​$EXTRACT​​函数与SET命令结合使用,在左侧填充带空格的字符串。

/// d ##class(PHA.TEST.ObjectScript).TestEx()
ClassMethod TestEx()
{
SET x = "abc"
WRITE x,!
SET $EXTRACT(y, 3) = x
SET x = y
WRITE x
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestEx()
abc
abc

这段代码接受字符串“​​abc​​​”,并将其放在字符​​串y​​​的第三个字符。因为​​y​​​没有指定值,所以​​$Extract​​假定它的字符是空的,这将填充字符串。

还可以使用​​$EXTRACT​​在变量中的特定点插入新字符串。它提取指定的字符,并用提供的子字符串替换它们,而不管新旧字符串的长度是否匹配。例如:

/// d ##class(PHA.TEST.ObjectScript).TestEx1()
ClassMethod TestEx1()
{
SET x = "1234"
WRITE x,!
SET $EXTRACT(x, 3) = "abc"
WRITE x,!
SET $EXTRACT(y, 3) = "abc"
WRITE y
}
DHC-APP>d ##class(PHA.TEST.ObjectScript).TestEx1()
1234
12abc4
abc

此代码将​​x​​​设置为“​​1234​​​”;然后使用​​$Extract​​​提取​​x​​​的第三个字符,并在其位置插入“​​abc​​​”,生成字符串“​​12abc4​​”。

分隔字符串

Caché包括允许将字符串作为一组子字符串使用的功能。此功能提供了对作为单个整体存储的相关数据片段的操作。这些是


  • ​$PIECE​​ -根据指定的分隔符返回字符串的特定部分。它还可以基于多个分隔符返回一系列片段,以及单个字符串中的多个片段。
  • ​$LENGTH​​-根据指定的分隔符返回字符串中的片段数。

​$PIECE​​​ 函数提供了非常重要的功能,因为它允许使用包含多个子字符串的单个字符串,并使用特殊的分隔符(如“​​^​​”)来分隔它们。大字符串充当记录,子字符串是它的字段。

​$PIECE​​ 的语法为:

WRITE $PIECE("ListString","QuotedDelimiter",ItemNumber)

其中,​​ListString​​​是包含正在使用的完整记录的带引号的字符串;​​QuotedDlimiter​​​是指定的分隔符,必须用引号括起来;​​ItemNumber​​是要返回的指定子字符串。例如,要显示以下空格分隔列表中的第二项,语法为:

DHC-APP> WRITE $PIECE("Kennedy Johnson Nixon"," ",2)
Johnson

还可以返回列表的多个成员,以便执行以下操作:

DHC-APP> WRITE $PIECE("Nixon***Ford***Carter***Reagan","***",1,3)
Nixon***Ford***Carter

请注意,这两个值都必须引用实际子字符串,并且第三个参数(此处为1)的值必须小于第四个参数(此处为3)的值。

分隔符可以是选择的任何分隔符,例如使用以下列表:

SET x = $PIECE("Reagan,Bush,Clinton,Bush,Obama",",",3)
SET y = $PIECE("Reagan,Bush,Clinton,Bush,Obama","Bush",2)
WRITE x,!,y
Clinton
,Clinton,

在第一种情况下,分隔符是逗号;在第二种情况下,它是字符串“​​Bush​​”,这就是返回的字符串包含逗号的原因。

高级​​$PIECE​​ 功能

对设置列表中分隔元素的值的​​$PIECE​​的调用将添加足够的列表项,以便它可以将子字符串作为适当的项放置在其他空的列表中。例如,假设某些代码设置了列表中的第一项,然后是第四项,然后是第二十项,

SET $PIECE(Alphalist, "^", 1) = "a"
WRITE "First, the length of the list is ",$LENGTH(Alphalist,"^"),".",!
SET $PIECE(Alphalist, "^", 4) = "d"
WRITE "Then, the length of the list is ",$LENGTH(Alphalist,"^"),".",!
SET $PIECE(Alphalist, "^", 20) = "t"
WRITE "Finally, the length of the list is ",$LENGTH(Alphalist,"^"),".",!

​$length​​函数返回值1,然后是4,然后是20,因为它创建了必要数量的分隔项。但是,第2项、第3项和第5项到第19项没有设置值。因此,如果尝试显示它们的任何值,则不会显示任何内容。

分隔字符串项还可以包含分隔字符串。要从这样的子列表中检索值,请嵌套​​$PIECE​​函数调用,如以下代码所示:

/// d ##class(PHA.TEST.ObjectScript).TestPIECE()
ClassMethod TestPIECE()
{
SET $PIECE(Powers, "^", 1) = "1::1::1::1::1"
SET $PIECE(Powers, "^", 2) = "2::4::8::16::32"
SET $PIECE(Powers, "^", 3) = "3::9::27::81::243"
WRITE Powers,!
WRITE $PIECE( $PIECE(Powers, "^", 2), "::", 3)
}
DHC-APP> d ##class(PHA.TEST.ObjectScript).TestPIECE()
1::1::1::1::1^2::4::8::16::32^3::9::27::81::243
8

此代码返回两行输出:第一行是字符串Powers,包括它的所有分隔符;第二行是8,这是Powers中的第二个元素所包含的子列表中第三个元素的值。

列表结构字符串操作

ObjectScript定义了一种称为“列表”的特殊字符串,它由称为元素的子字符串的编码列表组成。这些Caché 列表只能使用以下列表函数处理:


  • 列表创建:

  • ​$LISTBUILD​​通过将每个元素指定为参数值来创建列表。
  • ​$LISTFROMSTRING​​通过指定包含分隔符的字符串创建列表。该函数使用分隔符将字符串划分为元素。
  • ​$LIST​​通过将其作为子列表从现有列表中提取来创建列表。

  • 列表取数:

  • ​$LIST​​按位置返回列表元素值。它可以从列表的开头或结尾对位置进行计数。
  • ​$LISTNEXT​​​从列表开始按顺序返回列表元素值。虽然​​$LIST​​​和​​$LISTNEXT​​​都可以用于顺序返回列表中的元素,但​​$LISTNEXT​​在返回大量列表元素时速度要快得多。
  • ​$LISTGET​​按位置返回列表元素值,或返回默认值。
  • ​$LISTTOSTRING​​以分隔字符串的形式返回列表中的所有元素值。

  • 列表操作:
  • ​SET $LIST​​​插入、更新或删除列表中的元素。​​SET $LIST​​​用一个或多个值替换列表元素或列表元素范围。​​SET $LIST​​​可以用多个元素替换一个列表元素,可以使用它将元素插入到列表中。因为​​SET $LIST​​可以用空字符串替换列表元素,所以可以使用它来删除一个列表元素或一系列列表元素。
  • 列表计算:

  • ​$LISTVALID​​确定字符串是否为有效列表。
  • ​$LISTLENGTH​​确定列表中的元素数量。
  • ​$LISTDATA​​确定指定的列表元素是否包含数据。
  • ​$LISTFIND​​确定是否在列表中找到指定值,并返回列表位置。
  • ​$LISTSAME​​确定两个列表是否相同。


因为列表是编码字符串,所以Caché处理列表的方式与标准字符串略有不同。因此,不应该在列表上使用标准字符串函数。此外,对标准字符串使用大多数LIST函数会生成​​<LIST>​​错误。

以下过程演示了各种列表函数的用法:

/// d ##class(PHA.TEST.ObjectScript).TestList()
ClassMethod TestList()
{
// 设置列表元素的值
SET Addr="One Memorial Drive"
SET City="Cambridge"
SET State="MA"
SET Zip="02142"

// 创建列表
SET Mail = $LISTBUILD(Addr,City,State,Zip)

// 输入
READ "Enter a string: ",input,!,!

// 如果用户输入是列表的一部分,则打印列表的内容
IF $LISTFIND(Mail,input) {
FOR i=1:1:$LISTLENGTH(Mail) {
WRITE $LIST(Mail,i),!
}
}
}
DHC-APP> d ##class(PHA.TEST.ObjectScript).TestList()
Enter a string: MA

One Memorial Drive
Cambridge
MA
02142

此过程演示列表的几个值得注意的方面:


  • 如果要测试的值与列表项完全匹配,则​​$LISTFIND​​仅返回1(True)。
  • ​$LISTFIND​​​和​​$LISTLENGTH​​在表达式中使用。

稀疏列表和子列表

按位置将元素值添加到列表的函数将添加足够的列表元素以将值放置在适当的位置。例如:

SET $LIST(Alphalist,1)="a"
SET $LIST(Alphalist,20)="t"
WRITE $LISTLENGTH(Alphalist)

因为本例中的第二个​​$LIST​​​创建列表元素20,所以​​$LISTLENGTH​​​返回值20。但是,元素2到19没有设置值。因此,如果尝试显示它们的任何值,将收到​​<null value>​​​错误。可以使用​​$LISTGET​​来避免此错误。

列表中的元素本身可以是列表。要从这样的子列表中检索值,请嵌套​​$LIST​​函数调用,如以下代码所示:

SET $LIST(Powers,2)=$LISTBUILD(2,4,8,16,32)
WRITE $LIST($LIST(Powers,2),5)

此代码返回32,它是Power列表中第二个元素所包含的子列表中第五个元素的值。

比较列表和分隔字符串

列表的优点


  • 列表不需要指定的分隔符。虽然​​$PIECE​​函数允许管理包含多个数据项的字符串,但它取决于留出一个字符(或字符串)作为专用分隔符。使用分隔符时,总有可能其中一个数据项包含作为数据的分隔符字符,这将丢弃分隔字符串中各部分的位置作为专用分隔符。列表对于完全避免分隔符非常有用,因此允许将任何字符或字符组合作为数据输入。
  • 从列表(使用​​$LIST​​​或​​$LISTNEXT​​​)检索数据元素比从分隔字符串(使用​​$PIECE​​​)检索数据元素更快。对于顺序数据检索,​​$LISTNEXT​​​比​​$LIST​​​快得多,而且两者都比​​$PIECE​​快得多。

分隔字符串的优点


  • 带分隔符的字符串允许使用​​$find​​​函数更灵活地搜索数据内容。因为​​$LISTFIND​​​要求完全匹配,所以不能在列表中搜索部分子字符串。因此,在上面的示例中,即使地址“​​one Memorial Drive​​​”以字符“​​one​​​”开头,使用​​$LISTFIND​​​在邮件列表中搜索字符串“​​one​​”也会返回0(表示失败)。
  • 因为分隔字符串是标准字符串,所以可以对其使用所有标准字符串函数。因为 Caché列表是编码字符串,所以只能对 Caché列表使用​​$LIST​​函数。