Как заменить шаблон повторяющихся символов/слов только в начале строки?

обратите внимание, что этот вопрос находится в контексте Юлии, и поэтому (насколько мне известно) PCRE.

предположим, что у вас была такая строка:

"sssppaaasspaapppssss"

и вы хотели индивидуально сопоставить повторяющиеся символы в конце строки (в случае нашей строки четыре символа "s" - то есть, чтобы matchall давал ["s","s","s","s"], а не ["ssss"]). Это легко:

r"(.)(?=*$)"

это практически тривиально (и легко использовать - replace(r"(.)(?=*$)","hell","k") даст "hekk" пока replace(r"(.)(?=*$)","hello","k") даст "hellk"). И его можно обобщить для повторяющихся шаблонов, переключив точку на что-то более сложное:

r"(S+)(?=( )*$)"

который, например, будет независимо соответствовать последним трем экземплярам " abc " в "abc abc defg abc h abc abc abc".

что затем приводит к вопросу... как бы вы соответствовали повторяющемуся символу или шаблону в старт строки, а? В частности, использование regex так, как это используется выше.

очевидным подходом было бы изменить направление вышеупомянутого регулярного выражения как r"(?<=^*)(.)" - но PCRE / Julia не позволяет lookbehinds иметь переменную длину (за исключением случаев, когда она фиксирована-переменная, например (?<=ab|cde)), и таким образом выдает ошибку. Следующая мысль-использовать "K " как что-то вроде r"^*K(.)", но это только удается соответствовать первому символу (предположительно, потому что он "продвигается" после его сопоставления и больше не соответствует знак вставки.)

для ясности: я ищу регулярное выражение, которое, например, приведет к

replace("abc abc defg abc h abc abc abc",<regex here>,"hello")

производства

"hello hello defg abc h abc abc abc"

как вы можете видеть, он заменяет каждый " abc "с самого начала" hello", но только до первого несоответствия. Обратный, который я предоставляю выше, делает это на другом конце строки:

replace("abc abc defg abc h abc abc abc",r"(S+)(?=( )*$)","hello")

производит

"abc abc defg abc h hello hello hello"

2 ответов


можно использовать \G якорь, который соответствует позиции после предыдущего матча или в начале строки. Таким образом, вы обеспечиваете непрерывность результатов от начала строки до последнего вхождения:

\G(\S+)( (?= ))?

демо

или иметь возможность соответствовать до конца строки:

\G(\S+)( (?=(?: |\z)))?

для двигателей PCRE style, к сожалению, нет способа сделать это без
переменную длину просмотра назад.

чистое решение невозможно.
Есть нет \G якорный трюк, который может это сделать.

вот почему якорь \G не будет работать.

с якорем, единственная гарантия у вас есть, что последний матч
результатом стал матч, в котором было проверено, что переднее перекрытие равно
к текущий матч.

в результате, вы можете только глобально подходите к N-1 дубликатов с самого начала.

вот доказательство:

регулярное выражение:

 # (?:\G([a-c]+)(?=))

 (?:
      \G 
      ( [a-c]+ )                    # (1)
      (?=
            
      )
 )

вход:

abcabcabcbca

выход:

 **  Grp 0 -  ( pos 0 , len 3 ) 
abc  
 **  Grp 1 -  ( pos 0 , len 3 ) 
abc  
------------
 **  Grp 0 -  ( pos 3 , len 3 ) 
abc  
 **  Grp 1 -  ( pos 3 , len 3 ) 
abc  

вывод:

хотя ты знаю на Nth один из предыдущих lookahead,
the Nth никто не может сравниться без состояния текущего lookahead.

извините, и удачи!
Дайте мне знать, если вы найдете чистое решение regex.