5

Given a string A\xC3B, it can be converted to utf-8 string by doing this (ref link):

"A\xC3B".force_encoding('iso-8859-1').encode('utf-8') #=> "AÃB"

However, I only want to perform the action if the string contains the ASCII code, namely \xC3. How can I check for that?

Tried "A\xC3B".include?("\x") but it doesn't work.

Community
  • 1
  • 1
sbs
  • 4,102
  • 5
  • 40
  • 54

2 Answers2

7

\x is just a hexadecimal escape sequence. It has nothing to do with encodings on its own. US-ASCII goes from "\x00" to "\x7F" (e.g. "\x41" is the same as "A", "\x30" is "0"). The rest ("\x80" to "\xFF") however are not US-ASCII characters since it's a 7-bit character set.

If you want to check if a string contains only US-ASCII characters, call String#ascii_only?:

p "A\xC3B".ascii_only? # => false
p "\x41BC".ascii_only? # => true

Another example based on your code:

str = "A\xC3B"
unless str.ascii_only?
  str.force_encoding(Encoding::ISO_8859_1).encode!(Encoding::UTF_8)
end
p str.encoding # => #<Encoding:UTF-8>
cremno
  • 4,672
  • 1
  • 16
  • 27
1

I think what you want to do is to figure out whether your string is properly encoded. The ascii_only? solution isn't much help when dealing with non-Ascii strings.

I would use String#valid_encoding? to verify whether a string is properly encoded, even if it contains non-ASCII chars.

For example, what if someone else has encoded "Françoise Paré" the right way, and when I decode it I get the right string instead of "Fran\xE7oise Par\xE9" (which is what would be decoded if someone encoded it into ISO-8859-1).

[62] pry(main)> "Françoise Paré".encode("utf-8").valid_encoding?
=> true

[63] pry(main)> "Françoise Paré".encode("iso-8859-1")
=> "Fran\xE7oise Par\xE9"

# Note the encoding is still valid, it's just the way IRB displays
# ISO-8859-1

[64] pry(main)> "Françoise Paré".encode("iso-8859-1").valid_encoding?
=> true

# Now let's interpret our 8859 string as UTF-8. In the following
# line, the string bytes don't change, `force_encoding` just makes
# Ruby interpret those same bytes as UTF-8.

[65] pry(main)> "Françoise Paré".encode("iso-8859-1").force_encoding("utf-8")
=> "Fran\xE7oise Par\xE9"

# Is a lone \xE7 valid UTF-8? Nope.

[66] pry(main)> "Françoise Paré".encode("iso-8859-1").force_encoding("utf-8").valid_encoding?
=> false
Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75