2013-07-12 3 views
0

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

A — N° 1 2 janvier 2013 

TABLE OF CONTENT 

Topic à one ......... 30 Second Topic .......... 33 
Third - one ......... 3 Topic.with.dots .......... 33 
One more line ......................... 27 last topic ...... 34 

Я хочу, чтобы извлечь название «тема на один» в разделе, в «Вторая тема», «Третий -он», «Topic.with.dots», «еще один line 'и' last topic '

Любые идеи для соответствующего регулярного выражения?

+1

Кого вы можете использовать в регулярном выражении? Всегда добавляйте соответствующий тег к любому запросу регулярного выражения. Благодаря! –

+1

Какие символы разрешены в имени раздела? –

+0

@Tim Я использую Ruby 2 – denisjacquemin

ответ

2
# -*- coding: utf-8 -*- 
string = "A — N° 1 2 janvier 2013 

TABLE OF CONTENT 

Topic à one ......... 30 Second Topic .......... 33 
Third - one ......... 3 Topic.with.dots .......... 33 
One more line ......................... 27 last topic ...... 34" 
puts string.scan(/(\p{l}[\p{l} \.-]*)\s+\.+\s+\d+/i).flatten 

Это делает то, что вы хотите. Он также соответствует названиям одной буквы.

+1

Я бы предложил добавить '?' После первого '+' и, возможно, использовать '[\ t]' вместо '\ s' и использовать'/i'. – Qtax

+0

@Qtax Почему [\ t] вместо \ s? –

+0

Так что совпадение не может провести несколько строк (в случае какого-то нечетного текста). – Qtax

1

Следующее (неоптимизированное еще) регулярное выражение работает на ваш примере:

(?i)(?=[A-Z])(?:\.[A-Z-]+|[A-Z -]+)+\b 

Она нуждается в улучшении, хотя, например, если не-ASCII буква должна быть согласована, и есть некоторые возможные оптимизации производительности, которые зависят от используется точный аромат регулярного выражения.

See it on regex101.

Для Руби 2, я хотел бы предложить /(?=\p{L})(?:\.[\p{L}-]++|[\p{L} -]+)+\b/

-1

Вот решение в Perl:

$ cat tmp 
Topic one ......... 30 Second Topic .......... 33 Third one ......... 3 Topic.with.dots .......... 33 One more line ......................... 27 last topic ...... 34 


$ cat tmp | perl -ne 'while (m/((?:\w|[. ])+?) [.]+ \d+/g) { print "$1\n" }' 
Topic one 
Second Topic 
Third one 
Topic.with.dots 
One more line 
last topic 

Небольшое пояснение того, что я делаю здесь, внутренний набор скобок (?:...) не являются отлов, так что они предназначены только для группировки, и они группа слово -char (\w) или пробел или точку [. ], а затем, так как у вас больше точек, матч не является жадным +?, и весь матч идет в , который печатается.

НТН

--EDIT--

Рубин имеет почти все конструкты Perl, включая регулярное выражение, и это прямой конверсии! (! Не знаю, почему это должно было быть отвергнуто) FWIW, здесь в Ruby:

while ARGF.gets 
    puts $_.scan(/((?:\w|[. ])+?) [.]+ \d+/) 
end 
+1

Пока это работает, OP запросил решение Ruby. –

+0

@theTinMan Давай, регулярное выражение является регулярным выражением. Обычно не очень сложно использовать регулярное выражение с одного языка в другом. – rednaw

+0

Onigmo - это только подмножество PCRE. – sawa

1
string.scan(/(\S.*?)\s+\.{2,}\s+\d+/).flatten 
# => 
[ 
    "Topic one", 
    "Second Topic", 
    "Third one", 
    "Topic.with.dots", 
    "One more line", 
    "last topic" 
] 
1

Подобно @ Саввы:

puts text.scan(/([a-zA-Z .]+?) \.\.++ \d+/).flatten.map(&:strip) 
# >> Topic one 
# >> Second Topic 
# >> Third one 
# >> Topic.with.dots 
# >> One more line 
# >> last topic 

(мне нравится его рисунок лучше, хотя .)