2013-08-05 4 views
0

Я использую драгоценный камень креветки, чтобы прочитать 60-страничный сборник PDF, содержащий финансовые и демографические данные для десятков людей. Задача, с которой я сталкиваюсь, заключается в том, что я хочу иметь возможность записывать имя/специальный идентификатор (в одной строке) и последующие строки, относящиеся к этому человеку, в то время как каждая строка сканируется. Используя метод сканирования рубина для строк, я был в состоянии захватить только финансовый с каждым матчем возвращения строки таким образом:ruby ​​regex и многострочные строки

[<invoice no.>, <service type>, <modifier (if any)>, <service_date>, <units>, <amount>] 

Я попытался связать идентификатор с финансовыми данными несколько строк вниз, и то измените его, когда ИД изменится, но ничего не сработало. Я собираюсь сделать это задним путем? Мой опыт с регулярным выражением скуден (и вообще программирование).

Ниже приведен код, который работает только с финансовыми данными:

PDF::Reader.new(file).pages.each do |page| 
    page.raw_content.scan(/^\(\s(\d{6})\s+\d\s+(\w\d{4})\s+(0580|TT|1C|1C\s+1F)?\s+(\d+\/\d+\/\d+)\s+\d+\/\d+\/\d+\s+(\d+\.\d+)\s+(\d+\.\d+)/) do |line|   
    line.collect {|x| x.strip! if !x.nil?} 
    print "#{line.join(' ')}\n" 
    Cycle.check_details(line) 
    end 
end 

А вот выборки того, что puts page.raw_content производит (есть много пустых пробелов, содержащихся в этих строках).

(REG LOC CLIENT SERVICE NAME     BIRTH DATE RECIPIENT ID PRIOR AUTHORIZATION #)' 
(xx xxx xxxxx  xxxxxxx LANNISTER, JAIME   xx/xx/xxxx xxxx <special ID>)' 
(DIAGNOSIS CODES: 887.0)' 
()' 
( INV # LINE # PROCEDURE CODE REVENUE CD FROM DT THRU DT  UNITS AMOUNT)' 
(<inv num>  1 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  2 <service_code> <modifier>     xx/xx/13 xx/xx/13  2.50  41.00)' 
(<inv num>  3 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  4 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  5 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  6 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  7 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(                CLAIM TOTAL 
    434.60 CLAIM ACCOUNT REF. xxxxxxxxxxxxxxxSUP)' 

(REG LOC CLIENT SERVICE NAME     BIRTH DATE RECIPIENT ID PRIOR AUTHORIZATION #)' 
(xx xxx xxxxx  xxxxxxx LANNISTER, JOFFREY   xx/xx/xxxx xxxx <special ID>)' 
(DIAGNOSIS CODES: 259.0)' 
()' 
( INV # LINE # PROCEDURE CODE REVENUE CD FROM DT THRU DT  UNITS AMOUNT)' 
(<inv num>  1 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  2 <service_code> <modifier>     xx/xx/13 xx/xx/13  2.50  41.00)' 
(<inv num>  3 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  4 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  5 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  6 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  7 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(                CLAIM TOTAL 
    434.60 CLAIM ACCOUNT REF. xxxxxxxxxxxxxxxSUP)' 
+0

Вы уверены, что все верно читает? –

+0

Ваши данные сбивают с толку, поэтому я думаю, что вы не показываете его правильно или не разбираете PDF правильно. Линии должны начинаться и заканчиваться округлыми скобками или с одиночными кавычками. Вместо этого ваши строки начинаются с левых парен и закрываются одной кавычкой. Пожалуйста, подтвердите, что правильно, и если что-то не так с данными, пожалуйста, исправьте это. –

+0

@theTinMan, я тоже это заметил, и когда я изначально учился использовать креветку, образец кода для отображения текста в терминале показывал то же самое: '() '' – user1582261

ответ

1

Не все кандидат для анализа с регулярным выражением. И иногда regex полезен после вы разбиваете данные на управляемые куски. Ваши данные являются примером второго случая. Как только он разбит некоторые, отдельные строки могут быть легко проанализированы.

Ваши данные в замешательстве, но это разгадывает его. Как только ведущие ( и конец )' удаляются, код разбивает его на отдельные строки с использованием split, а затем использует slice_before, чтобы разбить его на логические куски. После того, как те, которые были собраны, можно обрабатывать каждый блок разумным образом:

require 'prettyprint' 

data = "(REG LOC CLIENT SERVICE NAME     BIRTH DATE RECIPIENT ID PRIOR AUTHORIZATION #)' 
(xx xxx xxxxx  xxxxxxx LANNISTER, JAIME   xx/xx/xxxx xxxx <special ID>)' 
(DIAGNOSIS CODES: 887.0)' 
()' 
( INV # LINE # PROCEDURE CODE REVENUE CD FROM DT THRU DT  UNITS AMOUNT)' 
(<inv num>  1 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  2 <service_code> <modifier>     xx/xx/13 xx/xx/13  2.50  41.00)' 
(<inv num>  3 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  4 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  5 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  6 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  7 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(                CLAIM TOTAL 
    434.60 CLAIM ACCOUNT REF. xxxxxxxxxxxxxxxSUP)' 

(REG LOC CLIENT SERVICE NAME     BIRTH DATE RECIPIENT ID PRIOR AUTHORIZATION #)' 
(xx xxx xxxxx  xxxxxxx LANNISTER, JOFFREY   xx/xx/xxxx xxxx <special ID>)' 
(DIAGNOSIS CODES: 259.0)' 
()' 
( INV # LINE # PROCEDURE CODE REVENUE CD FROM DT THRU DT  UNITS AMOUNT)' 
(<inv num>  1 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  2 <service_code> <modifier>     xx/xx/13 xx/xx/13  2.50  41.00)' 
(<inv num>  3 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  4 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  5 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  6 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(<inv num>  7 <service_code> <modifier>     xx/xx/13 xx/xx/13  4.00  65.60)' 
(                CLAIM TOTAL 
    434.60 CLAIM ACCOUNT REF. xxxxxxxxxxxxxxxSUP)' 
" 

lines = data.gsub(/^\(|\)'$/m, '').split("\n").map{ |s| s.strip }.reject{ |s| s.empty? }.slice_before(/^REG\b/) 

В этот момент lines представляет собой массив массивов. Каждая подматрица состоит из блоков строк, начинающихся с «REG». Каждый раз, когда slice_before видит новую строку, соответствующую /^REG\b/, она создает новую подматрицу/блок. lines - это перечислитель, который похож на предварительный объект до получения массива или отдельной пары ключ/значение из хеша. Вы можете перебрать счетчиками, что то, что мы хотим сделать:

patient_data = lines.map { |sub_ary| 
    sub_ary[1][/(?:\S+ \s+){4} (\S+, \s+ \S+) \s+ (?:\S+ \s+){2} (.+)$/x] 
    patient_name, special_id = $1, $2 

    invoice_info = sub_ary[5..-3].map{ |line| 
    line[/^(\S+) \s+ \S+ \s+ (\S+) \s+ (\S+)/x] 
    [$1, $2, $3] 
    } 

    { 
    patient_name: patient_name, 
    special_id: special_id, 
    invoice_info: invoice_info 
    } 
} 

pp patient_data 

Какие выходы:

[{:patient_name=>"LANNISTER, JAIME", 
    :special_id=>"<special ID>", 
    :invoice_info=> 
    [["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"]]}, 
{:patient_name=>"LANNISTER, JOFFREY", 
    :special_id=>"<special ID>", 
    :invoice_info=> 
    [["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"], 
    ["<inv_num>", "<service_code>", "<modifier>"]]}] 

Это заставляет вас близко, но не решает вопрос полностью. Я намеренно оставляю это для вас, чтобы выяснить, как изменить код, чтобы захватить все поля, которые вы хотите из записей.

+0

Большое спасибо! Я заметил, что вы используете '$ 1' и т. Д. Для регулярных выражений. Я предполагаю, что каждый номер просто соответствует любому регулярному выражению в последовательности? Я попытался добавить инкрементально в часть 'invoice_info', и я получил остальную информацию о счете, которая мне нужна, но хочу убедиться, что это то, что она на самом деле делает. – user1582261

+0

Не предполагайте. Прочитайте [документацию для Regexp] (http://ruby-doc.org/core-2.0/Regexp.html). Существует несколько способов получить группы захвата, и иногда один из способов имеет больше смысла, чем другой. –

0

Если вы хотите, чтобы проверить вашу проверку регулярных выражений из http://rubular.com/

Это является очень полезным инструментом и имеет большинство основ для регулярного выражения в нижней части страницы

Смежные вопросы