R регулярное выражение просто не совсем правильно

#regex #r

#регулярное выражение #r

Вопрос:

У меня проблема с регулярным выражением в R. Может быть, я просто слишком долго смотрел на это. У меня есть строки вида

 'thing1 - thing2'
'thingA - thingB'
 

где первое отделено от второго пробелом, тире и другим пробелом. Первое — это комбинация букв, цифр, косых черт и точек; второе может быть таким же или не существовать (в этом случае также нет разделительной черточки). Я хочу использовать regmatches with gregexpr для поиска шаблонов, соответствующих первой и второй частям. Это что-то вроде

 regmatches(
  'thing1 - thing2',
  gregexpr('^(\w|\s|\.|/) (\s-\s){0,1}', 'thing1 - thing2', perl=T)
)
 

Хорошо и хорошо. Но иногда thing1 бывает сложно, с тире без пробелов (например 10-43 ), или это может быть точная строка Blue - MC , что, очевидно, нарушает правило «разделять по \s-\s «. И я просто не могу правильно использовать регулярное выражение! Я пытался

 regmatches(
  c('10-43', 'Blue - MC'),
  gregexpr(
    '^\w(\w|\s|\.|/\S-\S) \s-\s{0,1}|^Blue\s-\sMC', 
    c('10-43', 'Blue - MC'), perl=T
  )
)
 

и я получаю c('10', 'Blue') . Помогите? Спасибо!

и

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

1. Вы действительно должны предоставить больше примеров ввода / желаемого вывода. Итак, вы хотите не допускать пробелов. Вы просто хотите, чтобы все было слева от тире и справа? Всегда будет тире?

2. Если нужно разделить два элемента, они всегда будут разделены пробелом.

3. Чего вы хотите вернуть из того, чего там нет? Как вы хотите, чтобы данные были возвращены?

4. Если второго элемента нет, т. Е. Нет пробела, я хочу вернуть все.

Ответ №1:

Я знаю, вы сказали, что хотите использовать gregexpr и regmatches , но почему бы и нет strsplit , поскольку все, что вы делаете, это разделяете строки, которые «всегда будут разделены пробелом-тире-пробелом»?

Согласно вашему комментарию, вы можете разделить на пробел-тире-пробел, но сохранить Blue - MC , просто удалив Blue - MC из списка перед применением разделения. Затем вы можете добавить его обратно позже.

 > things <- c('thing1 - thing2', 'thingA - thingB', 'thingC', 'Blue - MC')
> w <- which(things == 'Blue - MC')
> ( s <- c(strsplit(things[-w], " - ", fixed = TRUE), things[w]) )
#[[1]]
#[1] "thing1" "thing2"

#[[2]]
#[1] "thingA" "thingB"

#[[3]]
#[1] "thingC"

#[[4]]
#[1] "Blue - MC"
 

Тогда, если вам нужно только первое из каждого из них,

 > sapply(s, "[", 1)
#[1] "thing1" "thingA" "thingC" "Blue - MC"
 

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

1. Если я сделаю strsplit, как я могу заставить его разделяться на все ‘ — ‘, кроме ‘Blue — MC’?

2. @TiffBrender Откуда нам знать, что не стоит разделять «Blue — MC». Чем это отличается от «Blue — MC». Это предложение strsplit, несомненно, хорошее.

3. @TiffBrender, я добавил это к ответу, но, пожалуйста, пересмотрите вопрос, чтобы включить в него то, чего вы не хотите Blue - MC .

4. @Ричард Скривен, это есть в вопросе, но он слегка скрыт. Спасибо за помощь. Я решил пойти с strsplit, разделившись на ‘(?! Синий) \s-\s (?!MC)’. Спасибо!

5. @TiffBrender Обратите внимание, что это также не приведет к разделению «Red — MC».

Ответ №2:

Когда я хочу захватить части сообщения, мне нравится использовать regcapturedmatches .Вспомогательная функция R. Я бы использовал его так

 v <- c("thing1 - thing2", "thingalone","Blue-MC","1 - 2")
m <- gregexpr('^(.*?)(?:\s-\s(.*))?

Это возвращает

      [,1]         [,2]    
[1,] "thing1"     "thing2"
[2,] "thingalone" ""      
[3,] "Blue-MC"    ""      
[4,] "1"          "2" 
 

Что, я полагаю, удовлетворяет вашим ожиданиям.


, v, perl=T)
regmatches(v, m)
do.call(rbind, regcapturedmatches(v,m))
Это возвращает


Что, я полагаю, удовлетворяет вашим ожиданиям.