Точное совпадение с шаблоном в неструктурированном наборе данных (текстовый или CSV-файл)

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

Мне нужно извлечь точно образец «BR1*********» (BR1 + ровно 9 цифр), который находится в середине строки: 61:, и образец «?54***» (?54 + ровно 3 цифры), который всегда находится в конце строки: 61 :.

Оба шаблона повторяются, но с разными комбинациями цифр.

Я пробовал с grep и grepl пока безуспешно. Я получаю в результате всегда всю строку, где этот шаблон примерно совпадает, но не точное совпадение символов и цифр.

Ниже представлена ​​небольшая часть набора данных:

:11:hgttu6576575?//80&&80980jhkhkhlkhkh  gjdggfjsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1678899458iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54160
:11:hgggdgf79878yiuhlkhkh  gjdggfhuihiuhuiou89 ioiojsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1234885765iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54190

person Sofia    schedule 25.10.2014    source источник
comment
Не могли бы вы показать dput(head(lines))? Кроме того, можете ли вы проверить, работает ли решение для меньшего набора данных? т.е. lines1 <- head(lines,20)   -  person akrun    schedule 26.10.2014
comment
Привет @akrun, спасибо за вопрос. Проблема в том, что это огромный файл (File.txt) с тысячами строк / строк, и я не могу использовать строки ‹-readLines (textConnection () и копировать и вставлять все строки в textConnection (). Любая идея приветствуется.   -  person Sofia    schedule 26.10.2014
comment
Я не говорю о публикации полного файла. Вы можете прочитать файл, используя lines <- readLines("file.txt"), а затем опубликовать первые несколько строк, используя dput(head(lines)). Также вы запускали код на подмножестве набора данных.   -  person akrun    schedule 26.10.2014


Ответы (5)


strapplyc в пакете gsubfn можно использовать для извлечения этих частей. Здесь мы извлекаем всю строку или, если вы хотите, чтобы часть цифр заключалась в круглые скобки вокруг части цифр, например pat1 <- "BR(1\\d{9})"

library(gsubfn)

pat1 <- "BR1\\d{9}"
pat2 <- "[?]54\\d{3}$"

strapplyc(lines, pat1, simplify = c)
## [1] "BR1678899458" "BR1234885765"

strapplyc(lines, pat2, simplify = c)
## [1] "?54160" "?54190"

или оба сразу:

strapplyc(lines, paste(pat1, pat2, sep = "|"), simplify = c)
## [1] "BR1678899458" "?54160"       "BR1234885765" "?54190"  

Используйте grep с теми же шаблонами, если вы хотите, чтобы номера строк (т.е. первая строка - 1, вторая строка - 2 и т. Д.) Вместо самих значений.

Добавлено. Прочитать файл не составит труда, если в нем всего несколько тысяч строк:

lines <- readLines("File.txt")

Если он действительно слишком велик, вы можете прочитать use read.csv.sql в пакете sqldf, который в одной строке кода может читать настройки, база данных sqlite считывает файл в него, а затем извлекает подмножество строк в R. Здесь мы предположили, что нет ? в файле, но если есть другой разделитель, которого нет в файле:

library(sqldf)

lines <- read.csv.sql("File.txt", header = FALSE, sep = "?", 
      sql = "select * from file where V1 like '%BR1%' or V1 like '%54%'")
# now use strapplyc as above
person G. Grothendieck    schedule 25.10.2014
comment
Привет @ G.Grothendieck, спасибо, что поделились своим решением. Проблема в том, что это огромный файл (File.txt) с тысячами строк / строк, и я не могу использовать строки ‹-readLines (textConnection () и копировать и вставлять все строк в textConnection (). Любая идея приветствуется. - person Sofia; 26.10.2014
comment
См. Обсуждение, добавленное в конце ответа. - person G. Grothendieck; 26.10.2014
comment
Привет, @ G.Grothendieck, большое спасибо за то, что поделились этим, а также за ваши усилия! Было очень полезно и полезно увидеть задачу с другой стороны. Спасибо! - person Sofia; 26.10.2014

dat <- readLines(textConnection(":11:hgttu6576575?//80&&80980jhkhkhlkhkh  gjdggfjsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1678899458iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54160
:11:hgggdgf79878yiuhlkhkh  gjdggfhuihiuhuiou89 ioiojsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1234885765iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54190"))

library(stringr)

unlist(str_match_all(dat, "(BR1[[:digit:]]{9})|(\\?54[[:digit:]]{3})"))
##  [1] "BR1678899458" "BR1678899458" ""             "?54160"      
##  [5] ""             "?54160"       "BR1234885765" "BR1234885765"
##  [9] ""             "?54190"       ""             "?54190"

Если бы мы знали больше о формате, в котором вам это нужно, мы могли бы помочь вам лучше.

person hrbrmstr    schedule 25.10.2014
comment
Привет, спасибо за ваши усилия и за то, что поделились своим решением. Да, вы совершенно правы, что формат очень важен (забыл об этом упомянуть, извините). Проблема в том, что это огромный файл (File.txt), и я не могу использовать dat = readLines (textConnection (). Поэтому я попробовал его с помощью: dat ‹-readLines (File.txt) library (stringr) unlist (str_match_all (dat , (BR1 [[: digit:]] {9}) | (\\? 54 [[: digit:]] {3}))) Но это не работает. В результате оба шаблона должны совпадать одновременно так как они соответствуют друг другу всегда в ряду: 61: Есть идеи? - person Sofia; 26.10.2014
comment
Привет @hrbrmstr, я проверил ваш код со всем файлом File.txt, и он сработал. Я понял, что раньше я использовал неправильный файл. Поскольку мне нужно, чтобы оба шаблона совпадали одновременно, для меня лучшим решением является: lines ‹-readLines (File.txt)› unlist (regmatches (lines, gregexpr ('BR1 \\ d {9} | \\? 54 \\ d {3} ', строки))) [1] BR1678899458? 54160 BR1234885765? 54190 BR1548812358? 54195 BR1768834128? 54199 - person Sofia; 26.10.2014

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

> unlist(regmatches(lines, gregexpr('BR1\\d{9}|\\?54\\d{3}', lines)))
# [1] "BR1678899458" "?54160"       "BR1234885765" "?54190" 
person hwnd    schedule 25.10.2014
comment
Начни называть тебя Доктором довольно скоро - person Rich Scriven; 25.10.2014
comment
@hwnd. Это оно! Вот и все! :) Большое спасибо за то, что поделились этим. lines ‹-readLines (File.txt)› unlist (regmatches (lines, gregexpr ('BR1 \\ d {9} | \\? 54 \\ d {3}', lines))) [1] BR1678899458? 54160 BR1234885765 ? 54190 BR1548812358? 54195 BR1768834128? 54199 - person Sofia; 26.10.2014

Я так понимаю описание естественного языка, что только 2 строки удовлетворяют требованию. Например, в 4-й строке есть шаблон «? 54nnn $», но эта строка не начинается с «: 61:»:

dat=readLines(textConnection(":11:hgttu6576575?//80&&80980jhkhkhlkhkh  gjdggfjsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1678899458iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54160
:11:hgggdgf79878yiuhlkhkh  gjdggfhuihiuhuiou89 ioiojsdf?kjhkuhsfk778798978**&
:27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
:61:kjljlkfjsdlBR1234885765iyuyugug7787?>?///uhhiuyi
jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54190"))

> grep("^:61:.+(BR1\\d{9}|[?]54\\d{3}$)", dat)
#[1] 3 7

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

> dat=readLines(textConnection(":11:hgttu6576575?//80&&80980jhkhkhlkhkh  gjdggfjsdf?kjhkuhsfk778798978**&
+ :27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
+ :61:kjljlkfjsdlBR1678899458iyuyugug7787?>?///uhhiuyi
+ :61:jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54160
+ :11:hgggdgf79878yiuhlkhkh  gjdggfhuihiuhuiou89 ioiojsdf?kjhkuhsfk778798978**&
+ :27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
+ :61:kjljlkfjsdlBR1234885765iyuyugug7787?>?///uhhiuyi
+ jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54190")
+ )
> grep("^:61:.+(BR1\\d{9}|[?]54\\d{3}$)", dat)
[1] 3 4 7
person IRTFM    schedule 25.10.2014
comment
Я прочитал это Learned R on my own со страницы вашего профиля. За какой книгой вы следили? - person Avinash Raj; 25.10.2014
comment
Моя первая книга была «Современная прикладная статистика на языке S» (2-е изд.)? Наверное, мне следовало подобрать хороший вводный текст, но в то время их действительно не было. После этого я учился, читая сообщения в списке рассылки Rhelp, а затем пытаясь ответить на них, а если я не мог, то запускал код другими участниками и разбивал его построчно, читал страницы справки и запускал примеры. - person IRTFM; 25.10.2014
comment
запуск кода другими участниками и разбиение его на части, чтение страниц справки и выполнение примеров. - Я не могу с этим согласиться. Вот как я провел большую часть своего обучения R - person Rich Scriven; 25.10.2014
comment
Привет, большое спасибо за то, что поделились своим решением. Проблема в том, что это огромный файл (File.txt) (я должен был упомянуть об этом в начале), и я не могу использовать dat = readLines (textConnection (). Поэтому я попробовал это с помощью: dat ‹-readLines (File.txt ) grep (^: 61:. + (BR1 \\ d {9} | [?] 54 \\ d {3} $), dat) Но это не работает Я получаю в результате целое число (0). На самом деле в результате оба шаблона должны быть сопоставлены одновременно, поскольку они соответствуют друг другу всегда в строке: 61: Есть идеи? - person Sofia; 26.10.2014
comment
Если оба шаблона находятся в одной строке, то аргумент шаблона будет просто сформирован путем помещения произвольного совпадения переменной длины между двумя шаблонами: "^:61:.+BR1\\d{9}.+[?]54\\d{3}$". Функция readlines() может принимать аргумент имени файла, поэтому, если размер файла не указан в гигабайтах, это не должно быть препятствием. - person IRTFM; 26.10.2014
comment
@BondedDust Спасибо за отзыв. Вы абсолютно правы! Код работает и для всего файла с readLines. Спасибо, что поделились. - person Sofia; 26.10.2014

Пытаться

   library(stringr)
   unlist(str_extract_all(lines, "(BR1\\d{9})|(\\?54\\d{3})"))
   #[1] "BR1678899458" "?54160"        "BR1234885765" "?54190"   

Обновлять

Если это большой файл, вы можете использовать stringi, что будет быстрее

  library(stringi)
  na.omit(unlist(stri_extract_all_regex(lines, "(BR1\\d{9})|(\\?54\\d{3})")))
  #[1] "BR1678899458" "?54160"       "BR1234885765" "?54190"     

данные

lines <- readLines(textConnection(':11:hgttu6576575?//80&&80980jhkhkhlkhkh  gjdggfjsdf?kjhkuhsfk778798978**&
 :27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
 :61:kjljlkfjsdlBR1678899458iyuyugug7787?>?///uhhiuyi jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54160
 :11:hgggdgf79878yiuhlkhkh  gjdggfhuihiuhuiou89 ioiojsdf?kjhkuhsfk778798978**&
 :27:jhkjhuiy867tjhfsh/.>?kjklh8ggdhkotrdkhofkhodkgj
 :61:kjljlkfjsdlBR1234885765iyuyugug7787?>?///uhhiuyi jhkhkjhiy878697y8hukjlu97 ??///khiuy8oujhuhijk?54190'))
person akrun    schedule 25.10.2014
comment
Привет, большое спасибо за то, что поделились своим решением. Результат выглядит неплохо. Проблема в том, что это огромный файл (File.txt) (я должен был упомянуть об этом в начале), и я не могу использовать dat = readLines (textConnection (), так как в txt.file тысячи строк, поэтому я попробовал это с: lines ‹-readLines (File.txt) library (stringr) unlist (str_extract_all (lines, (BR1 \\ d {9}) | (\\? 54 \\ d {3}))) Но это не ' t работа Я получаю в результате символ (0). Есть идеи, как это сделать с File.txt? - person Sofia; 26.10.2014
comment
Большое спасибо за то, что поделились обеими альтернативами кода. Это сделало фокус :). Извините, я понял, что раньше использовал не тот файл, но теперь он работал неплохо. библиотека (строка) ›unlist (str_extract_all (lines, (BR1 \\ d {9}) | (\\? 54 \\ d {3}))) [1] BR1678899458? 54160 BR1234885765? 54190 BR1548812358? 54195 BR1768834128? 54199 - person Sofia; 26.10.2014