Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re^5: Text::CSV encoding parse()

by haukex (Chancellor)
on Aug 14, 2019 at 19:55 UTC ( #11104478=note: print w/replies, xml ) Need Help??


in reply to Re^4: Text::CSV encoding parse()
in thread Text::CSV encoding parse()

I don't see any mention of any encoding in this code, which is not good. And earlier you said: "I'm using the CGI module and have it properly set: print $q->header(-charset => 'utf-8');" so I doubt this code is representative.

You need to:

  • Use a Perl version >= 5.12 and say use feature 'unicode_strings'; or use 5.012; (or higher).
  • If you have any non-ASCII characters in your Perl script, save it as UTF-8 and add the use utf8; directive at the top.
  • Make sure your data is coming from the database properly encoded. As I linked to above, you can check this via Devel::Peek. If you need that output to go to the browser, see this.
  • Make sure you are doing binmode STDOUT, ':encoding(UTF-8)'; or use open qw/:std :utf8/;.
  • Make sure you are telling your browser what encoding you are sending it.

Text::CSV is not the problem:

use warnings; use strict; use Devel::Peek; use Text::CSV; my $str = "\N{U+20AC}|\N{U+20AC}"; Dump($str); # ... UTF8 "\x{20ac}|\x{20ac}" ... my ($s1,$s2) = split /\|/, $str; Dump($s1); # ... UTF8 "\x{20ac}" ... Dump($s2); # ... UTF8 "\x{20ac}" ... my $csv = Text::CSV->new ({ binary => 1, sep_char => "|" }); $csv->parse($str); my ($c1,$c2) = $csv->fields; Dump($c1); # ... UTF8 "\x{20ac}" ... Dump($c2); # ... UTF8 "\x{20ac}" ...

Replies are listed 'Best First'.
Re^6: Text::CSV encoding parse()
by slugger415 (Monk) on Aug 14, 2019 at 21:41 UTC

    Hello haukex, thanks a million for your advice, but I have to confess this is way beyond my understanding or abilities in many ways, so I think I'm going to have to live with it. FWIW every time encoding problems come up I get lost in the weeds. (I'm not a developer, just a Perl hack, don't grok hexdump or Devel::Peek etc.)

    All I know in this case is I can print my @sorted_array rows to a flat file (opened with Notepad++) or to a web page using CGI, and those characters look fine. It's only when I use Text:CSV that something goes haywire.

    Anyway I appreciate your patience and help, sorry for the trouble.

      Try taking the following code and replacing my $data with your code that fetches the data from the database (as short as possible), and post both your code and the output here. <update> Note that PerlMonks does not handle Unicode inside of <code> tags well, so tell us if you've got any Unicode in there. </update>

      #!/usr/bin/env perl
      use warnings;
      use 5.012;
      use utf8; # Perl script file is encoded as UTF-8
      use open qw/:utf8 :std/; # reopen STDIN/OUT/ERR as UTF-8
      use Text::CSV;
      use CGI qw/escapeHTML/;
      use CGI::Carp qw/fatalsToBrowser warningsToBrowser/; # for debug ONLY!
      use Data::Dumper;
      $Data::Dumper::Useqq=1;
      
      my $cgi = CGI->new;
      print $cgi->header(-charset=>'UTF-8');
      print $cgi->start_html(-title=>'Example', -encoding=>'UTF-8');
      warningsToBrowser(1);
      
      my $data = "Euro symbol: € | I \N{U+2764}\N{U+FE0F} \N{U+1F42A}";
      
      print $cgi->pre(escapeHTML( Dumper( $data ) # debugging
      	."UTF-8 flag is ".( utf8::is_utf8( $data )?'on':'off' ) ));
      
      print $cgi->p(escapeHTML( $data ));
      
      my $csv = Text::CSV->new ({ binary => 1, sep_char => "|" });
      $csv->parse($data);
      my ($c1,$c2) = $csv->fields;
      print $cgi->p(escapeHTML( "After Text::CSV: ".$c1." | ".$c2 ));
      
      print $cgi->end_html;
      

      (Note: It is better to use utf8::is_utf8() only for debugging.) The output you should see in the browser from the above:

      $VAR1 = "Euro symbol: \x{20ac} | I \x{2764}\x{fe0f} \x{1f42a}";
      UTF-8 flag is on

      Euro symbol: € | I ❤️ 🐪

      After Text::CSV: Euro symbol: € | I ❤️ 🐪

        Using the perl internals through Data::Peek's DPeek, you'll see both versions if UTF-8 is in effect without the fragile use of utf8 function calls. It also shows the importance of using utf8 in your example code.

        $ perl -MData::Peek -wE'my $data = "Euro symbol: € | I \N{U+276 +4}\N{U+FE0F} \N{U+1F42A}"; DPeek $data' PV("Euro symbol: \303\242\302\202\302\254 | I \342\235\244\357\270\217 + \360\237\220\252"\0) [UTF8 "Euro symbol: \x{e2}\x{82}\x{ac} | I \x{2 +764}\x{fe0f} \x{1f42a}"] $ perl -Mutf8 -MData::Peek -wE'my $data = "Euro symbol: € | I \N{U+276 +4}\N{U+FE0F} \N{U+1F42A}"; DPeek $data' PV("Euro symbol: \342\202\254 | I \342\235\244\357\270\217 \360\237\22 +0\252"\0) [UTF8 "Euro symbol: \x{20ac} | I \x{2764}\x{fe0f} \x{1f42a} +"] $ perl -Mutf8 -MData::Peek -wE'my $data = "Euro symbol: \xe2\x82\xac | + I \xe2\x9d\xa4\xef\xb8\x8f \xf0\x9f\x90\xaa"; DPeek $data' PV("Euro symbol: \342\202\254 | I \342\235\244\357\270\217 \360\237\22 +0\252"\0)

        Enjoy, Have FUN! H.Merijn

        Hello, thank you for the test code. Yes I see the same in the browser with your sample code. I've substituted my own string for yours and here's what I see now in the browser:

        $VAR1 = "/search/\x{bf}Cuales son las partes de una cadena de conexi\x +{f3}n??scope=SSGU8G_12.1.0|/com.ibm.jdbc_pg.doc/ids_jdbc_011.htm|0|1| +1|0\n"; UTF-8 flag is on /search/¿Cuales son las partes de una cadena de conexión??scope=SSGU8G +_12.1.0|/com.ibm.jdbc_pg.doc/ids_jdbc_011.htm|0|1|1|0 After Text::CSV: /search/¿Cuales son las partes de una cadena de conex +ión??scope=SSGU8G_12.1.0 | /com.ibm.jdbc_pg.doc/ids_jdbc_011.htm

        BTW I'm assigning $data by reading a stdout output file that is returned from the db via the tool I'm using for the SQL query.

        my($data); open my $fh, "<:encoding(utf8)", $file || die("cannot open $file file\ +n"); while(<$fh>){ if($_ =~ /Cuales/){ $data = $_; print $_; } } close($fh);

        I've also tried opening the file without the :encoding and get the same result.

        open(R, "$resultsFile") || die("cannot open results file $resultsFile +for reading.\n");

        Hope this is helpful.

      I am sorry, but you will need to learn to use hex dumps. They are the only reliable way to solve this type of encoding problem, where the "bytes on the wire" are what matters. Have you tried using Wireshark to observe the actual network traffic? It offers a convenient hex dump view of each packet.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11104478]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2019-09-16 08:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The room is dark, and your next move is ...












    Results (186 votes). Check out past polls.

    Notices?