how to double single quote (beginner blockage)

A

Alexandru Popescu

Hi!

Sorry for this `stupid=B4 question but it looks like i am suffering a men=
tal blockage:

if I have a string that contains single quote (f.e. "al'alamein") i would=
like to escape it with=20
another single quote (=3D> "al''alamein").

there are cases when these strings are already escaped according to the a=
bove rule, so those should=20
remain untouched

my `brainless=B4 attempt was:

Code:
fixed_value =3D ""
wrong_value.each_with_index do |char, idx|
fixed_value << char
if ( (idx < wrong_value.size - 1)  && (wrong_value[idx + 1] !=3D=
'\'') && (idx > 0) &&=20
(wrong_value[idx - 1] !=3D '\''))
fixed_value << '\''
end
end

but the above results in exactly the same strings. I would appreciate ver=
y much your help

=2E/alex
 
J

Jules Jacobs

And what if the input string correctly contains double quotes?? ;-)

String doesn't have a each_with_index method.

class String
def each_with_index
counter = 0
each_byte do |char|
yield char, counter
counter += 1
end
end
end

"abc".each_with_index do |char, index|
puts char.chr + ' ' + index.to_s
end

Please note that char is an integer, so you have to call char.chr.

Untested, but it should work.
 
A

Alexandru Popescu

#: Jules Jacobs changed the world a bit at a time by saying (astral date: 1/18/2006 5:05 PM) :#
And what if the input string correctly contains double quotes?? ;-)

String doesn't have a each_with_index method.

class String
def each_with_index
counter = 0
each_byte do |char|
yield char, counter
counter += 1
end
end
end

"abc".each_with_index do |char, index|
puts char.chr + ' ' + index.to_s
end

Please note that char is an integer, so you have to call char.chr.

Untested, but it should work.

I have passed over my no-brainer moment:

Code:
fixed_value = ""
idx = 0
while (idx < wrong_value.size) do
fixed_value << wrong_value[idx]
if ( wrong_value[idx] == 39 )
if ( (wrong_value[idx + 1] != 39) )
if ( idx > 0 && wrong_value[idx - 1] != 39 )
fixed_value << '\''
end
end
end
idx += 1
end

but now i've reached the no-ruby point. Can you teach me what would be the ruby way?

Note: the double quotes are not considered in this problem; in fact i am removing them right from
the beginning

/alex
 
G

Gavin Kistner

if I have a string that contains single quote (f.e. "al'alamein") i
would like to escape it with another single quote (=> "al''alamein").

there are cases when these strings are already escaped according to
the above rule, so those should remain untouched

Let's build this step by step.

The simple case is pretty simple, using Regular Expressions. You want
to find a single quote that has characters other than a single quote
on either side, and replace it with two single quotes:

irb(main):001:0> input = "al'alamein"
=> "al'alamein"
irb(main):002:0> input.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "al''alamein"

The above breaks if the single quote occurs at the beginning or end
of the input:
irb(main):003:0> input2 = "'Hey, it's al'alamein'"
=> "'Hey, it's al'alamein'"
irb(main):004:0> input2.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "'Hey, it''s al''alamein'"

...so let's say that there has to be a non-single quote at either
end, OR the start/end of the string:
irb(main):005:0> input2.gsub( /(\A|[^'])'([^']|\Z)/, "\\1''\\2" )
=> "''Hey, it''s al''alamein''"

Finally, the above handles 1 or 2 single quotes in a row correctly,
but not 3 or more. Probably you want to ensure that single quotes
always come in even-numbered runs.

Instead of looking for a single quote in the middle of that regular
expression, we'll look for a single quote followed by an even number
of single quotes. Then we'll add one more.

irb(main):006:0> input3 = "'''Jimbo' said, 'this isn''t too hard'.''"
=> "'''Jimbo' said, 'this isn''t too hard'.''"
irb(main):007:0> input3.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\
\3" )
=> "''''Jimbo'' said, ''this isn''t too hard''.''"


(The above could be made a bit simpler with lookaheads and
lookbehinds. I've chosen not to use them because you need Oniguruma
to do lookbehinds, and no sense cluttering the example with one
technique for the front and another for the back.)
 
R

Robert Klemme

Jules said:
And what if the input string correctly contains double quotes?? ;-)

String doesn't have a each_with_index method.

My String has:

16:16:43 [c]: ruby -e '"aaa\nbbb".each_with_index {|*a| p a}'
["aaa\n", 0]
["bbb", 1]
class String
def each_with_index
counter = 0
each_byte do |char|
yield char, counter
counter += 1
end
end
end

"abc".each_with_index do |char, index|
puts char.chr + ' ' + index.to_s
end

Please note that char is an integer, so you have to call char.chr.

Untested, but it should work.

Alexandru's requirements are a bit problematic: what if an original string
contains two single quotes in sequence? Normally these should be expanded
into four single quotes but the solution he envisions would detect them as
a single single quote that has been quoted already...

Anyway, a simple gsub should do what he wants:

16:16:51 [c]: irbs=> "a''b''c"

Kind regards

robert
 
A

ara.t.howard

if I have a string that contains single quote (f.e. "al'alamein") i would
like to escape it with another single quote (=> "al''alamein").

there are cases when these strings are already escaped according to the
above rule, so those should remain untouched

Let's build this step by step.

The simple case is pretty simple, using Regular Expressions. You want to find
a single quote that has characters other than a single quote on either side,
and replace it with two single quotes:

irb(main):001:0> input = "al'alamein"
=> "al'alamein"
irb(main):002:0> input.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "al''alamein"

The above breaks if the single quote occurs at the beginning or end of the
input:
irb(main):003:0> input2 = "'Hey, it's al'alamein'"
=> "'Hey, it's al'alamein'"
irb(main):004:0> input2.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "'Hey, it''s al''alamein'"

...so let's say that there has to be a non-single quote at either end, OR the
start/end of the string:
irb(main):005:0> input2.gsub( /(\A|[^'])'([^']|\Z)/, "\\1''\\2" )
=> "''Hey, it''s al''alamein''"

Finally, the above handles 1 or 2 single quotes in a row correctly, but not 3
or more. Probably you want to ensure that single quotes always come in
even-numbered runs.

Instead of looking for a single quote in the middle of that regular
expression, we'll look for a single quote followed by an even number of
single quotes. Then we'll add one more.

irb(main):006:0> input3 = "'''Jimbo' said, 'this isn''t too hard'.''"
=> "'''Jimbo' said, 'this isn''t too hard'.''"
irb(main):007:0> input3.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\\3" )
=> "''''Jimbo'' said, ''this isn''t too hard''.''"


(The above could be made a bit simpler with lookaheads and lookbehinds. I've
chosen not to use them because you need Oniguruma to do lookbehinds, and no
sense cluttering the example with one technique for the front and another for
the back.)

nice explanation gavin. my brain is too feeble for that but i do the same
thing logically using

irb(main):016:0> %Q( '''Jimbo' said, 'this isn''t too hard'.'' ).gsub(/'+/){|m| m.size % 2 == 0 ? m : m << "'"}
=> " ''''Jimbo'' said, ''this isn''t too hard''.'' "

i assume it would be slower though.

cheers.

-a
 
A

Alexandru Popescu

#: Gavin Kistner changed the world a bit at a time by saying (astral date: 1/18/2006 5:28 PM) :#
if I have a string that contains single quote (f.e. "al'alamein") i
would like to escape it with another single quote (=> "al''alamein").

there are cases when these strings are already escaped according to
the above rule, so those should remain untouched

Let's build this step by step.

The simple case is pretty simple, using Regular Expressions. You want
to find a single quote that has characters other than a single quote
on either side, and replace it with two single quotes:

irb(main):001:0> input = "al'alamein"
=> "al'alamein"
irb(main):002:0> input.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "al''alamein"

The above breaks if the single quote occurs at the beginning or end
of the input:
irb(main):003:0> input2 = "'Hey, it's al'alamein'"
=> "'Hey, it's al'alamein'"
irb(main):004:0> input2.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "'Hey, it''s al''alamein'"

...so let's say that there has to be a non-single quote at either
end, OR the start/end of the string:
irb(main):005:0> input2.gsub( /(\A|[^'])'([^']|\Z)/, "\\1''\\2" )
=> "''Hey, it''s al''alamein''"

Finally, the above handles 1 or 2 single quotes in a row correctly,
but not 3 or more. Probably you want to ensure that single quotes
always come in even-numbered runs.

Instead of looking for a single quote in the middle of that regular
expression, we'll look for a single quote followed by an even number
of single quotes. Then we'll add one more.

irb(main):006:0> input3 = "'''Jimbo' said, 'this isn''t too hard'.''"
=> "'''Jimbo' said, 'this isn''t too hard'.''"
irb(main):007:0> input3.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\
\3" )
=> "''''Jimbo'' said, ''this isn''t too hard''.''"


(The above could be made a bit simpler with lookaheads and
lookbehinds. I've chosen not to use them because you need Oniguruma
to do lookbehinds, and no sense cluttering the example with one
technique for the front and another for the back.)

I've been fighting to figure out how a regexp should look, so I appreciate very much your approach.
I will be reading it carefully.

thanks,

/alex
 
A

Alexandru Popescu

#: Gavin Kistner changed the world a bit at a time by saying (astral date: 1/18/2006 5:28 PM) :#
if I have a string that contains single quote (f.e. "al'alamein") i
would like to escape it with another single quote (=> "al''alamein").

there are cases when these strings are already escaped according to
the above rule, so those should remain untouched

Let's build this step by step.

The simple case is pretty simple, using Regular Expressions. You want
to find a single quote that has characters other than a single quote
on either side, and replace it with two single quotes:

irb(main):001:0> input = "al'alamein"
=> "al'alamein"
irb(main):002:0> input.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "al''alamein"

The above breaks if the single quote occurs at the beginning or end
of the input:
irb(main):003:0> input2 = "'Hey, it's al'alamein'"
=> "'Hey, it's al'alamein'"
irb(main):004:0> input2.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "'Hey, it''s al''alamein'"

...so let's say that there has to be a non-single quote at either
end, OR the start/end of the string:
irb(main):005:0> input2.gsub( /(\A|[^'])'([^']|\Z)/, "\\1''\\2" )
=> "''Hey, it''s al''alamein''"

Finally, the above handles 1 or 2 single quotes in a row correctly,
but not 3 or more. Probably you want to ensure that single quotes
always come in even-numbered runs.

Instead of looking for a single quote in the middle of that regular
expression, we'll look for a single quote followed by an even number
of single quotes. Then we'll add one more.

irb(main):006:0> input3 = "'''Jimbo' said, 'this isn''t too hard'.''"
=> "'''Jimbo' said, 'this isn''t too hard'.''"
irb(main):007:0> input3.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\
\3" )
=> "''''Jimbo'' said, ''this isn''t too hard''.''"


(The above could be made a bit simpler with lookaheads and
lookbehinds. I've chosen not to use them because you need Oniguruma
to do lookbehinds, and no sense cluttering the example with one
technique for the front and another for the back.)

I've been fighting to figure out how a regexp should look (mainly the first/last position part), so
I appreciate very much your approach. I will be reading it carefully.

... and what is Oniguruma? (sounds pretty cool :) ).

thanks,

/alex
 
P

Phrogz

Whoa, sexy! I'm too used to dealing with situations where 'pure' regexp
is all that's allowed. (Text editors, or Safari whose JS replace
doesn't permit functions.) Yours is a little slower, but not a GOBS
slower:

user system total real
pure regexp 3.843000 0.032000 3.875000 ( 3.875000)
gsub w/ block 4.531000 0.000000 4.531000 ( 4.531000)

Benchmark.bmbm( 10 ){ |x|
x.report( "pure regexp" ){
n.times{
s.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\\3" )
}
}
x.report( "gsub w/ block" ){
n.times{
s.gsub(/'+/){|m| m.size % 2 == 0 ? m : m << "'"}
}
}
}
 
P

Phrogz

Oniguruma is a new regular expression engine for Ruby. It isn't
included in default 1.8 builds (though I hear it's possible to build
your own 1.8 with Oniguruma inside) but is slated to be the regexp
engine for future Ruby releases. (I believe it's already included in
the 1.9 builds?)

http://www.google.com/search?q=oniguruma
 
R

Robert Klemme

Gavin said:
if I have a string that contains single quote (f.e. "al'alamein") i
would like to escape it with another single quote (=> "al''alamein").

there are cases when these strings are already escaped according to
the above rule, so those should remain untouched

Let's build this step by step.

The simple case is pretty simple, using Regular Expressions. You want
to find a single quote that has characters other than a single quote
on either side, and replace it with two single quotes:

irb(main):001:0> input = "al'alamein"
=> "al'alamein"
irb(main):002:0> input.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "al''alamein"

The above breaks if the single quote occurs at the beginning or end
of the input:
irb(main):003:0> input2 = "'Hey, it's al'alamein'"
=> "'Hey, it's al'alamein'"
irb(main):004:0> input2.gsub( /([^'])'([^'])/, "\\1''\\2" )
=> "'Hey, it''s al''alamein'"

..so let's say that there has to be a non-single quote at either
end, OR the start/end of the string:
irb(main):005:0> input2.gsub( /(\A|[^'])'([^']|\Z)/, "\\1''\\2" )
=> "''Hey, it''s al''alamein''"

Finally, the above handles 1 or 2 single quotes in a row correctly,
but not 3 or more. Probably you want to ensure that single quotes
always come in even-numbered runs.

Instead of looking for a single quote in the middle of that regular
expression, we'll look for a single quote followed by an even number
of single quotes. Then we'll add one more.

irb(main):006:0> input3 = "'''Jimbo' said, 'this isn''t too hard'.''"
=> "'''Jimbo' said, 'this isn''t too hard'.''"
irb(main):007:0> input3.gsub( /(\A|[^'])'('')*([^']|\Z)/, "\\1''\\2\
\3" )
=> "''''Jimbo'' said, ''this isn''t too hard''.''"


(The above could be made a bit simpler with lookaheads and
lookbehinds. I've chosen not to use them because you need Oniguruma
to do lookbehinds, and no sense cluttering the example with one
technique for the front and another for the back.)

No lookbehinds / -aheads needed, or am I missing something? As far as I
can see special treatment of quotes at beginning and end of string was not
a requirement.
=> "al''alamein"
=> "''Hey, it''s al''alamein''"
=> "''''Jimbo'' said, ''this isn''t too hard''.''"

Can't see any difference to your output - but the RX is much simpler. :)

Cheers

robert
 
P

Phrogz

Well, aren't you tricky? :) And, yours is quite fast:

user system total real
pure regexp 4.078000 0.016000 4.094000 ( 4.093000)
gsub w/ block 5.438000 0.000000 5.438000 ( 5.438000)
Klemme's Simplicity 2.203000 0.000000 2.203000 ( 2.219000)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top