Захват нескольких экземпляров подгруппы - PullRequest
1 голос
/ 02 августа 2020

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

value AGEGRP_
 1 = "0 to 9 years"
 2 = "10 to 14 years"
 3 = "20 years and over"
 88 = "Not available"
;

Я хочу получить следующее:

Group 1: AGEGRP (note: without underscore)
Group 2: 1
Group 3: 0 to 9 years
Group 4: 2
Group 5: 10 to 14 years
Group 6: 3
Group 7: 20 years and over
Group 8: 88
Group 9: Not available

Конечно, количество меток значений будет различаться для каждой переменной.

Используя regex101.com, я построил следующее выражение:

value (.+)_(?:\R|\z)((\s(.+) = "(.+)"(?:\R|\z))+);

Моя функция:

parse_sas_variable_labels <- function(text) {
 pattern <- "value (.+)_(?:\\R|\\z)((\\s(.+) = \"(.+)\"(?:\\R|\\z))+);"
 l <- str_match_all(text, pattern) # to extract all patterns on the same line 
 df <- map_dfr(l, ~ tibble(var = .x[,2], label = .x[,3]))
 return(df) 
}

Это не совсем работает: это дает мне

Group 1.    AGEGRP
Group 2.    1 = "0 to 9 years"
            2 = "10 to 14 years"
            3 = "20 years and over"
            88 = "Not available"
Group 3.    88 = "Not available"
Group 4.    88
Group 5.    Not available

Только группы 1, 4 и 5 соответствуют тому, что я хочу; но затем он возвращает только последнюю итерацию меток значений, которые он находит, и пропускает метки для возрастов 0-10, 10-19 и 20+. Похоже, что объяснение, согласно regex101.com:

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

Как мне исправить мое выражение?

1 Ответ

1 голос
/ 02 августа 2020

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

Захватите все строки с назначением с помощью

value (.+)_((?:\R\s.+ = ".+")+)\s*;

Затем извлеките ключи и значения отдельно от Группы 2:

(?m)^\h*(.+?)\h*=\h*"(.+)"

См. доказательство

ПОЯСНЕНИЕ

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (?m)                     set flags for this block (with ^ and $
                           matching start and end of line) (case-
                           sensitive) (with . not matching \n)
                           (matching whitespace and # normally)
--------------------------------------------------------------------------------
  ^                        the beginning of a "line"
--------------------------------------------------------------------------------
  \h*                      horizontal whitespace (0 or more times (matching the most
                           amount possible))
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    .+?                      any character except \n (1 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  \h*                      horizontal whitespace (0 or more times (matching the most
                           amount possible))
--------------------------------------------------------------------------------
  =                        '='
--------------------------------------------------------------------------------
  \h*                      'h' (0 or more times (matching the most
                           amount possible))
--------------------------------------------------------------------------------
  "                        '"'
--------------------------------------------------------------------------------
  (                        group and capture to \2:
--------------------------------------------------------------------------------
    .+                       any character except \n (1 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
  )                        end of \2
--------------------------------------------------------------------------------
  "                        '"'
...