Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Convert special characters in UTF8

by Digioso (Sexton)
on Jun 08, 2016 at 18:17 UTC ( [id://1165163]=perlquestion: print w/replies, xml ) Need Help??

Digioso has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I've checked out a bunch of threads regarding encoding and decoding but none really described my problem.

A while ago I changed my webhoster and setup a new MySQL db there which uses UTF8. I exported the old db (which didn't use UTF8) and imported it to the new db.

So far the good. The problem now is that special characters (EG german ones like ä, ü, ö, ß, ...) haven't been converted properly.

So now I have a database full with funny looking sentences.

Example: Ein gelber dreif├â┬╝├â┼©iger Greif auf gr├â┬╝n-rotem Grund, der ein Gelds├â┬ñckchen und eine Spitzhacke h├â┬ñlt
This should be: Ein gelber dreifüßiger Greif auf grün-rotem Grund, der ein Geldsäckchen und eine Spitzhacke hält

What I thought:

Get text from db.
$text =~ s/├â┬ñ/ä/g;
Repeat for all special characters.
Save changed text in db.

Unfortunately this doesn't work.
I'm printing out the text to my screen and there is no change after the conversion.
My problem right now is not a conversion between different encodings because I already am using UTF8. I need to somehow substitute the characters. But I'm probably not using the right substitutions because Perl handles those special characters different internally.
My current code:
#!/usr/bin/perl -w use strict; use warnings; use Encode; use DBI; use feature 'unicode_strings'; binmode(STDOUT, ":utf8"); my $db = "..."; my $user = "..."; my $pw = '...'; my $host = "..."; my $options = {RaiseError => 1, AutoCommit => 1, mysql_enable_utf8 => +1}; my $dbh = DBI->connect("DBI:mysql:$db:$host", $user, "$pw", $options) +|| die "Could not connect to database!"; my $sql = 'select post_id, post_text from phpbb_posts where post_id = +24358'; my $sth = $dbh->prepare($sql); $sth->execute() or die "Error: $DBI::errstr"; my ($id, $text) = $sth->fetchrow_array; print "id: $id text: $text"; $text =~ s/├â┬ñ/ä/g; $text =~ s/├â┬Â/ö/g; $text =~ s/├â┼©/ß/g; $text =~ s/├â┬╝/ü/g; print "\nid: $id text: $text";
The code tag seems to be having problems displaying the special characters. But I guess you get the idea.

Replies are listed 'Best First'.
Re: Convert special characters in UTF8 (layers)
by tye (Sage) on Jun 08, 2016 at 19:21 UTC

    When dealing with UTF-8, you usually end up having to exhaustively track and verify the format of your text at each layer. With Perl, you will also often have to worry about whether strings are considered "utf8" or not by Perl.

    When things are working properly, you shouldn't have to worry about Perl's "utf8" flag for strings. And the p5p community (the authors of Perl) tends to cater toward the "things working properly" case and so just being able to tell what format the string is really in and whether the "utf8" flag is on keeps getting trickier.

    One of the easiest tools to aid such investigations, in my experience, is Devel::Peek. It will nicely dump the byte format of a string, whether the "utf8" flag is on, and, if it is on, the UTF-8 char format of the string.

    So you might want to update your code to something like:

    #!/usr/bin/perl -w use strict; use warnings; use Encode; use DBI; use feature 'unicode_strings'; use Devel::Peek qw< Dump >; binmode(STDOUT, ":utf8"); my $db = "..."; my $user = "..."; my $pw = '...'; my $host = "..."; my $options = {RaiseError => 1, AutoCommit => 1, mysql_enable_utf8 => +1}; my $dbh = DBI->connect("DBI:mysql:$db:$host", $user, "$pw", $options) +|| die "Could not connect to database!"; my $sql = 'select post_id, post_text from phpbb_posts where post_id = +24358'; my $sth = $dbh->prepare($sql); $sth->execute() or die "Error: $DBI::errstr"; my ($id, $text) = $sth->fetchrow_array; print "id: $id text: $text"; Dump( $text ); $text =~ s/&#9500;â&#9516;ñ/ä/g; $text =~ s/&#9500;â&#9516;Â/ö/g; $text =~ s/&#9500;â&#9532;©/ß/g; $text =~ s/&#9500;â&#9516;&#9565;/ü/g; print "\nid: $id text: $text"; Dump( $text );

    You should also do some tests where you put a specific UTF-8 string into your DB and then pull it back out, using Dump() on both what you sent in and what you got back.

    You may need to fiddle with more MySQL-specific options or even update DBD::mysql, or, if you are using something very old, upgrade Perl itself. You might even find that DBD::mysql misuses Perl's "utf8" flag for strings so you may end up testing taking a proper UTF-8 string but telling Perl that it is a string of bytes ("utf8" off) before sending it off to MySQL. Or find that MySQL is giving back to you such a string.

    - tye        

Re: Convert special characters in UTF8
by afoken (Chancellor) on Jun 08, 2016 at 19:08 UTC
    A while ago I changed my webhoster and setup a new MySQL db there which uses UTF8. I exported the old db (which didn't use UTF8) and imported it to the new db.

    So the DB import was messed up. You should repair and repeat the DB import. Another option: Export the current messed-up DB to a text file, repair the encoding in the text file, and re-import it.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      With a while ago I meant "six months ago". Since it's a forum DB there have been many changes and new posts. So redoing the import is no option.
      Exporting the text and repair the encoding is what I am trying to do right now. The text is now UTF8, so simply changing the encoding does not work.
        Exporting the text and repair the encoding is what I am trying to do right now.

        Export using current database tools, not perl. This makes sure you won't get encoding problems at that level, plus often, a bulk import / export is faster than working on table rows.

        The text is now UTF8, so simply changing the encoding does not work.

        There is no text, there are only database columns, and they contain a mix of properly UTF-8 encoded characters and mojibake.

        Exporting, fixing mojibake, and importing takes DBI, DBD::mysql, and the MySQL client libraries used by DBD::mysql out of the picture. Only a UTF-8 encoded text file is left. Much easier to handle. The export should show proper encoded characters in a UTF-8 capable editor for fresh postings. After fixing it (maybe using perl or some other tool), the entire export should show proper encoded characters in the editor. Importing it back to the DB will fix the problem.

        Use a second DB (and a second forum installation) to develop and test the process. Once the process works, shut down the forum, export, fix, import, restart the forum.

        (This is what you should have done six months ago.)

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1165163]
Approved by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-20 03:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found