I would like to loop through regex matches and replace each match individually in the loop.
For example:
content.scan(/myregex/).each do |m|
m = 'new str'
end
How could I do that?
The reason why I want to do that is because each match will be replaced with a different output from a function.
Thanks for help
The following form of the gsub method will do exactly what you want:
gsub(pattern) {|match| block } → new_str
See http://ruby-doc.org/core-2.0.0/String.html#method-i-gsub for documentation.
If you're looking for the same thing every time then you could just do:
def some_function_here(args)
.... some logic creates replacement
while something == true
content.sub(/myregex/, replacement)
.... some logic to change replacement/or a call to a helper function
end
end
Not sure how you're generating the new replacement values, but from what I gather it appears that the easiest way to do it is to call the sub method on the string for your regex and replace them one at a time.
Related
I am working in Ruby. I need to create a regex that takes in a string, I suppose, and returns an array with only the words that start with "un" and end with "ing". I have no clue how to do it :/
def words_starting_with_un_and_ending_with_ing(text)
!!text.capitalize.scan(/\A+UN\Z+ING/)
end
Something like this:
def uning string
string.scan(/\b[Uu]n[a-z]*ing\b/)
end
See String#scan for more info. For a nice interactive introduction to Regex take a look at RegexOne.
I want to replace the content (or delete it) that does not match with my filter.
I think the perfect description would be an opposite sub. I cannot find anything similar in the docs, and I'm not sure how to invert the regex, but I think a method would probably be the more convenient.
An example of how it would work (I've just changed the words to make it more clear)
"bird.cats.dogs".opposite_sub(/(dogs|cats)\.(dogs|cats)/, '')
#"cats.dogs"
I hope it's easy enough to understand.
Thanks in advance.
String#[] can take a regular expression as its parameter:
▶ "bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#⇒ "cats.dogs"
For multiple matches one can use String#scan:
▶ "bird.cats.dogs.bird.cats.dogs".scan /(?:dogs|cats)\.(?:dogs|cats)/
#⇒ ["cats.dogs", "cats.dogs"]
So you want to extract the part that matches your regex?
You can use String#slice, for example:
"bird.cats.dogs".slice(/(dogs|cats)\.(dogs|cats)/)
#=> "cats.dogs"
And String#[] does the same.
"bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#=> "cats.dogs"
You cannot have a single replacement string because the part of the string that matches the regex might not be at the beginning or end of the string, in which case it's not clear whether the replacement string should precede or follow the matching string. I've therefore written the following with two replacement strings, one for pre-match, the other for post_match. I've made this a method of the String class as that's what you've asked for (though I've given the method a less-perfect name :-) )
class String
def replace_non_matching(regex, replace_before, replace_after)
first, match, last = partition(regex)
replace_before + match + replace_after
end
end
r = /(dogs|cats)\.(dogs|cats)/
"birds.cats.dogs.pigs".replace_non_matching(r, "", "")
#=> "cats.dogs"
"birds.cats.dogs".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
"birds.cats.dogs.mice.cats.dogs.bats".replace_non_matching(r, "snakes.", ".hens")
#=> "snakes.cats.dogs.hens"
Regarding the last example, the method could be modified to replace "birds.", ".mice." and ".bats", but in that case three replacement strings would be needed. In general, determining in advance the number of replacement strings needed could be problematic.
I've created a web framework that uses the following function:
def to_class(text)
text.capitalize
text.gsub(/(_|-)/, '')
end
To turn directory names that are snake_cased or hyphen-cased into PascalCased class names for your project.
Problem is, the function only removed _ and -, and doesn't capitalize the next letter. Using .capitalize, or .upcase, is there a way to achieve making your snake/hyphen_/-cased names into proper PascalCased class names?
gsub(/(?:^|[_-])([a-z])?/) { $1.upcase unless $1.nil? }
This splits the _-cased string into an array; capitalizes every member and glues the array back to a string:
def to_pascal_case(str)
str.split(/-|_/).map(&:capitalize).join
end
p to_pascal_case("snake_cased") #=>"SnakeCased"
Your code does not work for several reasons:
The resulting object of the capitalize method is discarded - you
should do something like text.capitalize! or text = text.capitalize.
But the capitalize method just upcases the first letter of the string,
not the first letter of every word.
Rails has a similar method called camelize. It basically capitalizes every part of the string consisting of [a-z0-9] and removes everything else.
You can probably golf it down to something smaller, but:
txt = 'foo-bar_baz'
txt.gsub(/(?:^|[-_])([a-z])/) { |m| m.upcase }.gsub(/[-_]/, '') # FooBarBaz
Suppose I have:
foo/fhqwhgads
foo/fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf/bar
And I want to replace everything that follows 'foo/' up until I either reach '/' or, if '/' is never reached, then up to the end of the line. For the first part I can use a non-capturing group like this:
(?<=foo\/).+
And that's where I get stuck. I could match to the second '/' like this:
(?<=foo\/).+(?=\/)
That doesn't help for the first case though. Desired output is:
foo/blah
foo/blah/bar
I'm using Ruby.
Try this regex:
/(?<=foo\/)[^\/]+/
Implementing #Endophage's answer:
def fix_post_foo_portion(string)
portions = string.split("/")
index_to_replace = portions.index("foo") + 1
portions[index_to_replace ] = "blah"
portions.join("/")
end
strings = %w{foo/fhqwhgads foo/fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf/bar}
strings.each {|string| puts fix_post_foo_portion(string)}
I'm not a ruby dev but is there some equivalent of php's explode() so you could explode the string, insert a new item at the second array index then implode the parts with / again... Of course you can match on the first array element if you only want to do the switch in certain cases.
['foo/fhqwhgads', 'foo/fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf/bar'].each do |s|
puts s.sub(%r|^(foo/)[^/]+(/.*)?|, '\1blah\2')
end
Output:
foo/blah
foo/blah/bar
I'm too tired to think of a nicer way to do it but I'm sure there is one.
Checking for the end-of-string anchor -- $ -- as well as the / character should do the trick. You'll also need to make the .+ non-greedy by changing it to .+? since the greedy version will always match right up to the end of the string, given the chance.
(?<=foo\/).+?(?=\/|$)
In other languages, in RegExp you can use /.../g for a global match.
However, in Ruby:
"hello hello".match /(hello)/
Only captures one hello.
How do I capture all hellos?
You can use the scan method. The scan method will either give you an array of all the matches or, if you pass it a block, pass each match to the block.
"hello1 hello2".scan(/(hello\d+)/) # => [["hello1"], ["hello2"]]
"hello1 hello2".scan(/(hello\d+)/).each do|m|
puts m
end
I've written about this method, you can read about it here near the end of the article.
Here's a tip for anyone looking for a way to replace all regex matches with something else.
Rather than the //g flag and one substitution method like many other languages, Ruby uses two different methods instead.
# .sub — Replace the first
"ABABA".sub(/B/, '') # AABA
# .gsub — Replace all
"ABABA".gsub(/B/, '') # AAA
use String#scan. It will return an array of each match, or you can pass a block and it will be called with each match.
All the details at http://ruby-doc.org/core/classes/String.html#M000812