On Thu, 19 Jan 2006, Gavin Kistner wrote: > On Jan 18, 2006, at 7:47 AM, Alexandru Popescu wrote: >> 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 -- strong and healthy, who thinks of sickness until it strikes like lightning? preoccupied with the world, who thinks of death, until it arrives like thunder? -- milarepa