http://www.perlmonks.org?node_id=645255


in reply to Re^3: Unicode substitution regex conundrum
in thread Unicode substitution regex conundrum

"the" internal format for Unicode strings is actually two different formats: ISO-8859-1 and UTF8. As an optimization, Perl may use ISO-8859-1 even though the original source was UTF-8.

Encode::_is_utf8 (not encode::is_utf8) will return true if the string is internally encoded as UTF8, and can return false even though you properly decoded.

Recommendation: do not look at the UTF8 flag. It is next to useless, except for internals debugging and performance tweaking.

Pretend that the UTF8 flag does not exist.

Do not use Encode::_is_utf8 (it is prefixed with an underscore for a reason: you should not have to use this in normal code).

Really, Perl's Unicode strings may be encoded as *ANYTHING* internally. Don't look at the internal buffer, unless you really want to mess with the internals. You do not need to know the internals for simple text processing, as is the case in the OP's problem.

  • Comment on Re^4: Unicode substitution regex conundrum

Replies are listed 'Best First'.
Re^5: Unicode substitution regex conundrum
by moritz (Cardinal) on Oct 16, 2007 at 19:21 UTC
    I meant utf8's is_utf8 originally.

    And what is your suggestion how to check if a string is already decoded into perl's internal format?

    Sadly enough many modules don't document how and if at all they handle encoding issues, so sometimes I do need a method to check that.

      And what is your suggestion how to check if a string is already decoded into perl's internal format?

      Every string is. And that is why your "convert to Perl's internal format" is a bit tricky. It's not incorrect, but it converts both FROM and TO this format. Even binary strings are in this format, or well, one of these formats.

      Perl makes no distinction internally between binary strings and latin1-encoded text strings. None whatsoever. As such, it is impossible for perl to tell you whether a certain string is a text string or a binary string. If the UTF8 flag is true, it certainly is a text string, but if it is false, it can be either text or binary.

      Every string starts out (again, internally) as a binary/latin1 string. The buffer is upgraded when that is needed or convenient. The internal representation of a text string may change, but the string that you, the Perl programmer, work with, is consistent: your chr 0x80 stays 128, regardless of the internal encoding for it.

      You do have to be extra careful not to mix binary with text, because that either makes perl interpret the binary as latin1-encoded text, or the text buffer (which can be latin1 or utf8) as binary.

      Binary string can be safely used without explicitly mentioning that they are binary. This is a feature that ensures backwards compatibility, and a deliberate hole in the abstraction layer, that shouldn't hurt anyone except those who fail to separate binary from text :)

      I recommend saying "decode the binary input to a text string" instead of "convert the string to Perl's internal format", because that would suggest that before conversion it would be something other than a Perl string. The distinction is not "internal format" versus "external format", it is also not "latin1" versus "utf8", it is not "utf8 flagged" versus "not utf8 flagged", and it is certainly not "not flagged" versus "unicode".

      The distinction is "binary string" versus "text string" and the classification of a string should live in the mind of the programmer, because it doesn't live in perl's internals. Binary and text are inherently different, even though they look much alike.

      Compare it to packed numbers versus "numeric Perl values", because that's very much the same thing: the internal representation of a number is scaled up and down based on whatever happens with a number, while pack provides a way to get a certain encoding of the number, resulting in a binary string. Similarly, the internal representation of a text string is scaled up and down based on whatever happens with the string, while encode provides a way to get a certain encoding of the text string, resulting in a binary string. The problem with the two string kinds is that they share a single data type.

      Juerd # { site => 'juerd.nl', do_not_use => 'spamtrap', perl6_server => 'feather' }

      Sadly enough many modules don't document how and if at all they handle encoding issues, so sometimes I do need a method to check that.

      Maybe http://juerd.nl/perladvice can be of a little help.