stringr для извлечения столбца текста

У меня есть строка, которая выглядит так:

t2 <- "============================================
                       Model 1    Model 2   
--------------------------------------------
education               3.66 ***    2.80 ***
                       (0.65)      (0.59)   
income                  1.04 ***    0.85 ***
                       (0.26)      (0.23)   
type: blue collar      -5.91      -27.55 ***
                       (3.94)      (5.41)   
type: white collar     -8.82 **   -24.12 ***
                       (2.79)      (5.35)   
income x blue collar                3.01 ***
                                   (0.58)   
income x white collar               1.91 *  
                                   (0.81)   
prop. female            0.01        0.08 *  
                       (0.03)      (0.03)   
--------------------------------------------
R^2                     0.83        0.87    
Adj. R^2                0.83        0.86    
Num. obs.              98          98       
============================================
*** p < 0.001, ** p < 0.01, * p < 0.05"

и я пытаюсь извлечь левый столбец, чтобы получить вектор, который выглядит так:

education
income
type: blue collar
type: white collar
income x blue collar
income x white collar
prop. female

Я новичок в regex и stringr и пытаюсь извлечь слова, следующие за разрывом строки:

library(stringr)
covariates <- str_extract_all(t2, "\n\\w+")
covariates

что немного приближает меня:

[1] "\neducation" "\nincome"    "\ntype"      "\ntype"      "\nincome"    "\nincome"    "\nprop"      "\nR"        
 [9] "\nAdj"       "\nNum"

но я не могу понять, как захватить весь столбец текста, например, получить полный «тип: синий воротничок» вместо «\ntype».


person Jeremy K.    schedule 22.08.2019    source источник
comment
Итак, только значения столбца 1 находятся между двумя --------------?   -  person Wiktor Stribiżew    schedule 22.08.2019
comment
@WiktorStribiżew Да, именно так, спасибо. Извините, я не был яснее.   -  person Jeremy K.    schedule 22.08.2019


Ответы (1)


Вы можете использовать

covariates <- str_extract_all(
        str_match(t2, "(?ms)^-{3,}\n(.*?)\n-{3,}$")[,2], 
        "(?m)^\\S.*?(?=\\h{2})"
)

Или, чтобы заставить его работать намного быстрее, используйте эти шаблоны unrolled:

covariates <- str_extract_all(
        str_match(t2, "(?m)^-{3,}\n(.*(?:\n(?!-{3,}$).*)*)\n-{3,}$")[,2],
        "(?m)^\\S\\H*(?:\\h(?!\\h)\\H*)*"
)

С помощью str_match(t2, "(?ms)^-{3,}\n(.*?)\n-{3,}$")[,2] вы извлекаете весь текст между двумя строками, состоящими из 3 или более дефисов. Вот детали этого узора:

  • (?ms) - многострочный (чтобы ^ соответствовало началу строки, а $ соответствовало концу строки) и однострочный/точечный (чтобы . также соответствовало разрыву строки) режимы -
  • ^ - начало строки
  • -{3,} - три и более дефиса
  • \n - новая строка
  • (.*?) - Группа 1: любые 0+ символов, но как можно меньше
  • \n - новая строка
  • -{3,} - три и более дефиса
  • $ - конец строки.

(?m)^\\S.*?(?=\\h{2}) используется позже в этой части строки и соответствует

  • (?m) - многострочный режим включен
  • ^ - начало строки
  • \\S - символ без пробелов
  • .*? - любые символы 0+, кроме символов разрыва строки, как можно меньше
  • (?=\\h{2}) - сразу справа от текущего местоположения должно быть 2 горизонтальных пробела.
person Wiktor Stribiżew    schedule 22.08.2019
comment
Редактирование, в котором вы объясняете, как работает каждая часть регулярного выражения, бесценно для людей, которые учатся, как я. Вы рекомендуете конкретный ресурс для изучения регулярных выражений? - person Jeremy K.; 22.08.2019
comment
@JeremyK.stringr использует библиотеку регулярных выражений ICU, и для нее довольно мало ресурсов. Используйте документы по регулярным выражениям ICU в качестве основного справочника. ICU близок к регулярному выражению Java, поэтому многое будет выглядеть одинаково. - person Wiktor Stribiżew; 22.08.2019
comment
@ДжеремиК. Я добавил намного лучшую альтернативу без объяснений, потому что эти шаблоны соответствуют точно тем же строкам, что и приведенные выше, но быстрее. Если вам нужны дополнительные сведения, прочитайте развертывание цикла в регулярном выражении. - person Wiktor Stribiżew; 22.08.2019
comment
Могу я задать еще один вопрос? Почему str_match(t2, "(?ms)^-{3,}\n(.*?)\n-{3,}$") возвращает два разных совпадения (это означает, что нам нужно выполнить str_match(t2, "(?ms)^-{3,}\n(.*?)\n-{3,}$")[,2], чтобы получить только релевантное. Если мы ищем ^-{3,}, я бы подумал, что будет возвращено только [,1], так как [,2] не t даже не начинается с ---. Еще раз спасибо за вашу неоценимую помощь. Я читал и работал над примерами по этому вопросу. - person Jeremy K.; 23.08.2019
comment
@ДжеремиК. str_match ищет одно совпадение с регулярным выражением во входной строке. Каждое совпадение может содержать захваченные подстроки, совпадающие с частями регулярного выражения в скобках (в отличие от str_extract, при котором захваты удаляются). Поскольку есть один, (.*?), вывод содержит матрицу с двумя столбцами, а так как нам нужен второй, я использовал [,2]. Вы можете заменить str_match двумя вызовами sub: sub("\n-{3,}(?:\n.*)?$", "", sub("^.*?\n-{3,}\n", "", t2)) - person Wiktor Stribiżew; 23.08.2019