How to split a string by slash in ruby - ruby

how can i split a string "DESKTOP-AHDESI\Username" by slash in ruby 2.7.1p83
tmp = "DESKTOP-AHDESI\Username"
print tmp
tmp = tmp.split("\\")
print tmp
i got:
Ruby Error: NoMethodError undefined method `gsub!'

Problem
Your tmp variable is enclosed in double-quotes, and contains a backslash which is being interpreted as an escape rather than a character literal. You can see this easily by simply pasting your string into a REPL like irb:
"DESKTOP-AHDESI\Username" #=> "DESKTOP-AHDESIUsername"
You need to handle the backslash specially in both your String methods.
Solution
One way to handle this is to use Ruby's alternate quoting mechanism. For example:
%q(DESKTOP-AHDESI\Username).split '\\' #=> ["DESKTOP-AHDESI", "Username"]
This may not help you directly, though.
Wherever the value from tmp is coming from, you need to refactor the code to ensure that your String is properly escaped before you assign it to your variable, or otherwise pre-process it. String#dump won't really help much if the value you're assigning is unescaped before assignment, so you're going to have to fix this in whatever code you're using to generate or grab the string in the first place.

First of all, you are giving the wrong string. \ is the escape character when you use inside the "". So It will try to escape the next character U but this character doesn't have any Job so it will print U on the screen. Modify your string like below, it will work.
tmp = "DESKTOP-AHDESI\\Username"
p tmp
tmp = tmp.split("\\")
p tmp
Output
"DESKTOP-AHDESI\\Username"
["DESKTOP-AHDESI", "Username"]

Related

Regexp.escape adds weird escapes to a plain space

I stumbled over this problem using the following simplified example:
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty. Indeed, this is the case for many strings, but not for this case:
searchstring = "D "
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
p line
It turns out, that line is printed as "D " afterwards, i.e. no replacement had been performed.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string, in the following way:
REPLACEMENTS.each do
|from, to|
line.chomp!
line.gsub!(Regexp.escape(from)) { to }
end
. I'm using Regexp.escape just as a safety measure in the case that the string being replaced contains some regex metacharacter.
I'm using the Cygwin port of MRI Ruby 2.6.4.
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty.
Your understanding is incorrect. The guarantee in the docs is
For any string, Regexp.new(Regexp.escape(str))=~str will be true.
This does hold for your example
Regexp.new(Regexp.escape("D "))=~"D " # => 0
therefore this is what your code should look like
line.gsub!(Regexp.new(Regexp.escape(searchstring))) { '' }
As for why this is the case, there used to be a bug where Regex.escape would incorrectly handle space characters:
# in Ruby 1.8.4
Regex.escape("D ") # => "D\\s"
My guess is they tried to keep the fix as simple as possible by replacing 's' with ' '. Technically this does add an unnecessary escape character but, again, that does not break the intended use of the method.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
This looks to be a bug. In my opinion, whitespace is not a Regexp meta character, there is no need to escape it.
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string […]
If you want to do literal string replacement, then don't use a Regexp. Just use a literal string:
line.gsub!(from, to)

How can I get a non-interpolation bash escape in Ruby?

In ruby, the backticks are a system call, but they are interpolation. This is nice as I could do this
a = 20.sqrt
`cat #{a}`
But it is also annoying because I sometimes want \ in my code, but I need \\ within `` because it is interpolation and escaping. How can I avoid this?
Try this
Kernel.`('echo "#{a}"')
Which prints verbatim
#{a}
Fun fact, ` is actually a method on Kernel and you can call it just like any other method. And thus pass a single quote string as argument.
Form the string in a nonescaping context and interpolate it into the backticks:
s = %{echo "he\ny"}
puts `#{s}`
If you need to juggle with escape characters, you could instead use %q :
system(%q{echo '#&%$][/\'})
#=> #&%$][/\
If you want string interpolation, you can use %Q :
a = 20
system(%Q{echo '#{a}&%$][/\'})
#=> 20&%$][/
Here's a thread about it. Note that you can use any delimiter after %q and %Q : pick one that isn't in your string!
I used system here instead of %x{} or ticks. They're not equivalent, but I just wanted to show the string definition without making the line even more complex than it already is.

Reformatting dates

I'm trying to reformat German dates (e.g. 13.03.2011 to 2011-03-13).
This is my code:
str = "13.03.2011\n14:30\n\nHannover Scorpions\n\nDEG Metro Stars\n60\n2 - 3\n\n\n\n13.03.2011\n14:30\n\nThomas Sabo Ice Tigers\n\nKrefeld Pinguine\n60\n2 - 3\n\n\n\n"
str = str.gsub("/(\d{2}).(\d{2}).(\d{4})/", "/$3-$2-$1/")
I get the same output like input. I also tried my code with and without leading and ending slashes, but I don't see a difference. Any hints?
I tried to store my regex'es in variables like find = /(\d{2}).(\d{2}).(\d{4})/ and replace = /$3-$2-$1/, so my code looked like this:
str = "13.03.2011\n14:30\n\nHannover Scorpions\n\nDEG Metro Stars\n60\n2 - 3\n\n\n\n13.03.2011\n14:30\n\nThomas Sabo Ice Tigers\n\nKrefeld Pinguine\n60\n2 - 3\n\n\n\n"
find = /(\d{2}).(\d{2}).(\d{4})/
replace = /$3-$2-$1/
str = str.gsub(find, replace)
TypeError: no implicit conversion of Regexp into String
from (irb):4:in `gsub'
Any suggestions for this problem?
First mistake is the regex delimiter. You do not need place the regex as string. Just place it inside a delimiter like //
Second mistake, you are using captured groups as $1. Replace those as \\1
str = str.gsub(/(\d{2})\.(\d{2})\.(\d{4})/, "\\3-\\2-\\1")
Also, notice I have escaped the . character with \., because in regex . means any character except \n

gsub! On an argument doesn't work

I am making a function that turns the first argument into a PHP var (useless, I know), and set it equal to the second argument. I'm trying to gsub! it to get rid of all the characters that can't be used in a PHP var. Here is what I have:
dvar = "$" + name.gsub!(/.?\/!#\#{}$%^&*()`~/, "") { |match| puts match }
I have the puts match there to make sure some of the characters were removed. name is a variable passed into a method in which this is its purpose. I am getting this error:
TypeError: can't convert nil into String
cVar at ./Web.rb:31
(root) at C:\Users\Andrew\Documents\NetBeansProjects\Web\lib\main.rb:13
Web.rb is the file this line is in, and main.rb is the file calling this method. How can I fix this?
EDIT: If I remove the ! in gsub!, it goes through, but the characters aren't removed.
Short answer
Use dvar = "$" + name.tr(".?\/!#\#{}$%^&*()``~", '')
Long answer
The problem you are facing is that the gsub! call is returning nil. You can't concatenate (+) a String with a nil.
That's happening because you have a malformed Regexp. You aren't escaping the special regex symbols, like $, * and ., just for a start. Also, the way it is now, gsub will only match if your string contains all that symbols in sequence. You should use the pipe (|) operator to make an OR like operation.
gsub! will also return nil if no substitutions happened.
See the documentation for gsub and gsub! here: http://ruby-doc.org/core/classes/String.html#M001186
I think you should replace gsub! with gsub. Do you really need name to change?
Example:
name = "m$var.name$$"
dvar = "$" + name.gsub!(/\$|\.|\*/, "") # $ or . or *
# dvar now contains $mvarname and name is mvarname
Your line, corrected:
dvar = "$" + name.gsub(/\.|\?|\/|\!|\#|\\|\#|\{|\}|\$|\%|\^|\&|\*|\(|\)|\`|\~/, "")
# some things shouldn't (or aren't needed to) be escaped, I don't remember them all right now
As J-_-L appointed, you could also use a character class ([]), that makes it a little clearer, I guess. Well, it's hard to mentally parse anyway.
dvar = "$" + name.gsub(/[\.\?\/\!\#\\\#\{\}\$\%\^\&\*\(\)\`\~]/, "")
But because what you are doing is simple character replacement, the best method is tr (again reminded by J-_-L!):
dvar = "$" + name.tr(".?\/!#\#{}$%^&*()`~", '')
Way easier to read and make modifications.
You cannot apply a second parameter
and a block to gsub (the block is ignored)
The regex is wrong, you forgot the
square brackets:
/[.?\/!#\#{}$%^&*()~]/`
Because your regex is wrong, it
didn't match anything and because
gsub! returns nil if nothing was
replaced, you get this strange nil no
method error
btw: you should use gsub not gsub! in
this case, because you are using the
return value (and not name itself) --
and the error would not have happened
i dont see what the block is for
just do
name = 'hello.?\/!##$%^&*()`~hello'
dvar = "$" + name.gsub(/\.|\?|\\|\/|\!|\#|\#|\{|\}|\$|\%|\^|\&|\*|\(|\)|\`|\~/, "")
puts dvar # => "$hellohello"
or use [] to denote OR
dvar = "$" + name.gsub(/[\.\?\\\/\!\#\\\#\{\}\$\%\^\&\*\(\)\`\~]/, "")
you have to escape the special characters and then OR them so it will remove them individually not just if they are all found together
also there is really no need to use gsub! to modify the string in place use the non mutator gsub() since you assign it to a new variable,
gsub! returns nil for which the operator + is not defined for stings, which gives you the no method error mentioned
It seems as the 'name' object is nil, you may be calling gsub! on nil which usually complains with a NoMethodError: private method gusb! called for nilNilClass, since I don't know the version of ruby you are using I am not sure if the error would be the same, but it's a good place to start looking at.

Why doesn't this Ruby replace regex work as expected?

Consider the following string which is a C fragment in a file:
strcat(errbuf,errbuftemp);
I want to replace errbuf (but not errbuftemp) with the prefix G-> plus errbuf. To do that successfully, I check the character after and the character before errbuf to see if it's in a list of approved characters and then I perform the replace.
I created the following Ruby file:
line = " strcat(errbuf,errbuftemp);"
item = "errbuf"
puts line.gsub(/([ \t\n\r(),\[\]]{1})#{item}([ \t\n\r(),\[\]]{1})/, "#{$1}G\->#{item}#{$2}")
Expected result:
strcat(G->errbuf,errbuftemp);
Actual result
strcatG->errbuferrbuftemp);
Basically, the matched characters before and after errbuf are not reinserted back with the replace expression.
Anyone can point out what I'm doing wrong?
Because you must use syntax gsub(/.../){"...#{$1}...#{$2}..."} or gsub(/.../,'...\1...\2...').
Here was the same problem: werid, same expression yield different value when excuting two times in irb
The problem is that the variable $1 is interpolated into the argument string before gsub is run, meaning that the previous value of $1 is what the symbol gets replaced with. You can replace the second argument with '\1 ?' to get the intended effect. (Chuck)
I think part of the problem is the use of gsub() instead of sub().
Here's two alternates:
str = 'strcat(errbuf,errbuftemp);'
str.sub(/\w+,/) { |s| 'G->' + s } # => "strcat(G->errbuf,errbuftemp);"
str.sub(/\((\w+)\b/, '(G->\1') # => "strcat(G->errbuf,errbuftemp);"

Resources