Как заменить шаблон повторяющихся символов/слов только в начале строки?
обратите внимание, что этот вопрос находится в контексте Юлии, и поэтому (насколько мне известно) 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.