Замена строки
По вашему мнению, что было бы лучшим способом заменить что-либо в строке без использования $R? Я написал глобальный и пытаюсь заменить PETER на PAUL, но не использую $R. Вот какая итерация того, что я думал, сработает, но он просто заменяет первый 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
5 ответов
Если вы работаете в Cache и вам нужна утилита для этого, %GCHANGE - очень мощная программа, предназначенная только для того, что вы описали. Я всегда использовал его как утилиту и никогда не вызывал его из программы, но я верю, что есть ярлыки, где вы вызываете и передаете свои параметры.
Другое дело, что вы используете несколько косвенных указаний в цикле, которые замедляют вашу программу. Я предлагаю объединить все это в строку и использовать команду E(X)ecute для косвенного обращения ко всей строке. Вы можете увидеть пример, приведенный ниже.
Я включил два разных метода замены строки. Один использует $P и $L аналогично тому, что предложил Evgeny Shvarov, а второй метод использует $F и $E.
Второй метод в среднем выполнялся на 33% быстрее в глобальном масштабе из 100000 узлов и 4 замен на узел.
Я включу мои данные поколения. и тестирование функций, которые я написал. Я написал их в унаследованном коде MUMPS, чтобы он работал на разных платформах.
ОБНОВЛЕНИЕ: я только что проверил документацию GTM. %GCE - аналогичная утилита, доступная в GTM. ОБНОВЛЕНИЕ: Я C4xuxo, чтобы должным образом учитывать проблему LISA-ELISA, описанную C4xuxo. Он по-прежнему работает быстрее, чем при использовании $P $L.
ОБНОВЛЕНИЕ: внесена корректировка в значение PS в функции REPLACE, чтобы исправить ошибку;
;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
Без использования $replace это сложно. Я использовал функции $find и $extract... моя заменяет "MOZART" на "BACH"
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 !
Как насчет этого?
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
}
К сожалению, я пока не могу публиковать комментарии, и это должно было быть больше похоже на комментарий к предыдущему решению и вопрос о том, что такое настоящий паротит, сгенерированный Cache. Поэтому, если кто-то ответит и подтвердит мою подозрительность ниже, было бы здорово, так как я думаю, что в предыдущем решении есть ошибка.
Предполагая, что 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
Чтобы обойти эту проблему, необходимо добавить дополнительную логику, чтобы понять, что если имя в начале должно быть "ИМЯ", если в конце "ИМЯ", в противном случае в середине "ИМЯ".
что-то вроде (что, вероятно, может быть оптимизировано):
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
Стандартный REPLACE, указанный в протоколе Комитета по разработке паротита, находится в $$REPLACE^XLFSTR(). Я использую его очень часто в качестве эмулятора printf.
ЗАМЕНА (IN,SPEC); см. $$ ЗАМЕНА в минутах MDC. 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
Вот ссылка на то, как его использовать: