JasonBorne
JasonBorne

Reputation: 97

Regex to grab full firstname and first letter of last name

I have a list of users grabbed by the Etc Ruby library:

Thomas_J_Perkins

Jennifer_Scanner

Amanda_K_Loso

Aaron_Cole

Mark_L_Lamb

What I need to do is grab the full first name, skip the middle name (if given), and grab the first character of the last name. The output should look like this:

Thomas P

Jennifer S

Amanda L

Aaron C

Mark L

I'm not sure how to do this, I've tried grabbing all of the characters: /\w+/ but that will grab everything.

Upvotes: 1

Views: 3708

Answers (9)

Cary Swoveland
Cary Swoveland

Reputation: 110675

I'm in the don't-use-a-regex-for-this camp.

str1 = "Alexander_Graham_Bell"
str2 = "Sylvester_Grisby"

"#{str1[0...str1.index('_')]} #{str1[str1.rindex('_')+1]}"
  #=> "Alexander B"
"#{str2[0...str2.index('_')]} #{str2[str2.rindex('_')+1]}"
  #=> "Sylvester G"

or

first, last = str1.split(/_.+_|_/)
  #=> ["Alexander", "Bell"] 
first+' '+last[0]
  #=> "Alexander B" 

first, last = str2.split(/_.+_|_/)
  #=> ["Sylvester", "Grisby"] 
first+' '+last[0]
  #=> "Sylvester G" 

but if you insist...

r = /
    (.+?)     # match any characters non-greedily in capture group 1
    (?=_)     # match an underscore in a positive lookahead 
    (?:.*)    # match any characters greedily in a non-capture group 
    (?:_)     # match an underscore in a non-capture group
    (.)       # match any character in capture group 2
    /x        # free-spacing regex definition mode

str1 =~ r
$1+' '+$2
  #=> "Alexander B"

str2 =~ r
$1+' '+$2
  #=> "Sylvester G"

You can of course write

r = /(.+?)(?=_)(?:.*)(?:_)(.)/

Upvotes: 1

Avneesh Srivastava
Avneesh Srivastava

Reputation: 103

/^[A-Za-z]{5,15}\s[A-Za-z]{1}]$/i This will have the following criteria: 5-15 characters for first name then a whitespace and finally a single character for last name.

Upvotes: -1

Nafaa Boutefer
Nafaa Boutefer

Reputation: 2359

using the split method is much better

full_names.map do |full_name|
   parts = full_name.split('_').values_at(0,-1)
   parts.last.slice!(1..-1)
   parts.join(' ')
end

Upvotes: 0

Ron Rosenfeld
Ron Rosenfeld

Reputation: 60199

And another attempt using a replacement method:

result = subject.gsub(/^([^_]+)(?:_[^_])?_([^_])[^_]+$/, '\1 \2')

We capture the entire string, with the relevant parts in capturing groups. Then just return the two captured groups

Upvotes: 0

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626758

You can use

^([^\W_]+)(?:_[^\W_]+)*_([^\W_])[^\W_]*$

And replace with \1_\2. See the regex demo

The [^\W_] matches a letter or a digit. If you want to only match letters, replace [^\W_] with \p{L}.

^(\p{L}+)(?:_\p{L}+)*_(\p{L})\p{L}*$

See updated demo

The point is to match and capture the first chunk of letters up to the first _ (with (\p{L}+)), then match 0+ sequences of _ + letters inside (with (?:_\p{L}+)*_) and then match and capture the last word first letter (with (\p{L})) and then match the rest of the string (with \p{L}*).

NOTE: replace ^ with \A and $ with \z if you have independent strings (as in Ruby ^ matches the start of a line and $ matches the end of the line).

Ruby code:

s.sub(/^(\p{L}+)(?:_\p{L}+)*_(\p{L})\p{L}*$/, "\\1_\\2")

Upvotes: 1

IslandUsurper
IslandUsurper

Reputation: 11

Let's see if this works:

/^([^_]+)(?:_\w)?_(\w)/

And then you'll have to combine the first and second matches into the format you want. I don't know Ruby, so I can't help you there.

Upvotes: 0

xuanduc987
xuanduc987

Reputation: 1077

This is my attempt:

/([a-zA-Z]+)_([a-zA-Z]+_)?([a-zA-Z])/

See demo

Upvotes: 0

SteveTurczyn
SteveTurczyn

Reputation: 36860

You don't always need regular expressions.

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. Jamie Zawinski

You can do it with some simple Ruby code

string = "Mark_L_Lamb"
string.split('_').first + ' ' + string.split('_').last[0]
=> "Mark L"

Upvotes: 6

shivam
shivam

Reputation: 16506

I think its simpler without regex:

array = "Thomas_J_Perkins".split("_") # split at _
array.first + " " + array.last[0] # .first prints first name .last[0] prints first char of last name
#=> "Thomas P"

Upvotes: 6

Related Questions