Say
string = "Johnny be good! And smile :-) "
Is there a difference between
string.gsub(/\s+/, '')
and
string.strip
?
If so, what is it?
strip only removes leading and trailing whitespace, using gsub in the way that you outline in your question will remove all whitespace from the string.
irb(main):004:0* " hello ".strip
=> "hello"
irb(main):005:0> " h e l l o ".strip
=> "h e l l o"
irb(main):006:0> " hello ".gsub(/\s+/, '')
=> "hello"
irb(main):007:0> " h e l l o ".gsub(/\s+/, '')
=> "hello"
Related
I have an array in Ruby
words = ["horses", "follow", "useful", "offset"]
Reference:
h o r s e s
f o l l o w
u s e f u l
o f f s e t
I want to get a list of all its diagonals like this.
Here is want I expect in result:
["o", "uf", "fsf", "hoes", "olfe", "rlut", "sol", "ew", "s"]
Would be helpful if anyone can help me a bit on this. Thanks
Try that:
words = ["horses", "follow", "useful", "offset"]
words.reverse.each_with_index.map{|s,i| " " * i + s }.inject(Array.new(words.size + words.last.size-1,"")) do |a,s|
s.chars.each_with_index do |c,i|
a[i] = c + a[i]
end
a
end.map(&:strip)
# => ["o", "uf", "fsf", "hoes", "olfe", "rlut", "sol", "ew", "s"]
At first words.reverse.each_with_index.map{|s,i| " " * i + s } builds array with whitespace offset:
offset
useful
follow
horses
Inject creates array of empty strings and inside main block each string chars are prepended to proper array element
even if i use gsub to change white space to _ the if statement still get error attempt to index a nil value i wonder whats the problem.i cant use pairs since that's the instruction my teacher gave.
this is the code sorry in advance im a beginner.
text = "ib c e d f"
text = string.lower(text)
b = text:gsub("%s+", "_")
for k=1, #b do
if not string.sub(b, k,k) or string.sub(b, k,k) ~= " " then
if a[i][2] == string.sub(b, k,k) then
print(yes)
end
end
There are some syntax error on your code snippet which causes the error you mentioned. The gsub function is actually working just fine.
text = "ib c e d f"
text = string.lower(text)
b = text:gsub("%s+", "_") --> this gsub is working just fine
for k=1, #b do
if not string.sub(b, k,k) or string.sub(b, k,k) ~= " " then
if a[i][2] == string.sub(b, k,k) then --> you didn't assign any table called "a" before --> attempting to index a nil value
print(yes)
end
--> haven't close the "if not string.sub" function with an end
end --> this is the end for the loop "for k"
I am just wildly guessing that you want to compare the result string with the original string. Since your question is so enigmatic, I could only offer you this code below for your reference:
text = "ab c d e f "
text = string.lower(text)
output = text:gsub("%s", "_")
for k = 1, #output do
local char = string.sub(output, k, k)
local originalChar = string.sub(text, k, k)
if (originalChar ~= " ") and (char == originalChar) then
print(char .. " --> OK")
end
end
The gsub pattern uses %s instead of %s+ so that each space is converted to an underscore to allow simple unit test (char by char comparison). Code snippet available here.
I try to remove 1 whitespace from this string:
m y r e a l n a m e i s d o n a l d d u c k
Expected result:
my real name is donald duck
My code are:
def solve_cipher(input)
input.split('').map { |c| (c.ord - 3).chr }.join(' ') # <- Here I tried everything
end
puts solve_cipher('p| uhdo qdph lv grqdog gxfn')
# => m y r e a l n a m e i s d o n a l d d u c k
I tried everything to solve my problem, example:
input.....join(' ').squeeze(" ").strip # => m y r e a l n a m e...
or
input.....join.gsub(' ','') # => myrealnameisdonaldduck
or
input.....join(' ').lstrip # => m y r e a l n a m e...
and so on...
Well, you could split the string into words first, then split each word into characters. Using the same method you used in your code, it could look like this.
def solve_cipher(input) input.split(' ').map{ |w| w.split('').map { |c| (c.ord - 3).chr}.join('')}.join(' ') end
When joining the characters in the same word, we put no space between them; when joining the words together we put one space between them.
As stated in the question, you are using Rails, so you can also try squish method:
def solve_cipher( input )
input.split(' ').map(&:squish).join(' ')
end
str = "m y r e a l n a m e i s d o n a l d d u c k"
str.gsub(/\s(?!\s)/,'')
#=> "my real name is donald duck"
The regex matches a whitespace character not followed by another whitespace character and replaces the matched characters with empty strings. (?!\s) is a negative lookahead that matches a whitespace.
If more than two spaces may be present between words, first replace three or more spaces with two spaces, as follows.
str = "m y r e a l n a m e i s d o n a l d d u c k"
str.gsub(/\s{3,}/, " ").gsub(/\s(?!\s)/,'')
#=> "my real name is donald duck"
I know that it is not a fancy way of doing it but you could just try to create a new string and have a function traversal(input) with a counter initiated at 0, that would return this new string.
It would go through your input (which is here your string) and if the counter is 0 and it sees a space it just ignores it, increments a counter and go to the next character of the string.
If the counter is different of 0 and it sees a space it just concatenates it to the new string.
And if the counter is different of 0 and it sees something different of a space, it concatenates it to the new string and counter equals 0 again.
The trick is to use a capture group
"m y r e a l n a m e i s d o n a l d d u c k".gsub(/(\s)(.)/, '\2')
=> "my real name is donald duck
I need to iterate over some pairs of strings in a program that I am writing. Instead of putting the string pairs in a big table-of-tables, I am putting them all in a single string, because I think the end result is easier to read:
function two_column_data(data)
return data:gmatch('%s*([^%s]+)%s+([^%s]+)%s*\n')
end
for a, b in two_column_data [[
Hello world
Olá hugomg
]] do
print( a .. ", " .. b .. "!")
end
The output is what you would expect:
Hello, world!
Olá, hugomg!
However, as the name indicates, the two_column_data function only works if there are two exactly columns of data. How can I make it so it works on any number of columns?
for x in any_column_data [[
qwe
asd
]] do
print(x)
end
for x,y,z in any_column_data [[
qwe rty uio
asd dfg hjk
]] do
print(x,y,z)
end
I'm OK with using lpeg for this task if its necessary.
function any_column_data(data)
local f = data:gmatch'%S[^\r\n]+'
return
function()
local line = f()
if line then
local row, ctr = line:gsub('%s*(%S+)','%1 ')
return row:match(('(.-) '):rep(ctr))
end
end
end
Here is an lpeg re version
function re_column_data(subj)
local t, i = re.compile([[
record <- {| ({| [ %t]* field ([ %t]+ field)* |} (%nl / !.))* |}
field <- escaped / nonescaped
nonescaped <- { [^ %t"%nl]+ }
escaped <- '"' {~ ([^"] / '""' -> '"')* ~} '"']], { t = '\t' }):match(subj)
return function()
local ret
i, ret = next(t, i)
if i then
return unpack(ret)
end
end
end
It basicly is a redo of the CSV sample and supports quoted fields for some nice use-cases: values with spaces, empty values (""), multi-line values, etc.
for a, b, c in re_column_data([[
Hello world "test
test"
Olá "hug omg"
""]].."\tempty a") do
print( a .. ", " .. b .. "! " .. (c or ''))
end
local function any_column_data( str )
local pos = 0
return function()
local _, to, line = str:find("([^\n]+)\n", pos)
if line then
pos = to
local words = {}
line:gsub("[^%s]+", function( word )
table.insert(words, word)
end)
return table.unpack(words)
end
end
end
Outer loop returns lines, and inner loop returns words in line.
s = [[
qwe rty uio
asd dfg hjk
]]
for s in s:gmatch('(.-)\n') do
for s in s:gmatch('%w+') do
io.write(s,' ')
end
io.write('\n')
end
I am using Ruby on Rails 3.1.0 and I would like to validate a class attribute just to avoid to store in the database a string containing these characters: (blank space), <, >, ", #, %, {, }, |, \, ^, ~, [, ] and ```.
What is the regex?
Assuming it should also be non-empty:
^[^\] ><"#%{}|\\^~\[`]+$
Since someone is downvoting this, here is some test code:
ary = [' ', '<', '>', '"', '#', '%', '{', '}', '|', '\\', '^', '~', '[', ']', '`', 'a']
ary.each do |i|
puts i =~ /^[^\] ><"#%{}|\\^~\[`]+$/
end
Output:
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
nil
0
bad_chars = %w(< > " # % { } | \ ^ ~ [ ] ')
re = Regexp.union(bad_chars)
p %q(hoh'oho) =~ re #=> 3
Regexp.union takes care of escaping.
a = "foobar"
b = "foo ` bar"
re = /[ \^<>"#%\{\}\|\\~\[\]\`]/
a =~ re # => nil
b =~ re # => 3
The inverse expression is:
/\A[^ \^<>"#%\{\}\|\\~\[\]\`]+\Z/