Reputation: 12003
I'm trying to match some strings in a text file with a regex, and then modify all places where the pattern is found. It's like a search and replace, but I'm trying to replace with a modified version of what was found (and I'm sure this has a name but I'm not familiar enough with it).
So I'm looking for strings that match [a-z]_[a-z]
(e.g., some_string
) and I want to replace it by removing the underscore and capitalizing the second lowercase word, essentially camel-casing it (someString
).
Any pointers on how to do this (the tricky part is I don't really know how to even Google for this).
Edit
I tried to simplify the question a bit to make it more generic, but I'm also trying to do this only in the case where the match doesn't happen in quotes. That is, I don't want to match underscores in quotes (so, no match here: "this_is_a_string"
...that should remain as is). I probably should have included this when I first made this post.
Upvotes: 2
Views: 143
Reputation: 89547
you can use a callback function with gsub, example:
"some_thing_good".gsub(/_([a-z])/) {|m| m[1].upcase}
To avoid strings inside double-quotes you can do that:
"\"look_at_me\" some_thing_good".gsub(/"[^"]+"|_[a-z]/) {|m| (m.length>2)? m : m[1].upcase }
The idea is to match them before and replace them by themselves. If i test the match length, i know immediatly which part of the alternation has been matched, since the second part contains only 2 characters and the first part at least 3 characters.
Upvotes: 4
Reputation: 2828
I think the better approach is to use parentheses to enclose patterns that you are interesting in.
In your case, I would use the following regular expression:
string.gsub(/(?<=[a-z])_([a-z]+)/) {|s| "#{s[1].upcase}#{s[2..-1]}"}
This regexp can be read in two parts, the first ask for string that starts with valid char and the second is followed by "_" and a sequence of valid chars.
Inside the block code, you can use Regexp.last_match and will return the MatchData where you can access each pattern inside the parentheses, ex:
string.gsub(/(?<=[a-z])_([a-z]+)/) do |s|
p Regexp.last_match.to_a # this will print all sub-patterns found
"#{s[1].upcase}#{s[2..-1]}" # return formatted string
end
As you mentioned, you are not interesting in patterns inside quotes. I would use a regular expression inside other. The first one to remove quoted string and second one to search for patterns:
string.scan(/(\"[^\"]+\"|([^\"]+))/) do |s|
next s[0] unless s[1] # skip quoted data
# replace snake case to camel case
s[1].gsub(/(?<=[a-z])_([a-z]+)/) {|s| "#{s[1].upcase}#{s[2..-1]}"}
end
Upvotes: 1