Замена строки

На ваш взгляд, как лучше всего заменить что-то в строке без использования $R? Я написал глобальную переменную и пытаюсь заменить PETER(s) на PAUL, но не использую $R. Вот какая итерация того, что, как я думал, сработает, но она просто заменяет первого ПЕТРА. Что бы вы предложили, ребята, для нескольких Питеров на одной линии?

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

person M Noob    schedule 28.03.2016    source источник
comment
Итак, до сих пор, когда некоторые читали о $Q и Indirection, я смог выяснить следующее.   -  person M Noob    schedule 29.03.2016
comment
without using $R? $R[АНДОМ] ?   -  person tsafin    schedule 29.03.2016
comment
У вас был этот глобальный XNAME в вопросе раньше)   -  person Evgeny Shvarov    schedule 29.03.2016
comment
ХА-ХА, да, потом я начал искать кое-что и все переписал. Когда я пытался стать программистом, а M был моим первым реальным языком, у меня были некоторые проблемы.   -  person M Noob    schedule 29.03.2016
comment
Обязаны ли вы использовать ANSI M/Mumps (как это должны делать программисты Epic), разрешено ли вам использовать многие усовершенствования языка, которые были сделаны за последние 20 лет в Caché ObjectScript? Лично я старался избегать ANSI Mumps как чумы, но COS был достойным языком для быстрой разработки приложений [но я могу быть предвзятым, потратив на его реализацию 29 лет!]   -  person Scott Jones    schedule 16.04.2016


Ответы (5)


Если вы работаете в Cache и вам нужна утилита для этого, %GCHANGE — очень мощная программа, которая просто делает то, что вы описали. Я всегда использовал его как утилиту и никогда не вызывал его из программы, но я считаю, что есть ярлыки, где вы вызываете и передаете свои параметры.

Другое дело, что вы используете несколько косвенных обращений в цикле, что замедлит вашу программу. Я предлагаю объединить все это в строку и использовать команду E(X)ecute для косвенного обращения ко всей строке. Вы можете увидеть пример, представленный ниже.

Я включил два разных метода замены строки. Один использует $P и $L аналогично тому, что предложил Евгений Шваров, а второй метод использует $F и $E .

Второй метод в среднем работал на 33 % быстрее в глобальном масштабе из 100 000 узлов и 4 замен на узел.

Я включу свои данные gen. и функции тестирования, которые я написал. Я написал их в устаревшем коде MUMPS, чтобы он работал на разных платформах.

ОБНОВЛЕНИЕ: я только что проверил документацию GTM. %GCE — аналогичная утилита, доступная в GTM. ОБНОВЛЕНИЕ: я изменил функцию REPLACE, чтобы правильно учитывать проблему с 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
person Arya Rasouli    schedule 29.03.2016
comment
Это действительно здорово, я многому научился у вас всех. Большое спасибо. - person M Noob; 31.03.2016

Без использования $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 !
person Jonathan Parrish    schedule 12.05.2016

Как насчет этого?

    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
}
person Evgeny Shvarov    schedule 28.03.2016

К сожалению, я пока не могу публиковать комментарии, и это должно было быть больше похоже на комментарий к предыдущему решению и вопрос о том, что такое фактическая свинка, сгенерированная 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,

Измените, например, «ЛИЗА» на «ЭЛИЗА», «ЭЛИЗАБЕТ», «АЛИЗА», «МЕЛИЗА».

Пример, используемый ниже, заменяет 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
person C4xuxo    schedule 29.03.2016

Стандартный 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

Вот ссылка на то, как его использовать:

http://hardhats.org/kernel/html/x-replace%5Exlfstr.shtml .

person Sam Habiel    schedule 29.03.2016
comment
Если кто-то не обязан использовать ANSI Standard M/MUMPS, я бы не стал даже показывать такой код 40-летней давности, это определенно то, что приводит к тому, что люди избегают языка, даже если доступны лучшие альтернативы. Даже если вам нужно использовать ANSI Standard M/MUMPS (либо потому, что вам приходится использовать GT/M, либо этого требует ваш работодатель [например, Epic]), этот стиль кодирования с отдельными символами вместо прописанных имен команд и локальными переменными следует избегать с именем %[1-8] с большим количеством команд в каждой строке. - person Scott Jones; 16.04.2016