Reputation: 3552
I'm writing a short class to extract email addresses from documents. Here is my code so far:
# Class to scrape documents for email addresses
class EmailScraper
EmailRegex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
def EmailScraper.scrape(doc)
email_addresses = []
File.open(doc) do |file|
while line = file.gets
temp = line.scan(EmailRegex)
temp.each do |email_address|
puts email_address
emails_addresses << email_address
end
end
end
return email_addresses
end
end
if EmailScraper.scrape("email_tests.txt").empty?
puts "Empty array"
else
puts EmailScraper.scrape("email_tests.txt")
end
My "email_tests.txt" file looks like so:
[email protected]
[email protected]
[email protected]
When I run this script, all I get is the "Empty array" printout. However, when I fire up irb and type in the regex above, strings of email addresses match it, and the String.scan function returns an array of all the email addresses in each string. Why is this working in irb and not in my script?
Upvotes: 2
Views: 854
Reputation: 52326
Several things (some already mentioned and expanded upon below):
\z
matches to the end of the string, which with IO#gets will typically include a \n
character. \Z
(upper case 'z') matches the end of the string unless the string ends with a \n
, in which case it matches just before.emails_addresses
\A
and \Z
is fine while the entire line is or is not an email address. You say you're seeking to extract addresses from documents, however, so I'd consider using \b
at each end to extract emails delimited by word boundaries.File.foreach()...
rather than the clumsy-looking File.open...while...gets
thingThere's a smarter one here: http://www.regular-expressions.info/email.html (clicking on that odd little in-line icon takes you to a piece-by-piece explanation). It's worth reading the discussion, which points out several potential pitfalls.
Even more mind-bogglingly complex ones may be found here.
class EmailScraper
EmailRegex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\Z/i # changed \z to \Z
def EmailScraper.scrape(doc)
email_addresses = []
File.foreach(doc) do |line| # less code, same effect
temp = line.scan(EmailRegex)
temp.each do |email_address|
email_addresses << email_address
end
end
email_addresses # "return" isn't needed
end
end
result = EmailScraper.scrape("email_tests.txt") # store it so we don't print them twice if successful
if result.empty?
puts "Empty array"
else
puts result
end
Upvotes: 3
Reputation: 80105
When you read the file, the end of line is making the regex fail. In irb, there probably is no end of line. If that is the case, chomp the lines first.
regex=/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
line_from_irb = "[email protected]"
line_from_file = line_from_irb +"/n"
p line_from_irb.scan(regex) # => ["[email protected]"]
p line_from_file.scan(regex) # => []
Upvotes: 0
Reputation: 93066
You used at the end \z
try to use \Z
according to http://www.regular-expressions.info/ruby.html it has to be a uppercase Z to match the end of the string.
Otherwise try to use ^
and $
(matching the start and the end of a row) this worked for me here on Regexr
Upvotes: 0
Reputation: 26871
You have a typo, try with:
class EmailScraper
EmailRegex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
def EmailScraper.scrape(doc)
email_addresses = []
File.open(doc) do |file|
while line = file.gets
temp = line.scan(EmailRegex)
temp.each do |email_address|
puts email_address
email_addresses << email_address
end
end
end
return email_addresses
end
end
if EmailScraper.scrape("email_tests.txt").empty?
puts "Empty array"
else
puts EmailScraper.scrape("email_tests.txt")
end
Upvotes: 0
Reputation: 432
Looks like you're putting the results into emails_addresses, but are returning email_addresses. This would mean that you're always returning the empty array you defined for email_addresses, making the "Empty array" response correct.
Upvotes: 3