Richard
Richard

Reputation: 164

How can I replace everything within a string but a group of substrings?

I'm trying to replace everything in my input string that is not /str|con|dex|wis|int|cha/, but I'm unsure of the correct syntax. I've tried the following:

input.gsub(/[^str|con|dex|wis|int|cha]/, '')
input.gsub(/[^str,con,dex,wis,int,cha]/, '')
input.gsub(/[^str|^con|^dex|^wis|^int|^cha]/, '')
input.gsub(/[^str,^con,^dex,^wis,^int,^cha]/, '')

The following inputs:

+4cha
+2 strength
-3wisdom
+1asdfdexasdf

should return:

cha
str
wis
dex

To be clear, I'm only expecting one occurrence of a substring within input.

Upvotes: 1

Views: 111

Answers (4)

3limin4t0r
3limin4t0r

Reputation: 21130

If your only expecting one occurrence you could use the String#[] method:

input = input[/str|con|dex|wis|int|cha/]

This gives you the first occurrence or nil if it doesn't match. If you'd like a default empty string simply change it to:

input = input[/str|con|dex|wis|int|cha/] || ''

Upvotes: 3

Sundeep
Sundeep

Reputation: 23667

From comment:

>> '+4cha'.gsub(/(str|con|dex|wis|int|cha)|./, '\1')
=> "cha"
>> '+2 strength'.gsub(/(str|con|dex|wis|int|cha)|./, '\1')
=> "str"
>> '-3wisdom'.gsub(/(str|con|dex|wis|int|cha)|./, '\1')
=> "wis"
>> '+1asdfdexasdf'.gsub(/(str|con|dex|wis|int|cha)|./, '\1')
=> "dex"

When two or more alternations match from same index, the precedence is left to right in order of declaration. So, whenever the capture group above matches, the left alternation wins and the string gets preserved via backreference. If the capture group doesn't match, . will match and \1 will be empty.

Upvotes: 1

A l w a y s S u n n y
A l w a y s S u n n y

Reputation: 38502

You can do this regex way https://regex101.com/r/bFwkIZ/1 to get only first group that matched.

re = /(?:.*?)(str|con|dex|wis|int|cha)(?:.*?)/m
str = '+4cha
+2 strength
-3wisdom
+1asdfdexasdf'

# Print the match result
str.scan(re) do |match|
    puts match.to_s
end

Upvotes: 1

Cereal
Cereal

Reputation: 3839

You don't have to match everything that's not that regex. You need to match everything that is.

inputs = [
  "+4cha",
  "+2 strength",
  "-3wisdom",
  "+1asdfdexasdf",
]
inputs.map do |input|
  matches = input.match(/str|con|dex|wis|int|cha/)
  matches[0] if matches
end.compact
# => ["cha", "str", "wis", "dex"]

So given an input string, you check if it matches any of str, con, dex, wis, int, or cha. If it does, you return the match. If it doesn't, you return nil.

Then, compact removes all nils from your array. Leaving you with an array of your matches.

Upvotes: 1

Related Questions