Заменить точку после цифры

Я столкнулся с проблемой, которая кажется простой, но решение, которое я нашел, не удовлетворяет. Я хочу заменить любую точку, за которой следует число, запятой. Например,

strings <- c("22.222.222", "12.323", "don.t replace")

будет успешно трансформирован как

[1] "22,222,222"    "12,323"        "don.t replace"

Первое решение, которое я попытался, было

str_replace_all(strings,
                "(?<=\\d+)\\.",
                ",")

но я получил следующее сообщение об ошибке:

Error in stri_replace_all_regex(string, pattern, replacement, vectorize_all = vec,  : 
 Look-Behind pattern matches must have a bounded maximum length. (U_REGEX_LOOK_BEHIND_LIMIT)

Когда я использую

str_replace_all(strings,
            "(?<=\\d{1,3})\\.",
            ",")

Я получаю правильное преобразование. Однако жестко запрограммированные цифры 1-3 - это не то, что мне нужно, и я не понимаю, почему \\d+ не работает, а \\d{1,3} работает.


person Ryan Erwin    schedule 07.03.2016    source источник
comment
Разве "(?<=\\d)\\." недостаточно хорошо?   -  person sgibb    schedule 08.03.2016
comment
Зачем нужен прогноз? Я имею в виду, что вы приняли ответ с прогнозным решением, и это действительно не то, что вам нужно здесь. Lookbehinds дорого обходятся с точки зрения производительности (по крайней мере, когда они размещаются в начале шаблона), и вам следует избегать их, когда это возможно. Обратите внимание, что просмотр назад, который ограничивает уже использованную подстроку, эффективен, но это не так.   -  person Wiktor Stribiżew    schedule 08.03.2016


Ответы (2)


Нет необходимости в квантификаторе +, все, что вам нужно, это соответствие последней цифре в последовательности. Так что просто поместите \d в ретроспективу.

str_replace_all(strings,
                "(?<=\\d)\\.",
                ",")
person Barmar    schedule 07.03.2016

Здесь вам не нужны какие-либо обходы, поскольку цифры являются известным подшаблоном, и вам не нужны какие-либо перекрывающиеся совпадения. Просто используйте группу захвата вокруг цифр и восстановите их в результате с помощью обратной ссылки:

> library(stringr)
> strings <- c("22.222.222", "12.323", "don.t replace")
> str_replace_all(strings, "(\\d+)\\.", "\\1,")
[1] "22,222,222"    "12,323"        "don.t replace"

Или с основанием R gsub:

> gsub("(\\d+)\\.", "\\1,", strings)
[1] "22,222,222"    "12,323"        "don.t replace"

См. демонстрацию регулярного выражения.

Обратите внимание, что (?<=\\d{1,3}) constrained-width look-behind работает, потому что разновидность регулярного выражения stringr имеет вид ОИТ. Это будет работать, если длина шаблона в ретроспективном просмотре может быть рассчитана заранее, поэтому ограничивающий квантификатор с минимальным и максимальным значениями работает нормально. Это не будет работать с регулярными выражениями PCRE (perl=T) с gsub. Просмотр назад с бесконечной шириной (с квантификаторами + и * внутри) поддерживается только в нескольких вариантах: модуль регулярных выражений Python PyPi, .NET, инструмент RegexBuddy, Vim.

person Wiktor Stribiżew    schedule 07.03.2016