Ja, das ist ein Problem mit allen mir bekannten Versionen von printf
. Ich diskutiere kurz die Angelegenheit in this answer und auch in this one.
Für C, ich weiß nicht von einer Bibliothek, die dies für Sie tun, aber wenn jemand es hat, wäre es ICU.
Für Perl müssen Sie das Unicode::GCString Modulformular CPAN verwenden, um die Anzahl der Druckspalten zu berechnen, die eine Unicode-Zeichenfolge aufnehmen wird. Dies berücksichtigt Unicode Standard Annex #11: East Asian Width.
Zum Beispiel nehmen einige Codepunkte 1 Spalte ein und andere belegen 2 Spalten. Es gibt sogar einige, die überhaupt keine Spalten aufnehmen, wie die Kombination von Zeichen und unsichtbaren Steuerzeichen. Die Klasse verfügt über eine columns
-Methode, die angibt, wie viele Spalten die Zeichenfolge belegt.
Ich habe ein Beispiel für die vertikale Ausrichtung von Unicode-Text here. Es wird eine Reihe von Unicode-Zeichenfolgen sortieren, einschließlich einiger Zeichen und "breiter" asiatischer Ideogramme (CJK-Zeichen), und Sie können Objekte vertikal ausrichten.

-Code für das kleine umenu
Demo-Programm, das druckt, die gut Ausgabe ausgerichtet, unten enthalten ist.
Sie könnten auch interessiert sein, die weit ambitionierteren Unicode::LineBreak-Modul, von denen die oben genannten Unicode::GCString
Klasse ist nur eine kleinere Komponente. Dieses Modul ist viel cooler und berücksichtigt Unicode Standard Annex #14: Unicode Line Breaking Algorithm.
Hier ist der Code für die kleine umenu
Demo, getestet auf Perl v5.14:
#!/usr/bin/env perl
# umenu - demo sorting and printing of Unicode food
#
# (obligatory and increasingly long preamble)
#
use utf8;
use v5.14; # for locale sorting
use strict;
use warnings;
use warnings qw(FATAL utf8); # fatalize encoding faults
use open qw(:std :utf8); # undeclared streams in UTF-8
use charnames qw(:full :short); # unneeded in v5.16
# std modules
use Unicode::Normalize; # std perl distro as of v5.8
use List::Util qw(max); # std perl distro as of v5.10
use Unicode::Collate::Locale; # std perl distro as of v5.14
# cpan modules
use Unicode::GCString; # from CPAN
# forward defs
sub pad($$$);
sub colwidth(_);
sub entitle(_);
my %price = (
"γύρος" => 6.50, # gyros, Greek
"pears" => 2.00, # like um, pears
"linguiça" => 7.00, # spicy sausage, Portuguese
"xoriço" => 3.00, # chorizo sausage, Catalan
"hamburger" => 6.00, # burgermeister meisterburger
"éclair" => 1.60, # dessert, French
"smørbrød" => 5.75, # sandwiches, Norwegian
"spätzle" => 5.50, # Bayerisch noodles, little sparrows
"包子" => 7.50, # bao1 zi5, steamed pork buns, Mandarin
"jamón serrano" => 4.45, # country ham, Spanish
"pêches" => 2.25, # peaches, French
"シュークリーム" => 1.85, # cream-filled pastry like éclair, Japanese
"막걸리" => 4.00, # makgeolli, Korean rice wine
"寿司" => 9.99, # sushi, Japanese
"おもち" => 2.65, # omochi, rice cakes, Japanese
"crème brûlée" => 2.00, # tasty broiled cream, French
"fideuà" => 4.20, # more noodles, Valencian (Catalan=fideuada)
"pâté" => 4.15, # gooseliver paste, French
"お好み焼き" => 8.00, # okonomiyaki, Japanese
);
my $width = 5 + max map { colwidth } keys %price;
# So the Asian stuff comes out in an order that someone
# who reads those scripts won't freak out over; the
# CJK stuff will be in JIS X 0208 order that way.
my $coll = new Unicode::Collate::Locale locale => "ja";
for my $item ($coll->sort(keys %price)) {
print pad(entitle($item), $width, ".");
printf " €%.2f\n", $price{$item};
}
sub pad($$$) {
my($str, $width, $padchar) = @_;
return $str . ($padchar x ($width - colwidth($str)));
}
sub colwidth(_) {
my($str) = @_;
return Unicode::GCString->new($str)->columns;
}
sub entitle(_) {
my($str) = @_;
$str =~ s{ (?=\pL)(\S) (\S*) }
{ ucfirst($1) . lc($2) }xge;
return $str;
}
Wie Sie der Schlüssel zu sehen, um es in diesem speziellen Programm machen zu arbeiten, ist diese Codezeile, die nur andere Funktionen, die oben definiert ruft, und verwendet das Modul I diskutiert wurde:
print pad(entitle($item), $width, ".");
Dadurch wird das Element auf die angegebene Breite aufgefüllt, wobei Punkte als Füllzeichen verwendet werden.
Ja, es ist viel weniger bequem, dass printf
, aber zumindest ist es möglich.
Mit anderen Worten, Sie suchen nach einer Multibyte-fähigen Version von 'printf' für Perl und/oder C? – deceze
Ich habe noch nie utf8 in C dekodiert, aber hier ist ein Go-Code, der Runen in einer utf-8-Zeichenfolge zählt: http://golang.org/src/pkg/unicode/utf8/utf8.go?s=4824:4876 # L202 –
@dystyroy Es ist nicht nur eine Frage des Zählens der Codepunkte (dh Runen). Es wird vielmehr in Betracht gezogen, dass verschiedene Codepunkte 0, 1 oder 2 Druckspalten pro UAX # 11 darstellen, und dies ist ziemlich subtil, insbesondere mit den Zeichen 'East_Asian_Width = Ambiguous'. Ich kenne keine Go-Bibliothek, die sich damit beschäftigt, wie die in meiner Antwort beschriebene Perl-Bibliothek tut, aber wenn es so etwas für Go gibt, würde ich gerne etwas darüber erfahren! Vielen Dank. – tchrist