Regex для удаления несмежных дубликатов в R - PullRequest
1 голос
/ 22 февраля 2020

Пытается придумать регулярное выражение, которое удаляет дублирующиеся символы в строке (т.е. сохраняет только первое вхождение)

В частности, я хочу удалить все двоеточия после первого появления

s <- c("note: conducted by j:m",
       "location: made :n :apan",
       "date: 2010, ma: 3rd")

чтобы стать

note: conducted by jm
location: made in apan
date: 2010, ma 3rd

Лучшее, что я могу получить, это

library(stringr)
str_remove(string = s, pattern = "(?<=:)(.*?):(.*)")
# [1] "note:"     "location:"     "date:"

РЕДАКТИРОВАТЬ:

Второе лучшее, что я могу получить, это "(:)(?=.*\1)" на regex.com - он идентифицирует все, кроме последнего : (что-то вроде того, что я хочу), но не будет работать в R, не знаю почему?

str_remove(string = s, pattern = "(:)(?=.*\1)")
# [1] "note: conducted by j:m"  "location: made :n :apan" "date: 2010, ma: 3rd" 

Ответы [ 4 ]

2 голосов
/ 22 февраля 2020

Попробуйте этот шаблон:

(?:^[^:]*:|\G(?!^))[^:]*\K:

Теперь, что я не знаю, будет ли это применимо к Ruby, поскольку я почти ничего не знаю об этом, чтобы быть Честно говоря.

Я получил этот образец для работы над одной строкой, и я решил, что должен работать =)

str = "location: made : in japan: or what:"
str.gsub(/(?:^[^:]*:|\G(?!^))[^:]*\K:/, '')
2 голосов
/ 22 февраля 2020

Попробуйте использовать sub в два этапа:

first <- sub("^(.*?:).*", "\\1", s)
second <- sub("^.*?:", "", s)
second <- sub(":", "", second, fixed=TRUE)
out <- paste0(first, second)
out

[1] "note: conducted by jm"  "location: made in apan" "date: 2010, ma 3rd"

Данные:

s <- c("note: conducted by j:m",
       "location: made in :apan",
       "date: 2010, ma: 3rd")

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

Обратите внимание, что более краткий способ сделать это - использовать sub или, возможно, str_replace_all с функцией обратного вызова, но синтаксис не так прост.

1 голос
/ 22 февраля 2020

К сожалению, " Совпадения шаблонов Look-Behind должны иметь ограниченную максимальную длину. "

Итак, Подход Тима , вероятно, является путем к go путем

  1. разбиение каждой строки на две части,
  2. удаление всех : из второй части и
  3. повторное объединение первой и измененной второй части

Вот однострочная реализация:

library(stringr)
sapply(str_split(s, "(?<=:)", n = 2L), function(x) paste0(x[1L], str_remove_all(x[-1L], ":")))

, которая возвращает

[1] "note: conducted by jm"    "location: made n apan"    "date: 2010, ma 3rd"      
[4] "no double colon"          "test1:"                   "test2: colon1 colon2 end"

для расширенного выборочного вектора символов (включая несколько крайние случаи):

s <- c("note: conducted by j:m",
       "location: made :n :apan",
       "date: 2010, ma: 3rd",
       "no double colon",
       "test1::::",
       "test2: colon1: colon2: end")
0 голосов
/ 22 февраля 2020

Судя по изложенной проблеме, регулярные выражения кажутся слишком сложным способом сделать это. Разве не регулярное выражение намного проще? Как этот:

for s in ss:
    it = re.subn( ":", "#", s, count=1 ) #Replace the first ":" with "#" to distinguish it from others
    print( it[0].replace( ":", "" ).replace( "#", ":" ) ) #Remove remaining ":"s and bring back the original

Конечно, если вы предпочитаете решение на основе регулярных выражений по какой-то другой причине, это не сработает. (Кроме того, указанное решение дано в Python, а не в R, вы могли заметить.)

...