I need to parse a string in ruby which contain vars of ids and names like this {2,Shahar}.
The string is like this:
text = "Hello {1,Micheal}, my name is {2,Shahar}, nice to meet you!"
when I am trying to parse it, the regexp skips the first } and I get something like this:
text.gsub(/\{(.*),(.*)\}/, "\\2(\\1)")
=> "Hello Shahar(1,Micheal}, my name is {2), nice to meet you!"
while the required resault should be:
=> "Hello Michael(1), my name is Shahar(2), nice to meet you!"
I would be thankful to anyone who can help.
Thanks
Shahar
The greedy .* matches too much. It means "any string, maximum possible length". So the first (.*) matches 1,Micheal}, my name is {2, then the comma matches the comma, and the second (.*) matches Shahar (and the final \} matches the closing braces.
Better be more specific. For example, you could restrict the match to allow only characters except braces to ensure that a match will never extend beyond the scope of a {...} section:
text.gsub(/\{([^{}]*),([^{}]*)\}/, "\\2(\\1)")
Or you could do this:
text.gsub(/\{([^,]*),([^}]*)\}/, "\\2(\\1)")
where the first part may be any string that doesn't contain a comma, the second part may be any string that doesn't contain a }.
Related
I'm trying to create a regex pattern to match particular sets of text in my string.
Let's assume this is the string ^foo{bar}#Something_Else
I would like to match ^foo{} skipping entirely the content of the brackets.
Until now i figured out how to get all everything with this regex here \^(\w)\{([^\}]+)} but i really don't know how to ignore the text inside the curly brackets.
Anyone has an idea? Thanks.
Update
This is the final solution:
puts script.gsub(/(\^\w+)\{([^}]+)(})/, '[BEFORE]\2[AFTER]')
Though I'd prefer this with fewer groups:
puts script.gsub(/\^\w+\{([^}]+)}/, '[BEFORE]\1[AFTER]')
Original answer
I need to replace the ^foo{} part with something else
Here is a way to do it with gsub:
s = "^foo{bar}#Something_Else"
puts s.gsub(/(.*)\^\w+\{([^}]+)}(.*)/, '\1SOMETHING ELSE\2\3')
See demo
The technique is the same: you capture the text you want to keep and just match text you want to delete, and use backreferences to restore the text you captured.
The regex matches:
(.*) - matches and captures into Group 2 as much text as possible from the start
\^\w+\{ - matches ^, 1 or more word characters, {
([^}]+) - matches and captures into Group 2 1 or more symbols other than }
} - matches the }
(.*) - and finally match and capture into Group 3 the rest of the string.
If you mean to match ^foo{} by a single match against a regex, it is impossible. A regex match only matches a substring of the original string. Since ^foo{} is not a substring of ^foo{bar}#Something_Else, you cannot match that with a single match.
I have a string and I want to remove all non-word characters and whitespace from it. So I thought Regular expressions would be what I need for that.
My Regex looks like that (I defined it in the string class as a method):
/[\w&&\S]+/.match(self.downcase)
when I run this expression in Rubular with the test string "hello ..a.sdf asdf..," it highlioghts all the stuff I need ("hellloasdfasdf") but when I do the same in irb I only get "hello".
Has anyone any ideas about why that is?
Because you use match, with returns one matching element. If you use scan instead, all should work properly:
string = "hello ..a.sdf asdf..,"
string.downcase.scan(/[\w&&\S]+/)
# => ["hello", "a", "sdf", "asdf"]
\w means [a-zA-Z0-9_]
\S means any non-whitespace character [a-zA-Z_-0-9!##$%^&*\(\)\\{}?><....etc]
so using a \w and \S condition is ambiguous.
Its like saying What is an intersection of India and Asia. Obviously its going to be India. So I will suggest you to use \w+.
and you can use scan to get all matches as mentioned in the second answer :
string = "hello ..a.sdf asdf..,"
string.scan(/\w+/)
Suppose I have the following string:
mystring = "start/abc123/end"
How can you splice out the abc123 with something else, while leaving the "/start/" and "/end" elements intact?
I had the following to match for the pattern, but it replaces the entire string. I was hoping to just have it replace the abc123 with 123abc.
mystring.gsub(/start\/(.*)\/end/,"123abc") #=> "123abc"
Edit: The characters between the start & end elements can be any combination of alphanumeric characters, I changed my example to reflect this.
You can do it using this character class : [^\/] (all that is not a slash) and lookarounds
mystring.gsub(/(?<=start\/)[^\/]+(?=\/end)/,"7")
For your example, you could perhaps use:
mystring.gsub(/\/(.*?)\//,"/7/")
This will match the two slashes between the string you're replacing and putting them back in the substitution.
Alternatively, you could capture the pieces of the string you want to keep and interpolate them around your replacement, this turns out to be much more readable than lookaheads/lookbehinds:
irb(main):010:0> mystring.gsub(/(start)\/.*\/(end)/, "\\1/7/\\2")
=> "start/7/end"
\\1 and \\2 here refer to the numbered captures inside of your regular expression.
The problem is that you're replacing the entire matched string, "start/8/end", with "7". You need to include the matched characters you want to persist:
mystring.gsub(/start\/(.*)\/end/, "start/7/end")
Alternatively, just match the digits:
mystring.gsub(/\d+/, "7")
You can do this by grouping the start and end elements in the regular expression and then referring to these groups in in the substitution string:
mystring.gsub(/(?<start>start\/).*(?<end>\/end)/, "\\<start>7\\<end>")
Apparently I still don't understand exactly how it works ...
Here is my problem: I'm trying to match numbers in strings such as:
910 -6.258000 6.290
That string should gives me an array like this:
[910, -6.2580000, 6.290]
while the string
blabla9999 some more text 1.1
should not be matched.
The regex I'm trying to use is
/([-]?\d+[.]?\d+)/
but it doesn't do exactly that. Could someone help me ?
It would be great if the answer could clarify the use of the parenthesis in the matching.
Here's a pattern that works:
/^[^\d]+?\d+[^\d]+?\d+[\.]?\d+$/
Note that [^\d]+ means at least one non digit character.
On second thought, here's a more generic solution that doesn't need to deal with regular expressions:
str.gsub(/[^\d.-]+/, " ").split.collect{|d| d.to_f}
Example:
str = "blabla9999 some more text -1.1"
Parsed:
[9999.0, -1.1]
The parenthesis have different meanings.
[] defines a character class, that means one character is matched that is part of this class
() is defining a capturing group, the string that is matched by this part in brackets is put into a variable.
You did not define any anchors so your pattern will match your second string
blabla9999 some more text 1.1
^^^^ here ^^^ and here
Maybe this is more what you wanted
^(\s*-?\d+(?:\.\d+)?\s*)+$
See it here on Regexr
^ anchors the pattern to the start of the string and $ to the end.
it allows Whitespace \s before and after the number and an optional fraction part (?:\.\d+)? This kind of pattern will be matched at least once.
maybe /(-?\d+(.\d+)?)+/
irb(main):010:0> "910 -6.258000 6.290".scan(/(\-?\d+(\.\d+)?)+/).map{|x| x[0]}
=> ["910", "-6.258000", "6.290"]
str = " 910 -6.258000 6.290"
str.scan(/-?\d+\.?\d+/).map(&:to_f)
# => [910.0, -6.258, 6.29]
If you don't want integers to be converted to floats, try this:
str = " 910 -6.258000 6.290"
str.scan(/-?\d+\.?\d+/).map do |ns|
ns[/\./] ? ns.to_f : ns.to_i
end
# => [910, -6.258, 6.29]
I have the following string:
"h3. My Title Goes Here"
I basically want to remove the first four characters from the string so that I just get back:
"My Title Goes Here".
The thing is I am iterating over an array of strings and not all have the h3. part in front so I can't just ditch the first four characters blindly.
I checked the docs and the closest thing I could find was chomp, but that only works for the end of a string.
Right now I am doing this:
"h3. My Title Goes Here".reverse.chomp(" .3h").reverse
This gives me my desired output, but there has to be a better way. I don't want to reverse a string twice for no reason. Is there another method that will work?
To alter the original string, use sub!, e.g.:
my_strings = [ "h3. My Title Goes Here", "No h3. at the start of this line" ]
my_strings.each { |s| s.sub!(/^h3\. /, '') }
To not alter the original and only return the result, remove the exclamation point, i.e. use sub. In the general case you may have regular expressions that you can and want to match more than one instance of, in that case use gsub! and gsub—without the g only the first match is replaced (as you want here, and in any case the ^ can only match once to the start of the string).
You can use sub with a regular expression:
s = 'h3. foo'
s.sub!(/^h[0-9]+\. /, '')
puts s
Output:
foo
The regular expression should be understood as follows:
^ Match from the start of the string.
h A literal "h".
[0-9] A digit from 0-9.
+ One or more of the previous (i.e. one or more digits)
\. A literal period.
A space (yes, spaces are significant by default in regular expressions!)
You can modify the regular expression to suit your needs. See a regular expression tutorial or syntax guide, for example here.
A standard approach would be to use regular expressions:
"h3. My Title Goes Here".gsub /^h3\. /, '' #=> "My Title Goes Here"
gsub means globally substitute and it replaces a pattern by a string, in this case an empty string.
The regular expression is enclosed in / and constitutes of:
^ means beginning of the string
h3 is matched literally, so it means h3
\. - a dot normally means any character so we escape it with a backslash
is matched literally