Невозможно правильно разделить данные с помощью Ruby Regex Rubular
Я пытаюсь упорядочить и разбить содержимое электронных писем, извлеченных с помощью Net::POP3. В коде, когда я использую
p mail.pop
я получил
****************************\r\n>>=20\r\n>>11) <> Summary: Working with Vars on Social Influence =\r\nplatform=20\r\n>>=20\r\n>> Name: Megumi Lindon \r\n>>=20\r\n>> Category: Social Psychology=20\r\n>>=20\r\n>> Email: information@example.com =\r\n<mailto:information@example.com>=20\r\n>>=20\r\n>> Journal News: Saving Grace \r\n>>=20\r\n>> Deadline: 10:00 PM EST - 15 February=20\r\n>>=20\r\n>> Query:=20\r\n>>=20\r\n>> Lorem ipsum dolor sit amet \r\n>> consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n>>=20\r\n>> Duis aute irure dolor in reprehenderit in voluptate \r\n>> velit esse cillum dolore eu fugiat nulla pariatur. =20\r\n>>=20\r\n>> Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.=20\r\n>> Requirements:=20\r\n>>=20\r\n>> Psychologists; anyone with good knowdledge\r\n>> with sociology and psychology.=20\r\n>>=20\r\n>> Please do send me your article and profile\r\n>> you want to be known as well. Thank you!=20\r\n>> Back to Top <x-msg://30/#top> Back to Category Index =\r\n<x-msg://30/#SocialPsychology>\r\n>>-----------------------------------\r\n>>=20\r\n>>
Я пытаюсь разбить его и организовать
11) Summary: Working with Vars on Social Influence
Name: Megumi Lindon
Category: Social Psychology
Email: information@example.com
Journal News: Saving Grace
Deadline: 10:00 PM EST - 15 February
Questions:Lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Requirements: Psychologists; anyone with good knowdledge with sociology and psychology.
До сих пор я использовал Rubular, но с разными результатами, так как я все еще учусь правильно использовать регулярные выражения, gsub и split. Мой код до сих пор, как показано ниже.
p mail.pop.scan(/Summary: (.+) Name:/)
p mail.pop.scan(/Name: (.+) Category:/)
p mail.pop.scan(/Category: (.+) Email:/)
p mail.pop.scan(/Email: (.+) Journal News:/)
p mail.pop.scan(/Journal News: (.+) Deadline:/)
p mail.pop.scan(/Deadline: (.+) Questions:/)
p mail.pop.scan(/Questions:(.+) Requirements:/)
p mail.pop.scan(/Requirements:(.+) Back to Top/)
Но я получаю пустые массивы.
[]
[]
[]
[]
[]
[]
[]
[]
Хотите знать, как я могу сделать это лучше. Заранее спасибо.
1 ответ
О мой! Какой беспорядок!
Конечно, есть много способов решения этой проблемы, но я ожидаю, что все они включают в себя несколько этапов и множество проб и ошибок. Я могу только сказать, как я пошел об этом.
Множество маленьких шагов - это хорошо, по нескольким причинам. Во-первых, он разбивает проблему на управляемые задачи, решения которых можно тестировать индивидуально. Во-вторых, правила синтаксического анализа могут измениться в будущем. Если у вас есть несколько шагов, вам может потребоваться только изменить и / или добавить одну или две операции. Если у вас мало шагов и сложных регулярных выражений, вы можете начать все сначала, особенно если код был написан кем-то другим.
Скажем text
переменная, содержащая вашу строку
Во-первых, мне не нравятся все эти новые строки, потому что они усложняют регулярные выражения, поэтому первое, что я сделаю, это избавлюсь от них:
s1 = text.gsub(/\n/, '')
Далее есть много "20\r"
Это может быть хлопотно, так как мы можем захотеть сохранить другой текст, содержащий цифры, чтобы мы могли удалить их (а также "7941\r"
):
s2 = s1.gsub(/\d+\r/, '')
Теперь давайте посмотрим на поля, которые вы хотите, и непосредственно предшествующий и непосредственно следующий текст:
puts s2.scan(/.{4}(?:\w+\s+)*\w+:.{15}/)
# <> Summary: Working with V
#=>> Name: Megumi Lindon
#=>> Category: Social Psychol
#=>> Email: information@ex
#<mailto:information@exa
#=>> Journal News: Saving Grace
#=>> Deadline: 10:00 PM EST -
#=>> Query:=>>=>> Lorem ip
#=>> Requirements:=>>=>> Psycholo
# <x-msg://30/#top> Back
#<x-msg://30/#SocialPsy
Мы видим, что области интересов начинаются с "> "
и имя поля сопровождается ": "
или же ":="
, Давайте упростим, изменив ":="
в ": "
после имени поля и "> "
в " :"
перед именем поля:
s3 = s2.gsub(/(?<=\w):=/, ": ")
s4 = s3.gsub(/>\s+(?=(?:\w+\s+)*\w+: )/, " :")
В регулярном выражении для s3
, (?<=\w)
является "положительным взглядом сзади": совпадению должно предшествовать слово (которое не входит в состав совпадения); в регулярном выражении для s4
, (?=(?:\w+\s+)*\w+: )
является "положительным взглядом": после совпадения сразу же следует одно или несколько слов, после которых следует двоеточие, а затем пробел. Обратите внимание, что s3
а также s4
должен быть рассчитан в указанном порядке.
Теперь мы можем удалить все несловарные символы, кроме знаков препинания и пробелов:
s5 = s4.gsub(/[^a-zA-Z0-9 :;.?!-()\[\]{}]/, "")
а потом (наконец) split
на полях:
a1 = s5.split(/((?<= :)(?:\w+\s+)*\w+:\s+)/)
# => ["11) :", "Summary: ", "Working with Vars on Social Influence platform :",
# "Name: ", "Megumi Lindon :",
# "Category: ", "Social Psychology :",
# "Email: ", "informationexample.com mailto:informationexample.com :",
# "Journal News: ", "Saving Grace :",
# "Deadline: ", "10:00 PM EST 15 February :",
# "Query: ", "Lorem ipsum ...laborum. :",
# "Requirements: ", "Psychologists; anyone...psychology...Top xmsg:30#top...Psychology"]
Обратите внимание, что я приложил (?<= :)(?:\w+\s+)*\w+:\s+
в группе захвата, так что String#split будет включать биты, на которые он разбивается, в результирующем массиве.
Все, что остается, это некоторая очистка:
a2 = a1.map { |s| s.chomp(':') }
a2[0] = a2.shift + a2.first
#=> "11) Summary: "
a3 = a2.each_slice(2).to_a
#=> [["11) Summary: ", "Working with Vars on Social Influence platform "],
# ["Name: ", "Megumi Lindon "],
# ["Category: ", "Social Psychology "],
# ["Email: ", "informationexample.com mailto:informationexample.com "],
# ["Journal News: ", "Saving Grace "],
# ["Deadline: ", "10:00 PM EST 15 February "],
# ["Query: ", "Lorem...est laborum. "],
# ["Requirements: ", "Psychologists;...psychology. Please...xmsg:30#SocialPsychology"]]
idx = a3.index { |n,_| n =~ /Email: / }
#=> 3
a3[idx][1] = a3[idx][1][/.*?\s/] if idx
#=> "informationexample.com "
Присоединитесь к строкам и удалите лишние пробелы:
a4 = a3.map { |b| b.join(' ').split.join(' ') }
#=> ["11) Summary: Working with Vars on Social Influence platform",
# "Name: Megumi Lindon",
# "Category: Social Psychology",
# "Email: informationexample.com",
# "Journal News: Saving Grace",
# "Deadline: 10:00 PM EST 15 February",
# "Query: Lorem...laborum.",
# "Requirements: Psychologists...psychology. Please...well. Thank...Psychology"]
"Requirements"
все еще проблематично, но без дополнительных правил ничего больше не поделаешь. Мы не можем ограничить все значения категорий одним предложением, потому что "Query"
может иметь более одного. Если вы хотите ограничить "Requirements"
в одно предложение:
idx = a4.index { |n,_| n =~ /Requirements: / }
#=> 7
a4[idx] = a4[idx][/.*?[.!?]/] if idx
# => "Requirements: Psychologists; anyone with good knowsledge with sociology and psychology."
Если вы хотите объединить эти операции:
def parse_it(text)
a1 = text.gsub(/\n/, '')
.gsub(/\d+\r/, '')
.gsub(/(?<=\w):=/, ": ")
.gsub(/>\s+(?=(?:\w+\s+)*\w+: )/, " :")
.gsub(/[^a-zA-Z0-9 :;.?!-()\[\]{}]/, "")
.split(/((?<= :)(?:\w+\s+)*\w+:\s+)/)
.map { |s| s.chomp(':') }
a1[0] = a1.shift + a1.first
a2 = a1.each_slice(2).to_a
idx = a2.index { |n,_| n =~ /Email: / }
a2[idx][1] = a2[idx][1][/.*?\s/] if idx
a3 = a2.map { |b| b.join(' ').split.join(' ') }
idx = a3.index { |n,_| n =~ /Requirements: / }
a3[idx] = a3[idx][/.*?[.!?]/] if idx
a3
end