Reputation: 41
Given an email address in the form, '[email protected]'
or '[email protected]'
, how can one extract only the domain bar
(not bar.com
), without resorting to regex or a specialist library?
This post: 'How to get domain from email' almost answers my question, but I am unsure how to split domain 'bar.com'
, or whether another approach might exist.
Upvotes: 1
Views: 1519
Reputation: 84363
There are a number of string-based approaches, but one of the easiest (at least in my opinion) is to use String#rpartition to grab what you need after the terminal @
symbol in the address. For example, given an address stored in an email variable:
# Get domain-parts.
email.rpartition('@').last
# Get domain parts without the TLD.
email.rpartition('@').last.rpartition('.').first
This is simple, reliable, and (most importantly) relatively easy to read.
To see String#rpartition in action, and to see how flexible it is even with subdomains or atypical local-parts, consider the results of the following:
emails = %w[
[email protected]
[email protected]
[email protected]
[email protected]
]
emails.map { |email| email.rpartition(?@).last.rpartition(?.).first }
#=> ["bar", "bar", "bar.baz", "subdomain.example"]
One benefit of using String#partition or String#rpartition over String#split is that the two methods provide a natural fit for destructuring assignments. For example:
email = "[email protected]"
local_part, _, domain_part = email.rpartition ?@
#=> ["foo+extension.address", "@", "subdomain.example.com"]
hostname, _, top_level_domain = domain_part.rpartition ?.
#=> ["subdomain.example", ".", "com"]
Because destructuring gives you access to each part in a separate variable, this approach could be useful in creating a variety of alternative representations for your email addresses, such as a hash of domains and the local-parts within each domain. As a trivial example, consider:
address_list = Hash.new { |k,v| k[v] = [] }
emails = %w[[email protected] [email protected] [email protected]]
emails.each do |email|
local_part, _, domain_part = email.rpartition ?@
address_list[domain_part] << local_part
end
address_list
#=> {"example.com"=>["foo", "bar"], "other.example.com"=>["baz"]}
Obviously, you could make the structure as simple or as complex as you want. However, complicated structures like {"com"=>{"example"=>["foo"], "other.example"=>["bar"]}}
are unwieldy, and there's probably an X/Y problem with a simpler solution available. Nevertheless, it's useful to know you can do these sorts of things with de- and restructuring.
Upvotes: 1
Reputation: 10359
You can achieve this using String#split.
'[email protected]'.split('@')[1].split('.')[0] # => bar
... or if you need to support subdomains:
'[email protected]'.
split('@')[1].
reverse.
split('.').
drop(1).
map(&:reverse).
reverse.
join('.') # => qux.bar
Upvotes: 0
Reputation: 110685
Here are four valid email email addresses:
valid_email_addresses = ["[email protected]", "[email protected]", "\"[email protected]\"@c.com", "a@b"]
See the Wiki for "Email address".
We can extract the desired strings with the following method.
def domain_preface(str)
# something here like: return nil unless email_address_valid?(str)
s = str[str.rindex('@')+1..-1]
i = s.rindex('.')
return "" unless i
s[0..s.rindex('.')-1]
end
valid_email_addresses.each { |s| puts "%s: |%s|" % [s, domain_preface(s)] }
[email protected]: |b|
[email protected]: |b.c|
"[email protected]"@c.com: |c|
a@b: ||
Upvotes: 0
Reputation: 436
Use the split function:
mystring = "bar.com"
mystring.split('.') --> ["bar", "com"]
This even works if the string has subdomains:
mystring = "night.bar.com"
mystring.split('.') --> ["night", "bar", "com"]
edit: Oops, two minutes too late :)
Upvotes: 0