Как шаблон разделения строк может стать самой подстрокой? - PullRequest
4 голосов
/ 20 сентября 2019

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

Допустим, что образец строкв форме:

test <- c("Some string that explains x. Conflict", 
          "Some string that explains y. Additional information. Precaution",
          "Some string that explains z. Justification.   Conflict") 

Я хочу разбить эти строки на следующий список:

[1] "Some string that explains x."
[2] "Conflict"
[3] "Some string that explains y. Additional information."
[4] "Precaution"
[5] "Some string that explains z. Justification."
[6] "Conflict"

В центре моей проблемы, мне нужно сохранить порядок.

Очевидно, что я упомянул шаблон:

pattern <- c("Conflict", "Precaution")

Большинство строк, которые у меня изначально были, имели двойной пробел между пояснительной частью и так называемым шаблоном, поэтому я мог просто использовать

unlist(strsplit(test, "\\s{2,}"))

чтобы дифференцировать их.Теперь я понимаю, что некоторые из них имеют только один пробел между ними, и этот метод больше не может функционировать, поскольку пояснительная строка будет разделена для каждого из его отдельных слов.

Извлечение их было вариантом, который я посмотрел, но когда я попытался, я бы потерял порядок, который должен сохранить (в итоге я создаю новый список только с извлеченной подстрокой).

Сstrsplit(), я не могу использовать указанный шаблон для функции, поскольку, разбивая строку на него, я удаляю сам шаблон.Я попытался использовать gsub() трюк, который я нашел, чтобы окружить шаблон "~", а затем разделить его соответствующим образом, но я оказался неудачным.

А именно,

 > unlist(strsplit(test, pattern))
[1] "Some string that explains x. "                        
[2] "Some string that explains y. Additional information. "
[3] "Some string that explains z. Justification.   "

По сути, какЯ мог бы разделить строки, используя указанный шаблон и получить желаемый результат?Кроме того, есть ли способ извлечь шаблон из исходных строк и вставить их в список в правильном порядке?

Ответы [ 4 ]

2 голосов
/ 20 сентября 2019

Если вы объедините два шаблона в один элемент patt, разделив их с помощью '|', этот новый шаблон будет соответствовать любому из двух исходных шаблонов в векторе test.Затем с помощью str_remove вы можете получить деталь без шаблона, а с помощью str_extract получите деталь, соответствующую одному из шаблонов.Теперь вы можете объединить эти два вектора в один, используя шаблон c(rbind(x, y))*.Это будет менее вычислительно эффективным, чем прямое использование регулярных выражений для получения частей, не относящихся к шаблону и шаблону, которые я предполагаю.

Примечание: Все это предполагает, что шаблон, который вы хотите извлечь, это просто "Конфликт" или "Мера предосторожности" ичтобы они могли появляться где угодно в строках.Это отличается от логики в некоторых других ответах, которые не идентифицируют эти два слова, а вместо этого идентифицируют последнюю часть строки.Не совсем понятно, что вы хотели, так что просто обратите внимание на разницу.

library(stringr)
patt <- paste(pattern, collapse = '|')
c(rbind(str_remove(test, patt), str_extract(test, patt)))

# [1] "Some string that explains x. "                        
# [2] "Conflict"                                             
# [3] "Some string that explains y. Additional information. "
# [4] "Precaution"                                           
# [5] "Some string that explains z. Justification.   "       
# [6] "Conflict" 

* См. Пример ниже.Это работает, потому что c преобразует матрицу в вектор по столбцам, и вы создаете матрицу с одним элементом от каждого вектора на столбец, связывая векторы вместе.

c(rbind(c('a', 'b', 'c'), c('A', 'B', 'C')))
#[1] "a" "A" "b" "B" "c" "C"
1 голос
/ 20 сентября 2019

Другой будет разделяться в последний раз .:

unlist(strsplit(test, "\\.\\s*(?=[^\\.]+$)", perl=TRUE))

# [1] "Some string that explains x"                         "Conflict" 
# [3] "Some string that explains y. Additional information" "Precaution"
# [5] "Some string that explains z. Justification"          "Conflict" 
1 голос
/ 20 сентября 2019

Возможность разделить на последний пробел.Здесь мы используем регулярное выражение, то есть для сопоставления одного или нескольких пробелов (+), которые следуют за . (?<=\\.) и предшествуют одному или нескольким непробельным символам (\\S+) до конца ($)) строки

library(tidyr)
library(tibble)
tibble(test) %>%
     separate_rows(test,  sep="(?<=\\.) +(?=\\S+$)")
# A tibble: 6 x 1
#  test                                                
#  <chr>                                               
#1 Some string that explains x.                        
#2 Conflict                                            
#3 Some string that explains y. Additional information.
#4 Precaution                                          
#5 Some string that explains z. Justification.         
#6 Conflict                                            

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

unlist(strsplit(test, "(?<=\\.) +(?=\\S+$)", perl = TRUE))

Если перед определением есть определенный вектор слов, нам нужно разделить, создайтерегулярное выражение на основе этого вектора

pat <- paste0("\\s+(?=\\b(", paste(pattern, collapse="|"), ")\\b)")

и использовать его в strsplit

unlist(strsplit(test, pat, perl = TRUE))
#[1] "Some string that explains x."              
#[2] "Conflict" 
#[3] "Some string that explains y. Additional information."
#[4] "Precaution"                                          
#]5] "Some string that explains z. Justification." 
#[6] "Conflict"                          
0 голосов
/ 23 сентября 2019

В свете того факта, что у вас могут быть случаи, которые вы не хотите отлавливать, вот что я бы предложил:

test <- c("Some string that explains x. Conflict",
          "Some string that explains y. Additional information. Precaution",
          "Some string that explains z. Justification.   Conflict",
          "A String You Don't Want Conflict",
          "Another string you don't want that ends with a single word.  Word" )

pattern <- c("Conflict", "Precaution") # Plus the other ~8 words you want
pattern.regex<-paste0("(\\.|\\?|!)\\s+(", paste(pattern, collapse="|"), ")$") # Pattern for punctuation that ends a sentence, one or more spaces, the words you want, and the end of a string

test2<-test[grep(pattern.regex, test, perl=T)] # A version of test without irrelevant values

А затем вы можете просто разбить каждую строку на test2, как вОтвет akrun (без необходимости указывать конкретные слова, поскольку мы уже ограничены test2, чтобы содержать только случаи, заканчивающиеся одним из ваших желаемых слов.

unlist(strsplit(test2, "(?<=\\.) +(?=\\S+$)", perl = TRUE))

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

  • Могут ли такие слова, как 'Конфликт', иметь точку после?
  • Должны ли они начинаться с заглавных или строчных / прописных букв?
  • Хотите ли вы случаи, подобные четвертому элементу test, в котором нет конца периода в конце сегмента перед последним словом?

В конечном счете, мой совет будет попробоватьиз вышесказанного и немного покопаться в наборе данных, чтобы увидеть, являются ли результаты слишком широкими или слишком узкими. Но это, по крайней мере, пересекает основную идею и обеспечивает некоторый уровень неопределенности в отношении того, как выr Необработанные данные выглядят.

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