Я думаю, не lookaround подход будет более эффективным и читаемым:
text="stack overflow... is a popular website."
gsub("*[[:space:]]*(\\.+)[[:space:]]*", " \\1 ", text)
## => [1] "stack overflow ... is a popular website . "
См IDEONE demo
Я обновил пост, так как требуется пространство перед и после пунктуации.
[[:space:]]*
вокруг (\\.+)
соответствует нулю или более пробелам и (\\.+)
будет соответствовать одному или нескольким периодам. (...)
образуют группу захвата , значение которой хранится в пронумерованном буфере # 1, к которому мы можем получить доступ, используя обратную ссылку \1
из шаблона замены. Таким образом, \1
заменяется периодами, захваченными рисунком. Захват более эффективен, чем использование обращений, поскольку нет накладных расходов на проверку текста до/после текущей позиции.
Теперь если вам нужно обработать все знаки пунктуации, используйте [[:punct:]]
:
gsub("[[:space:]]*([[:punct:]]+)[[:space:]]*", " \\1 ", text)
См R regex help:
[:punct:]
знаки пунктуации:
! " # $ % & ' () * + , - ./: ; < = > ? @ [ \ ]^_ ` { | } ~.
Code demo:
text="Hi!stack overflow... is a popular website, I visit it every day."
gsub("[[:space:]]*([[:punct:]]+)[[:space:]]*", " \\1 ", text)
## => [1] "Hi ! stack overflow ... is a popular website , I visit it every day . "
UPDATE в переносимых СЛОВ
Чтобы избежать сопоставления дефис слов, вы можете сопоставить и пропустить в -
, которые окруженное словоразделами:
text="Hi!stack-overflow... is a popular website, I visit it every day."
gsub("\\b-\\b(*SKIP)(*F)|\\s*(\\p{P}+)\\s*", " \\1 ", text, perl=T)
## => [1] "Hi ! stack-overflow ... is a popular website , I visit it every day . "
См. demo
'' GSUB делает ... (или 'GSUB ("([[: punct:]] +)", "\\ 1", text, fixed = FALSE) 'для любого типа пунктуации) – Cath
Только периоды, а как насчет других знаков препинания? –
@stribizhev все знаки препинания должны быть отделены от слов, но многоточие должно рассматриваться как единичные объекты и не разделяться в процессе – Antoine