TieDad
TieDad

Reputation: 9929

Use single quote in string inspection

I have the following program:

args = ["a", "b"]
cmd_args = args.map{|x| x.inspect}
str =  cmd_args.join(' ')
puts str

The output is:

"a" "b"

I expect the output to be like the following (sub-string quoted with ' instead of "):

'a' 'b'

I don't want to do a gsub after string inspect because, in my real system, substring might contain ". For example:

args = ['a"c', "b"]
cmd_args = args.map{|x| x.inspect.gsub('"', '\'')}
str =  cmd_args.join(' ')
puts str

will output:

'a\'c' 'b'

The " between a and c is wrongly replaced. My expected output is:

'a"c' 'b'

How can I make string inspect to quote strings with ' instead of "?

Upvotes: 3

Views: 892

Answers (3)

Evgeniy Berezovsky
Evgeniy Berezovsky

Reputation: 19248

If you care about correct escaping of ' via backslash, and consequently of \ as well, the solutions of both answers will fail. See raimo's comment to sawa's answer. user513951's solution fails in the same way:

irb(main):040> x = "b'c"; puts "'#{x}'"
'b'c'

Instead, you can use the following function, that properly escapes ' and \:

  def inspect_str_single_quote(s)
    "'" + s.gsub(/\\/, "\\\\").gsub(/'/, "\\\\'") + "'"
  end

If you want to be able to serialize not just plain strings, but arbitrary data structures, potentially containing strings, you may want to roll your own version of inspect. Here's a sketch, outlining how it could be done, with TODOs left for the reader:

  def inspect_single_quote(value)
    case value
    when String
      inspect_str_single_quote( value
    when Array
      "[" + value.map { |item| inspect_str_single_quote(item) }.join(", ") + "]"
    when Hash
      TODO follow "Array" example
    when Set
      TODO follow "Array" example
    when Range # to handle e.g. string ranges
      TODO follow "Array" example
    when Struct
      TODO follow "Array" example
    when OpenStruct
      TODO follow "Array" example
    when Enumerable
      TODO follow "Array" example
    else # fall back to the default inspect, and hope for the best
      value.inspect
    end
  end

Upvotes: 0

user513951
user513951

Reputation: 13690

You can't force String#inspect to use a single quote without rewriting or overwriting it.

Instead of x.inspect, you could substitute "'#{x}'", but then you would have to make sure you escape any ' characters that appear in x.

Here it is, working:

args = ["a", "b"]
cmd_args = args.map{|x| "'#{x}'" }
str =  cmd_args.join(' ')
puts str

The output is:

'a' 'b'

Upvotes: 2

sawa
sawa

Reputation: 168209

s = 'a"c'.inspect
s[0] = s[-1] = "'"
puts s.gsub("\\\"", "\"") #=> 'a"c'

Upvotes: 2

Related Questions