字符串替换
String Replacing
您认为在不使用 $R 的情况下替换字符串中的内容的最佳方法是什么?我写了一个全局的,我试图用 PAUL 替换 PETER(s),但不使用 $R。这是我认为可行的迭代,但它只是取代了第一个 PETER。对于同一条线路上的多个 Peter,你们有什么建议?
Start
SET ary="^XA"
SET queryary=$QUERY(@ary@(""))
WRITE !,@queryary
FOR {
SET queryary=$QUERY(@queryary)
QUIT:queryary=""
w !,$p(@queryary,"PETER",1)_"PAUL"_$p(@queryary,"PETER",2,$l(@queryary,"PETER"))
}
QUIT
这是我第二次尝试,但我仍然需要多次 运行 它才能执行所有更改。我的循环中是否缺少某些内容?
Start
N ary
S ary="^XA"
S queryary=$Q(@ary@(""))
S FROM="PETER"
S TO="PAUL"
W !,@queryary
F S queryary=$Q(@queryary) Q:queryary="" w !,@queryary d
. f s $E(@queryary,$F(@queryary,FROM)-$L(FROM),$F(@queryary,FROM))=TO_" " Q:ary'["PETER"
QUIT
这个怎么样?
ClassMethod PeterPaul()
{
s ^XNAME(1)="PETER PIPER PICKED A PEPPER"
s ^XNAME(2)="PETER ENJOYS PIZZA'. PETER"
s ^XNAME(3)="PETER WAS BORN IN 1982"
s ^XNAME(4)="PETER LIKES PIZZA AND FRENCH FRIES'. PETER"
s ^XNAME(5)="THE PETER WROTE A BOOK CALLED PETER ADVENTURES."
s ^XNAME(6)="THE PETER HAD THREE KIDS.' PETER JR AND PETER III"
s ^XNAME(7)="PETER MARRIED MARY."
s i=$O(^XNAME(""))
while i'="" {
s ^XNAME(i)=..Replace(^XNAME(i),"PETER","PAUL")
s i=$O(^XNAME(i))
}
q
}
ClassMethod Replace(str, from, to As %String)
{
while $F(str,from) {
s str=$P(str,from)_to_$P(str,from,2,$L(str,from))
}
quit str
}
不幸的是,我还不能 post 发表评论,这更像是对先前解决方案的评论,以及关于 Cache 生成的实际腮腺炎是什么的问题。因此,如果有人在下面回复并确认我的怀疑,那就太好了,因为我认为以前的解决方案存在错误。
因此假设缓存编译以下解决方案:
ClassMethod Replace(str, from, to As %String)
{
while $F(str,from) {
s str=$P(str,from)_to_$P(str,from,2,$L(str,from))
}
quit str
}
像这样:
REPLACE(str,from,to)
;
F I=1:1 Q:'$F(str,from) D
. S str=$P(str,from)_to_$P(str,from,2,$L(str,from))
Q str
此代码中存在严重错误,当我的实际 from
变量包含在 to
、
中时,会导致无限循环
例如将 "LISA" 更改为 "ELISA"、"ELISABETH"、"ALISA"、"MELISA"。
下面使用的示例将 DAN 更改为 DANIEL。
在 GTM 上测试(循环在 10 次迭代后手动中断,否则将是无限的):
GTM>W $$REPLACE^ZZTEST("DAN SMITH","DAN","DANIEL")
DANIELIELIELIELIELIELIELIELIELIEL SMITH
考虑到这一点,我提出如下建议:
REPLACE2(str,from,to)
;
N str2
S str2=""
F I=1:1:$L(str,from)-1 D
. S str2=str2_$P(str,from)_to
. S str=$P(str,from,2,$L(str,from))
;add the last piece if it exists or in case nothing to replace add all.
Q str2_str
在 GTM 中测试:
GTM>W $$REPLACE2^ZZTEST("DAN SMITH","DAN","DANIEL")
DANIEL SMITH
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN","DAN","DANIEL")
DANIEL SMITH DANIEL
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN DAN DAN","DAN","DANIEL")
DANIEL SMITH DANIEL DANIEL DANIEL
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN DAN DAN","DANA","DANIEL")
DAN SMITH DAN DAN DAN
当然这不是最终的解决方案,因为它仍然包含错误,例如生成了名称 LISABETH....
GTM>W $$REPLACE2^ZZTEST("ELISABETH SMITH","ELISA","LISA")
LISABETH SMITH
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA","ELISA","LISA")
LISA LISABETH SMITH LISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA","LISA")
ELISALISABETH SMITHLISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA ","LISA")
ELISA ELISABETH SMITH ELISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA","LISA")
ELISALISABETH SMITHLISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA","ELISA ","LISA")
LISAELISABETH SMITH ELISA
为了绕过这个问题,需要添加额外的逻辑来理解如果名字在开头需要"NAME "如果在结尾“NAME”,否则在中间“NAME”。
类似(可能可以优化):
REPLACE2(str,from,to)
;
N from2,str2
S str2=""
S from2=" "_from_" "
; check if string begins with name
I $E(str,1,$L(from))_" "=(from_" ") S str2=to,str=$E(str,$L(from)+1,$L(str))
; search for name with spaces
F I=1:1:$L(str,from2)-1 D
. S str2=str2_$P(str,from2)_" "_to
. S str=" "_$P(str,from2,2,$L(str,from2))
; check if finishes with name
I $L(str)>=$L(from) D
. I $E(str,$L(str)-$L(from),$L(str))=(" "_from) S str2=str2_$E(str,1,$L(str)-$L(from))_to,str=""
.
Q str2_str ;add the last piece if it exists
GTM 测试:
GTM>W $$REPLACE2^ZZTEST("MELISA ELISA ELISABETH ALISA ELISA","ELISA","LISA")
MELISA LISA ELISABETH ALISA LISA
GTM>W $$REPLACE2^ZZTEST("MELISA ELISA ELISABETH ALISA ELISA","LISA","ELISA")
MELISA ELISA ELISABETH ALISA ELISA
GTM>W $$REPLACE2^ZZTEST("LISA MELISA ELISA ELISABETH LISA ALISA LISA","LISA","ELISA)
ELISA MELISA ELISA ELISABETH ELISA ALISA ELISA
GTM>W $$REPLACE2^ZZTEST("LISA MELISA ELISA ELISABETH LISA ALISA LISA","LISA","ELISA)
ELISA MELISA ELISA ELISABETH ELISA ALISA ELISA
但如果您决定或收到如下输入,可能仍无法满足您的所有需求:
GTM>W $$REPLACE2^ZZTEST("ELISA,SMITH","ELISA","LISA")
ELISA,SMITH
如果您在 Cache 中工作并需要一个实用程序,%GCHANGE 是一个非常强大的程序,仅用于执行您描述的操作。我一直将它用作实用程序,从未从程序中调用它,但我相信有一些标签可以让你调用并传递参数。
另一件事是您在循环中使用多个间接寻址,这会减慢您的程序。我建议将所有这些组合成一个字符串,并使用 E(X)ecute 命令间接访问整个字符串。您可以看到下面提供的示例。
我包括了两种不同的字符串替换方法。一种使用类似于 Evgeny Shvarov 建议的 $P 和 $L,第二种方法是使用 $F 和 $E。
第二种方法在全局 100000 个节点和每个节点 4 个替换上平均执行速度快 33%。
我将包括我的数据生成。以及我编写的测试功能。我在遗留 MUMPS 代码中编写了这些代码,因此它可以跨平台工作。
更新:我刚刚查看了 GTM 文档。 %GCE 是一个类似的实用程序,可在 GTM 中使用。
更新:我更改了 REPLACE 函数以正确解决 C4xuxo 描述的 LISA 到 ELISA 问题。它仍然比使用 $P $L 执行得更快。
更新:对 REPLACE 函数中 PS 的值进行了调整以修复错误;
;GLOBAL REPLACE METHOD
GLBREPLACE(GLB,STR1,STR2) ;(GLOBAL NAME, STRING TO MATCH, STRING TO REPLACE WITH)
S CMD="N I S I="""" F S I=$O("_GLB_"(I)) Q:I="""" S "_GLB_"(I)=$$REPLACE("_GLB_"(I),"""_STR1_""","""_STR2_""")"
X CMD Q
;STRING REPLACE METHOD
REPLACE(STR,V1,V2) ;(INPUT STRING, STRING TO MATCH, STRING TO REPLACE WITH)
N I,L,F1,F2,PS S PS=0,L=$L(STR,V1) F I=1:1:L-1 S F2=$F(STR,V1,PS),F1=F2-$L(V1),$E(STR,F1,F2-1)=V2,PS=F2+$L(V2)
Q STR
;======================================================================
;ADDITINAL FUNCTIONS
;THIS IS AN ALTERNATE METHOD, DOESN'T ADDRESS THE LISA TO ELISA PROBLEM
REPLACE2(STR,V1,V2)
N I F I=1:1:$L(STR,V1)-1 S STR=$P(STR,V1)_V2_$P(STR,V1,2,$L(STR,V1))
Q STR
TESTGLBREPLACE ;THIS FUNCTION TESTS GLBREPLACE AND MEASURS PERFORMANCE
S STIM=$ZTS S COUNT=100000
D GENDATA(COUNT),GLBREPLACE("^XA","Peter","PAUL")
S ETIM=$ZTS,TIMDIF=$P(ETIM,",",2)-$P(STIM,",",2),OCCURS=COUNT*4
W !,"REPLACED "_OCCURS_" OCCURRENCES IN "_TIMDIF_" SECONDS"
Q
GENDATA(L) ;THIS FUNCTION GENERATES DATA FOR A GIVE COUNT(L=INTEGER)
F I=1:1:L S ^XA(I)="Peter Piper picked a peck of pickled peppers; A peck of pickled peppers Peter Piper picked; If Peter Piper picked a peck of pickled peppers, Where's the peck of pickled peppers Peter Piper picked"
Q
Mumps 开发委员会会议记录中引用的标准 REPLACE 在 $$REPLACE^XLFSTR() 中。我经常将它用作 printf 模拟器。
REPLACE(IN,SPEC) ;See $$REPLACE in MDC minutes.
Q:'$D(IN) "" Q:$D(SPEC)'>9 IN N %1,%2,%3,%4,%5,%6,%7,%8
S %1=$L(IN),%7=$J("",%1),%3="",%6=9999 F S %3=$O(SPEC(%3)) Q:%3="" S %6(%6)=%3,%6=%6-1
F %6=0:0 S %6=$O(%6(%6)) Q:%6'>0 S %3=%6(%6) D:$D(SPEC(%3))#2 RE1
S %8="" F %2=1:1:%1 D RE3
Q %8
;
RE1 S %4=$L(%3),%5=0 F S %5=$F(IN,%3,%5) Q:%5
这里是关于如何使用它的参考:
不使用 $replace 是很棘手的。我使用了 $find 和 $extract 函数...我用 "BACH"
替换了 "MOZART"
mozartdocument
s ^XA(1)="ONCE UPON A TIME A COMPOSER NAMED MOZART WROTE"
s ^XA(2)="THE 'MOZART PIANO CONCERTO NUMBER ONE'. MOZART"
s ^XA(3)="MOZART 12 MOZART HANDEL MOZART MOZART 12"
s ^XA(4)="MAN MOZART MUMPS MANY MUNCHKINS MOZART"
s ^XA(5)="MOVE ALONG, NOTHING TO SEE HERE!"
s ^XA(6)="123 MOZART 456"
s ^XA(7)="HAPPILY EVER AFTER!"
for z = 1:1:7 {
do {
set x = $find(^XA(z),"MOZART")
set $extract(^XA(z),x-6,x-1)="BACH"
} while x > 0
write !,^XA(z)
} write !
您认为在不使用 $R 的情况下替换字符串中的内容的最佳方法是什么?我写了一个全局的,我试图用 PAUL 替换 PETER(s),但不使用 $R。这是我认为可行的迭代,但它只是取代了第一个 PETER。对于同一条线路上的多个 Peter,你们有什么建议?
Start
SET ary="^XA"
SET queryary=$QUERY(@ary@(""))
WRITE !,@queryary
FOR {
SET queryary=$QUERY(@queryary)
QUIT:queryary=""
w !,$p(@queryary,"PETER",1)_"PAUL"_$p(@queryary,"PETER",2,$l(@queryary,"PETER"))
}
QUIT
这是我第二次尝试,但我仍然需要多次 运行 它才能执行所有更改。我的循环中是否缺少某些内容?
Start
N ary
S ary="^XA"
S queryary=$Q(@ary@(""))
S FROM="PETER"
S TO="PAUL"
W !,@queryary
F S queryary=$Q(@queryary) Q:queryary="" w !,@queryary d
. f s $E(@queryary,$F(@queryary,FROM)-$L(FROM),$F(@queryary,FROM))=TO_" " Q:ary'["PETER"
QUIT
这个怎么样?
ClassMethod PeterPaul()
{
s ^XNAME(1)="PETER PIPER PICKED A PEPPER"
s ^XNAME(2)="PETER ENJOYS PIZZA'. PETER"
s ^XNAME(3)="PETER WAS BORN IN 1982"
s ^XNAME(4)="PETER LIKES PIZZA AND FRENCH FRIES'. PETER"
s ^XNAME(5)="THE PETER WROTE A BOOK CALLED PETER ADVENTURES."
s ^XNAME(6)="THE PETER HAD THREE KIDS.' PETER JR AND PETER III"
s ^XNAME(7)="PETER MARRIED MARY."
s i=$O(^XNAME(""))
while i'="" {
s ^XNAME(i)=..Replace(^XNAME(i),"PETER","PAUL")
s i=$O(^XNAME(i))
}
q
}
ClassMethod Replace(str, from, to As %String)
{
while $F(str,from) {
s str=$P(str,from)_to_$P(str,from,2,$L(str,from))
}
quit str
}
不幸的是,我还不能 post 发表评论,这更像是对先前解决方案的评论,以及关于 Cache 生成的实际腮腺炎是什么的问题。因此,如果有人在下面回复并确认我的怀疑,那就太好了,因为我认为以前的解决方案存在错误。
因此假设缓存编译以下解决方案:
ClassMethod Replace(str, from, to As %String)
{
while $F(str,from) {
s str=$P(str,from)_to_$P(str,from,2,$L(str,from))
}
quit str
}
像这样:
REPLACE(str,from,to)
;
F I=1:1 Q:'$F(str,from) D
. S str=$P(str,from)_to_$P(str,from,2,$L(str,from))
Q str
此代码中存在严重错误,当我的实际 from
变量包含在 to
、
例如将 "LISA" 更改为 "ELISA"、"ELISABETH"、"ALISA"、"MELISA"。
下面使用的示例将 DAN 更改为 DANIEL。
在 GTM 上测试(循环在 10 次迭代后手动中断,否则将是无限的):
GTM>W $$REPLACE^ZZTEST("DAN SMITH","DAN","DANIEL")
DANIELIELIELIELIELIELIELIELIELIEL SMITH
考虑到这一点,我提出如下建议:
REPLACE2(str,from,to)
;
N str2
S str2=""
F I=1:1:$L(str,from)-1 D
. S str2=str2_$P(str,from)_to
. S str=$P(str,from,2,$L(str,from))
;add the last piece if it exists or in case nothing to replace add all.
Q str2_str
在 GTM 中测试:
GTM>W $$REPLACE2^ZZTEST("DAN SMITH","DAN","DANIEL")
DANIEL SMITH
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN","DAN","DANIEL")
DANIEL SMITH DANIEL
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN DAN DAN","DAN","DANIEL")
DANIEL SMITH DANIEL DANIEL DANIEL
GTM>W $$REPLACE2^ZZTEST("DAN SMITH DAN DAN DAN","DANA","DANIEL")
DAN SMITH DAN DAN DAN
当然这不是最终的解决方案,因为它仍然包含错误,例如生成了名称 LISABETH....
GTM>W $$REPLACE2^ZZTEST("ELISABETH SMITH","ELISA","LISA")
LISABETH SMITH
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA","ELISA","LISA")
LISA LISABETH SMITH LISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA","LISA")
ELISALISABETH SMITHLISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA ","LISA")
ELISA ELISABETH SMITH ELISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA"," ELISA","LISA")
ELISALISABETH SMITHLISA
GTM>W $$REPLACE2^ZZTEST("ELISA ELISABETH SMITH ELISA","ELISA ","LISA")
LISAELISABETH SMITH ELISA
为了绕过这个问题,需要添加额外的逻辑来理解如果名字在开头需要"NAME "如果在结尾“NAME”,否则在中间“NAME”。
类似(可能可以优化):
REPLACE2(str,from,to)
;
N from2,str2
S str2=""
S from2=" "_from_" "
; check if string begins with name
I $E(str,1,$L(from))_" "=(from_" ") S str2=to,str=$E(str,$L(from)+1,$L(str))
; search for name with spaces
F I=1:1:$L(str,from2)-1 D
. S str2=str2_$P(str,from2)_" "_to
. S str=" "_$P(str,from2,2,$L(str,from2))
; check if finishes with name
I $L(str)>=$L(from) D
. I $E(str,$L(str)-$L(from),$L(str))=(" "_from) S str2=str2_$E(str,1,$L(str)-$L(from))_to,str=""
.
Q str2_str ;add the last piece if it exists
GTM 测试:
GTM>W $$REPLACE2^ZZTEST("MELISA ELISA ELISABETH ALISA ELISA","ELISA","LISA")
MELISA LISA ELISABETH ALISA LISA
GTM>W $$REPLACE2^ZZTEST("MELISA ELISA ELISABETH ALISA ELISA","LISA","ELISA")
MELISA ELISA ELISABETH ALISA ELISA
GTM>W $$REPLACE2^ZZTEST("LISA MELISA ELISA ELISABETH LISA ALISA LISA","LISA","ELISA)
ELISA MELISA ELISA ELISABETH ELISA ALISA ELISA
GTM>W $$REPLACE2^ZZTEST("LISA MELISA ELISA ELISABETH LISA ALISA LISA","LISA","ELISA)
ELISA MELISA ELISA ELISABETH ELISA ALISA ELISA
但如果您决定或收到如下输入,可能仍无法满足您的所有需求:
GTM>W $$REPLACE2^ZZTEST("ELISA,SMITH","ELISA","LISA")
ELISA,SMITH
如果您在 Cache 中工作并需要一个实用程序,%GCHANGE 是一个非常强大的程序,仅用于执行您描述的操作。我一直将它用作实用程序,从未从程序中调用它,但我相信有一些标签可以让你调用并传递参数。
另一件事是您在循环中使用多个间接寻址,这会减慢您的程序。我建议将所有这些组合成一个字符串,并使用 E(X)ecute 命令间接访问整个字符串。您可以看到下面提供的示例。
我包括了两种不同的字符串替换方法。一种使用类似于 Evgeny Shvarov 建议的 $P 和 $L,第二种方法是使用 $F 和 $E。
第二种方法在全局 100000 个节点和每个节点 4 个替换上平均执行速度快 33%。
我将包括我的数据生成。以及我编写的测试功能。我在遗留 MUMPS 代码中编写了这些代码,因此它可以跨平台工作。
更新:我刚刚查看了 GTM 文档。 %GCE 是一个类似的实用程序,可在 GTM 中使用。 更新:我更改了 REPLACE 函数以正确解决 C4xuxo 描述的 LISA 到 ELISA 问题。它仍然比使用 $P $L 执行得更快。
更新:对 REPLACE 函数中 PS 的值进行了调整以修复错误;
;GLOBAL REPLACE METHOD
GLBREPLACE(GLB,STR1,STR2) ;(GLOBAL NAME, STRING TO MATCH, STRING TO REPLACE WITH)
S CMD="N I S I="""" F S I=$O("_GLB_"(I)) Q:I="""" S "_GLB_"(I)=$$REPLACE("_GLB_"(I),"""_STR1_""","""_STR2_""")"
X CMD Q
;STRING REPLACE METHOD
REPLACE(STR,V1,V2) ;(INPUT STRING, STRING TO MATCH, STRING TO REPLACE WITH)
N I,L,F1,F2,PS S PS=0,L=$L(STR,V1) F I=1:1:L-1 S F2=$F(STR,V1,PS),F1=F2-$L(V1),$E(STR,F1,F2-1)=V2,PS=F2+$L(V2)
Q STR
;======================================================================
;ADDITINAL FUNCTIONS
;THIS IS AN ALTERNATE METHOD, DOESN'T ADDRESS THE LISA TO ELISA PROBLEM
REPLACE2(STR,V1,V2)
N I F I=1:1:$L(STR,V1)-1 S STR=$P(STR,V1)_V2_$P(STR,V1,2,$L(STR,V1))
Q STR
TESTGLBREPLACE ;THIS FUNCTION TESTS GLBREPLACE AND MEASURS PERFORMANCE
S STIM=$ZTS S COUNT=100000
D GENDATA(COUNT),GLBREPLACE("^XA","Peter","PAUL")
S ETIM=$ZTS,TIMDIF=$P(ETIM,",",2)-$P(STIM,",",2),OCCURS=COUNT*4
W !,"REPLACED "_OCCURS_" OCCURRENCES IN "_TIMDIF_" SECONDS"
Q
GENDATA(L) ;THIS FUNCTION GENERATES DATA FOR A GIVE COUNT(L=INTEGER)
F I=1:1:L S ^XA(I)="Peter Piper picked a peck of pickled peppers; A peck of pickled peppers Peter Piper picked; If Peter Piper picked a peck of pickled peppers, Where's the peck of pickled peppers Peter Piper picked"
Q
Mumps 开发委员会会议记录中引用的标准 REPLACE 在 $$REPLACE^XLFSTR() 中。我经常将它用作 printf 模拟器。
REPLACE(IN,SPEC) ;See $$REPLACE in MDC minutes. Q:'$D(IN) "" Q:$D(SPEC)'>9 IN N %1,%2,%3,%4,%5,%6,%7,%8 S %1=$L(IN),%7=$J("",%1),%3="",%6=9999 F S %3=$O(SPEC(%3)) Q:%3="" S %6(%6)=%3,%6=%6-1 F %6=0:0 S %6=$O(%6(%6)) Q:%6'>0 S %3=%6(%6) D:$D(SPEC(%3))#2 RE1 S %8="" F %2=1:1:%1 D RE3 Q %8 ; RE1 S %4=$L(%3),%5=0 F S %5=$F(IN,%3,%5) Q:%5
这里是关于如何使用它的参考:
不使用 $replace 是很棘手的。我使用了 $find 和 $extract 函数...我用 "BACH"
替换了 "MOZART"mozartdocument
s ^XA(1)="ONCE UPON A TIME A COMPOSER NAMED MOZART WROTE"
s ^XA(2)="THE 'MOZART PIANO CONCERTO NUMBER ONE'. MOZART"
s ^XA(3)="MOZART 12 MOZART HANDEL MOZART MOZART 12"
s ^XA(4)="MAN MOZART MUMPS MANY MUNCHKINS MOZART"
s ^XA(5)="MOVE ALONG, NOTHING TO SEE HERE!"
s ^XA(6)="123 MOZART 456"
s ^XA(7)="HAPPILY EVER AFTER!"
for z = 1:1:7 {
do {
set x = $find(^XA(z),"MOZART")
set $extract(^XA(z),x-6,x-1)="BACH"
} while x > 0
write !,^XA(z)
} write !