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

#r #regex #stringr

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

Вопрос:

Пожалуйста, смотрите Ниже пример данных, с которыми я работаю, однако у меня в общей сложности более 100 тысяч записей.

обратите внимание, что ... в комментарии ниже UNIT это просто для того, чтобы оно соответствовало. Например, полный UNIT текст для первого элемента is 4- to 5-mm-diameter и пятого элемента is 3 1/2- to 4-inch-diameter и т.д.

 library(tidyverse)
                                                #i QTY    UNIT
parts <- c("6 4- to 5-mm-diameter plugs",       #1  6     4- to...diameter
           "6 large bricks",                    #2  6     large
           "1 1/3 shipment concrete",           #3  1.33  shipment
           "1 (14- to 15-oz) gold bars",        #4  1     (14- to 15-oz)
           "16 3 1/2- to 4-inch-diameter caps", #5  16    3 1/2- to...eter
           "1 1/2 tons sand",                   #6  1.5   tons
           "2 1 1/4- to 3-inch diameter caps",  #7  2     1 1/4- to...eter      
           "1/3 shipment cement")               #8  .333  shipment 
 

Я добился некоторого умеренного успеха, работая с некоторыми ответами на SO, но я сталкиваюсь с проблемами, когда UNIT текст также содержит смешанные дроби, как в пунктах 1 и 5:

 # Goal: extract QTY as mixed frac
parts %>% 
  str_extract("(\d [\/\d[ ]?]*|\d*)")

# i=1, 5 broken
#[1] "6 4"      "6 "       "1 1/3 "   "1 "       "16 3 1/2" "1 1/2 "  

# Goal: extract UNIT word
parts %>% 
  str_extract("[[:graph:]]{3,11}|[- to ].{5,21}")

# all i with some problem  
# [1] " 4- to 5-mm-diameter p" " large bricks"          " 1/3 shipment concrete"
# [4] " (14- to 15-oz) gold b" " 3 1/2- to 4-inch-diam" " 1/2 tons sand"
 

Мои цели — извлечь QTY и UNIT , как показано в комментарии к коду, от первой до последней записи, как 6, 6, 1 1/3, 1, 16, 1, 2, 1/3 — кроме того, я пытаюсь извлечь текст в разделе UNIT сокращенный, чтобы он поместился в разделе код — вот он полностью : 4- to 5-mm-diameter, large, shipment, (14- to 15-oz), 3 1/2- to 4-inch-diameter, tons, 1 1/4- to 3-inch diameter, shipment .

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

Спасибо.

редактировать: добавлен критический пример номер 8.

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

1. Я предположил, что ответ на любой изолированный вопрос может не решить его, т.Е. Решения для QTY не учитывают решения для строк, подобных UNIT в моем примере.

2. Проверьте ideone.com/pqbBC5 , работает ли это для вас?

3. Я добавил в список дополнительный элемент # 8, которого у меня раньше не было.

4. Планируются ли еще какие-либо дополнения?

Ответ №1:

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

 m <- str_match(parts, '^(\d (?:\s \d /\d )?|\d /\d )\s ((?:\d (?:-?in(?:ch)?|")?\s )*\S (?:\s to\s (?:\d (?:-?in(?:ch)?|")?\s )*\S )?)')
qty <- m[,2]
# => [1] "6"     "6"     "1 1/3" "1"     "16"    "1 1/2" "2"     "1/3"  
unit <- m[,3]
# => [1] "4- to 5-mm-diameter"       "large"                    
#    [3] "shipment"                  "(14- to 15-oz)"           
#    [5] "3 1/2- to 4-inch-diameter" "tons"                     
#    [7] "1 1/4- to 3-inch diameter" "shipment"      
 

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

  • ^ — начало строки
  • (d (?:s d /d )?|d /d ) — Группа 1 ( m[,2] ): одна или несколько цифр, за которыми следует необязательное вхождение одного или нескольких пробелов, одной или нескольких цифр / и одной или нескольких цифр, или a / , заключенный в одну или несколько цифр.
  • s — один или несколько пробелов
  • ((?:d (?:-?in(?:ch)?|")?s )*S (?:s tos (?:d (?:-?in(?:ch)?|")?s )*S )?) — Группа 2 ( m[,3] ):
    • (?:d (?:-?in(?:ch)?|")?s )* — ноль или более вхождений одной или нескольких цифр , за которыми следует необязательное вхождение a " или необязательный - , in а затем необязательная ch подстрока , а затем один или несколько пробелов
    • S — один или несколько символов, отличных от пробела («слово»)
    • (?:s tos (?:d (?:-?in(?:ch)?|")?s )*S )? — необязательное возникновение:
      • s tos to заключено одним или несколькими пробелами
      • (?:d (?:-?in(?:ch)?|")?s )* — см . выше
      • S — один или несколько символов, отличных от пробелов.

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

1. Спасибо за этот выдающийся ответ.