Разбить и извлечь часть строки (между "." И цифрой) в R - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть символьная переменная (companies) с наблюдениями, которые выглядят следующим образом:

  1. "612. Grt. Am. Mgt. & Inv. 7.33"
  2. "77. Wickes 4,61 "
  3. " 265. Wang Labs 8,75 "
  4. " 9. CrossLand Savings 6,32 "
  5. " 228. JPS Textile Group 2,00 "

Я пытаюсь разбить эти строки на 3 части:

  1. все цифры перед первым ".",
  2. все между первым "." иследующий номер (последовательно отформатированный #.##) и
  3. самого последнего номера (формат #.##).

Используя в качестве примера первые obs, я бы хотел: "612", "Grt. Am. Mgt & Inv", "5.01"

Я пытался определитьшаблон в rebus и использование str_match, но приведенный ниже код работает только в таких случаях, как obs # 2 и # 3.Он не отражает все вариации в средней части строки для захвата других аксов.

pattern2 <- capture(one_or_more(DGT)) %R% DOT %R% SPC %R% 
            capture(or(one_or_more(WRD), one_or_more(WRD) %R% SPC 
            %R% one_or_more(WRD))) %R% SPC %R% capture(DGT %R% DOT 
            %R% one_or_more(DGT))

str_match(companies, pattern = pattern2)

Есть ли лучший способ разделить строки на эти 3 части?

Я не знаком с regex, но я видел, что это много подсказывает (я новичок в R и Stack Overflow)

Ответы [ 5 ]

0 голосов
/ 19 февраля 2019

Вы должны быть в состоянии отладить написанное вами регулярное выражение.

> as.regex(pattern2)
<regex> ([\d]+)\.\s((?:[\w]+|[\w]+\s[\w]+))\s(\d\.[\d]+)

Подключите в regex101, и вы увидите, что ваши строки не всегда совпадают.Объяснение справа говорит вам, что вы можете разрешить только 1 или 2 пробела между точкой и числом.Кроме того, WRD (шаблон [\w]+) не соответствует точкам и любым другим символам, которые не являются буквами, цифрами или _.Теперь вы знаете, что вам нужно сопоставить вашу строку с

^(\d+)\.(.*?)\s*(\d\.\d{2})$

См. это демонстрационное выражение regex .Перевод в Rebus:

pattern2 <- START %R%            # ^ - start of string
 capture(one_or_more(DGT)) %R%   # (\d+) - Group 1: one or more digits
 DOT %R%                         # \. - a dot
 "(.*?)" %R%                     # (.*?) - Group 2: any 0+ chars as few as possible
 zero_or_more(SPC) %R%           # \s* - 0+ whitespaces 
 capture(DGT %R% DOT %R% repeated(DGT, 2)) %R% # (\d\.\d{2}) - Group 3: #.## number
END                              # $ - end of string

Проверка:

> pattern2
<regex> ^([\d]+)\.(.*?)[\s]*(\d\.[\d]{2})$

> companies <- c("612. Grt. Am. Mgt. & Inv. 7.33","77. Wickes 4.61","265. Wang Labs 8.75","9. CrossLand Savings 6.32","228. JPS Textile Group 2.00")
> str_match(companies, pattern = pattern2)
     [,1]                             [,2]  [,3]                    [,4]  
[1,] "612. Grt. Am. Mgt. & Inv. 7.33" "612" " Grt. Am. Mgt. & Inv." "7.33"
[2,] "77. Wickes 4.61"                "77"  " Wickes"               "4.61"
[3,] "265. Wang Labs 8.75"            "265" " Wang Labs"            "8.75"
[4,] "9. CrossLand Savings 6.32"      "9"   " CrossLand Savings"    "6.32"
[5,] "228. JPS Textile Group 2.00"    "228" " JPS Textile Group"    "2.00"

ПРЕДУПРЕЖДЕНИЕ : capture(lazy(zero_or_more(ANY_CHAR))) возвращает шаблон ([.]*?), который соответствует 0 или более точкам всего завозможно вместо сопоставления любых 0+ символов, потому что в rebus есть ошибка: он охватывает все символы repeated (one_or_more или zero_or_more) с [ и ], классом символов.Вот почему (.*?) добавляется «вручную».

Это можно решить или обойти, используя общую конструкцию, такую ​​как [\w\W] / [\s\S] или [\d\D]:

pattern2 <- START %R%                          # ^ - start of string
 capture(one_or_more(DGT)) %R%                 # (\d+) - Group 1: one or more digits
 DOT %R%                                       # \. - a dot
 capture(                                      # Group 2 start:
  lazy(zero_or_more(char_class(WRD, NOT_WRD))) #  - [\w\W] - any 0+ chars as few as possible
 ) %R%                                         # End of Group 2
 zero_or_more(SPC) %R%                         # \s* - 0+ whitespaces 
 capture(DGT %R% DOT %R% repeated(DGT, 2)) %R% # (\d\.\d{2}) - Group 3: #.## number
END

Проверьте:

> as.regex(pattern2)
<regex> ^([\d]+)\.([\w\W]*?)[\s]*(\d\.[\d]{2})$

См. Демоверсию regex .

0 голосов
/ 19 февраля 2019

Вы можете использовать 3 группы захвата:

([^.]+)\.\s+(\D+)\s+(\d\.\d{2})

Например

companies=c("612. Grt. Am. Mgt. & Inv. 7.33")
pattern="([^.]+)\\.\\s+(\\D+)\\s+(\\d\\.\\d{2})"
str_match(companies, pattern)

Результат

     [,1]                             [,2]  [,3]                   [,4]  
[1,] "612. Grt. Am. Mgt. & Inv. 7.33" "612" "Grt. Am. Mgt. & Inv." "7.33"

См. regex101 demo | R demo

Пояснение

  • ([^.]+) Захват в группе 1, соответствующий 1+ раз, не точка (не соответствует новой строкетакже используйте [^.\r\n])
  • \.\s+ Совпадение с точкой и 1+ раз символ пробела
  • (\D+) Захват в группе 2, соответствующий 1+ раз, а не цифра
  • \s+ Совпадение 1+ с символом пробела
  • (\d\.\d{2}) Захват в группе 3 цифры, точки и 2 цифры (формат #. ##)
0 голосов
/ 19 февраля 2019

Используйте следующее регулярное выражение:

^(.*?)\.(.*?)(?=\d)(.*)$

Демонстрация

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

0 голосов
/ 19 февраля 2019

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

delimitedString = gsub( "^([0-9]+). (.*) ([0-9.]+)$", "\\1,\\2,\\3", companies  )

do.call( 'rbind', strsplit(split = ",", x = delimitedString) )
#      [,1]  [,2]                   [,3]  
#[1,] "612" "Grt. Am. Mgt. & Inv." "7.33"
#[2,] "77"  "Wickes"               "4.61"
#[3,] "265" "Wang Labs"            "8.75"
#[4,] "9"   "CrossLand Savings"    "6.32"
#[5,] "228" "JPS Textile Group"    "2.00" 

Объяснение регулярных выражений :

  • ^[0-9]+: любой шаблон, состоящий из чисел от 0 до 9 в начале (т. е. ^) вашей строки
  • .*: жадное совпадение, в основном все, что окружено двумя пробелами в указанном выше случае
  • [0-9.]+$: снова цифры + точка и конец (т. Е. $) вашей строки

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

0 голосов
/ 19 февраля 2019

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

(.+?)\.\s+(.+)\s+(\d+\.\d+)

, которое будет собирать вашу информацию в группе 1, группе 2 и группе 3.

Демо

Здесь group1 записывает ваш первый номер перед информацией о компании, а group2 - информацию о компании, а group3 - последний номер формы #.##

Проверьте этот код r,

companies = c("612. Grt. Am. Mgt. & Inv. 7.33")
result <- str_match(companies, pattern = "(.+?)\\.\\s+(.+)\\s+(\\d+\\.\\d+)")
result[,2]
result[,3]
result[,4]

Печать

[1] "612"
[1] "Grt. Am. Mgt. & Inv."
[1] "7.33"
...