Отрицательный предварительный просмотр в R для сопоставления фрагментов с разделителями в строке, которые не содержат определенного символа

#r #regex #regex-lookarounds #regex-negation

#r #регулярное выражение #regex-поисковые запросы #регулярное выражение-отрицание

Вопрос:

Я пытаюсь извлечь (из строки) все фрагменты символов между двумя rn выражениями, которые не содержат пробелов. Для этого я использую оператор отрицательного предвидения.

Это моя строка:

 my_string <- "rnContent: base64rnrnDBhHBrnDGlVrnPAAHJrnAwQUrn"
  

И это то, что я пробовал:

 pat <- "\r\n (?! )\r\n.*"

out <- unlist(regmatches(my_string,
                         regexpr(pat, my_string, perl=TRUE)))

  

Это то, что я получил в R:

 > out
 [1] "rnrnDBhHBrn"

  

Как вы можете видеть, он останавливается при первом совпадении.

Редактировать

Мой ожидаемый результат в этом случае будет заключительной частью строки.

 > out
 [1] "DBhHBrnDGlVrnPAAHJrnAwQUrn"
  

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

 my_string <- "rnNot ThisrnrKeepThisrnKeepThisrnNot ThisrnKeepThisrn"
  

Предложения по базовому подходу R были бы высоко оценены.

Заранее спасибо.

Комментарии:

1. Для удобства чтения и тестирования я бы настоятельно рекомендовал сократить ваш пример, чтобы сделать его более читаемым и понятным, а также проиллюстрировать сложность «извлекать несколько частей, если в других фрагментах в середине строки есть еще один или два пробела». Если бы входные данные были my_string <- "rnBad Has SpacesrnrnKeepThisrnKeepThisToornNot ThisrnChunk2arnChunk2b" , каким был бы ваш ожидаемый результат?

2. Что касается работы над решением, предварительный просмотр используется, когда вы хотите что-то проверить после совпадения. Но вы не хотите никаких пробелов в совпадении, а не пробелов после совпадения. Я бы предложил попробовать `pat = «\r\ n[^ ] \ r \n». Жадный характер сопоставления в этом случае должен обеспечить максимальное совпадение.

3. Спасибо @Gregor Thomas. Я отредактировал текст. Что касается вашего другого предложения, оно сработало для первого примера, но не тогда, когда в других фрагментах есть более одного пробела. Я попытаюсь поработать над этим и посмотреть, что я получу. Еще раз спасибо

4. Что-то вроде regex101.com/r/hlrbQJ/1 ? Или (?m)^S (?:RS )*$ ( демо )?

5. @allanvc Как досадно, библиотека PCRE не была скомпилирована с PCRE_BSR_ANYCRLF опцией. Я обновил ответ базовым решением R.

Ответ №1:

Я предлагаю использовать

 (?m)^S (?:RS )*$
  

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

  • (?m) — многострочный режим включен
  • ^ — этот якорь теперь соответствует всем начальным позициям строки
  • S — один или несколько символов без пробелов
  • (?:RS )* — ноль или более повторений последовательности разрыва строки, а затем один или несколько символов без пробелов
  • $ — конец строки.

R demo:

 library(stringr)
my_string <- "rnContent: base64rnrnDBhHBrnDGlVrnPAAHJrnAwQUrn"
pat <- "(?m)^\S (?:\R\S )*$"
unlist(str_extract_all(my_string, pat))
## => [1] "DBhHBrnDGlVrnPAAHJrnAwQU"

my_string <- "rnNot ThisrnrnKeepThisrnKeepThisrnNot ThisrnKeepThisrn"
unlist(str_extract_all(my_string, pat))
## => [1] "KeepThisrnKeepThis" "KeepThis"
  

Базовое использование R

Обратите внимание, что в базовом R используется механизм PCRE, и $ в многострочном режиме (когда (?m) используется) совпадают только непосредственно перед n . Поскольку у вас есть rn окончания строк, вы не можете использовать plain $ для обозначения конца строки. Использование r не является хорошей идеей ( r$ ), поскольку вы не хотите иметь r на выходе. Вы можете указать PCRE, чтобы он обрабатывал CRLF, CR или LF как последовательность окончания строки с помощью (*ANYCRLF) глагола PCRE:

 unlist(regmatches(my_string, gregexpr("(*ANYCRLF)(?m)^\S (?:\R\S )*$",my_string, perl=TRUE)))
  

Обратите внимание (*ANYCRLF) , что глагол PCRE должен быть в начале шаблона regex.

Смотрите эту демонстрацию R онлайн.