2013-05-08 9 views
9

Ich versuche lokalisierte Währungszeichenfolgen zu Währung und Gleitkommawert zu analysieren.Wie kann ich das NumberFormatter :: parseCurrency() - Verhalten zum Akzeptieren von Leerraum und nicht brechendem Leerraum ändern?

Alles funktioniert gut für eine Weile, jetzt haben wir einige Probleme. Es scheint, dass NumberFormatter :: parseCurrency ein zusätzliches unsichtbaren Zeichen verwendet:

Testcode:

<?php 
$formatter = new NumberFormatter("de_DE", NumberFormatter::CURRENCY); 
var_dump(array(
    $formatter->parseCurrency("88,22 €", $curr), // taken from output of $formatter->format(88.22) 
    $formatter->parseCurrency("88,22 €", $curr), // input with keyboard 
    $formatter->parseCurrency("88,22 \xE2\x82\xAc", $curr), // just a test 
    $formatter->format(88.22), 
    "88,22 €" // keyboard input 
)); 

Ausgang:

array(5) { 
    [0]=> float(88,22) 
    [1]=> bool(false) 
    [2]=> bool(false) 
    [3]=> string(10) "88,22 €" // this as input works 
    [4]=> string(9) "88,22 €" // this not... 
} 

Wie Sie sehen können, gibt es einen Unterschied in der Stringlänge von Ausgang 3 und 4.

Ich bekomme die gleichen Ergebnisse in PHP 5.3 (Ubuntu mit Mbstring aktiviert) und 5.4 (Zend Server unter Mac OS X).

Das Hauptproblem ist, Eingabewerte von meiner Form (ZF1 Application) sind ebenso zur Ausgabe mit Index 4 ...

irgendwelche Vorschläge? Vielen Dank im Voraus

Edit1:

hexdump Arbeitswert:

00000000 38 38 2c 32 32 c2 a0 e2 82 ac 0a     |88,22......| 
0000000b 

hexdump Nichtarbeitswert:

00000000 38 38 2c 32 32 20 e2 82 ac 0a     |88,22 ....| 
0000000a 

Edit2:

Es scheint ein Problem mit dem verwendeten Whiteplace zu sein. c2 a0 ist NO-BREAK SPACE und (vielleicht?) erforderlich von NumberFormatter :: parseCurrency(). aber 0x20 ist der Standardbereich (der im Eingabeformular eingegeben wird). Aktuelle Problemumgehung wird mit $value = str_replace("\x20", "\xC2\xA0", $value);

Edit3 den Leerraum mit NO-BREAK SPACE ersetzt:

auf einem anderen System (Mac OS X mit Zend Server 5.6, aktiviert mbstring, PHP 5.3.14) alles wie erwartet funktioniert :

array(5) { 
    [0]=> float(88,22) 
    [1]=> float(88,22) 
    [2]=> float(88,22) 
    [3]=> string(9) "88,22 €" 
    [4]=> string(9) "88,22 €" 
} 

Edit4:

Der Hauptunterschied zwischen den Arbeits s Tempo und mit nicht Pause Raumkonfiguration arbeitet, ist die ICU-Version:

Arbeitsversion:

intl 

Internationalization support => enabled 
version => 1.1.0 
ICU version => 3.8.1 

Directive => Local Value => Master Value 
intl.default_locale => no value => no value 
intl.error_level => 0 => 0 

nicht funktionierende Version:

intl 

Internationalization support => enabled 
version => 1.1.0 
ICU version => 4.8.1.1 
ICU Data version => 4.8.1 

Directive => Local Value => Master Value 
intl.default_locale => no value => no value 
intl.error_level => 0 => 0 
+1

Nur eine Idee: Ist das € -Zeichen vom Formatierer UTF-8 codiert (0x20AC) und das von der Tastatur Latin-1 (0x80)? Soweit ich weiß, kennt die Funktion strlen() keine Unicode-Zeichen. Wenn es intern von var_dump() verwendet wird, würde das das zusätzliche Zeichen erklären. – CodeZombie

+0

Meine Terminal-App (iTerm2) verwendet Unicode (UTF-8) als Terminal-Emulation. Dieser Fehler/dieses Verhalten geschieht auch aus Eingabedaten des Browsers über HTML-Formular-Texteingabefelder. Ich habe die Hexdump-Ausgabe zur Verdeutlichung hinzugefügt. – nofreeusername

+0

ist die Datei als UTF-8 gespeichert? –

Antwort

3

NumberFormatter::parseCurrency ist eine dünne Hülle um die ICU-Bibliothek Funktion unum_parseDoubleCurrency (see source).

Die ICU-Bibliotheksfunktion ist insofern restriktiv, als sie nur Strings analysiert, die sich aus ihrer Doppelfunktion unum_formatDoubleCurrency ergeben würden. Das Format wird durch die Unicode-Ländereinstellungsdaten gesteuert, die einen nicht brechenden Abstand zwischen dem Währungswert und dem numerischen Wert angeben. Offensichtlich akzeptiert die frühere Version der Bibliothek andere Leerzeichen.

Kurz gesagt, Sie können nicht NumberFormatter::parseCurrency akzeptieren Leerzeichen. Allerdings Zend_Currency sollte auch Ausgangs non-breaking Leerzeichen standardmäßig:

$currency = new Zend_Currency(array(
    'currency' => 'EUR', 
    'value' => 88.22, 
), 'de_DE'); 

var_dump(
    strval($currency),    // 88,22 € 
    strpos($currency, "\x20"),  // false 
    strpos($currency, "\xc2\xa0") // 5 
); 

Die Frage ist, welcher Teil Ihrer Anwendung einen Raum ausgibt und wie Sie adressieren es. Sie erwähnen, dass es sich um einen Teil Ihres Formulars handelt. Vielleicht könnten Sie also darauf achten, dass das Formular die Währung und den Wert als separate Felder zurückgibt, sodass Sie sich keine Gedanken über die Analyse der Zahl machen müssen. Wenn der Benutzer die Zeichenfolge "88,22 €" selbst eingibt, könnten möglicherweise mehr Probleme als nur das Leerzeichen auftreten. Die von Ihnen erwähnte Problemumgehung (\x20 durch \xc2\xa0 zu ersetzen) ist die einzige Möglichkeit, das zu beheben, wenn Sie NumberFormatter verwenden möchten.

+0

thx für die Erklärung! Zend_Currency gibt den korrekten Wert zurück. Aber mein Formular ermöglicht direkte Benutzereingabe mit Float im lokalen Format mit Währungssymbol. Eine vollständige Lösung mit Zend Framework ist ein benutzerdefinierter Filter, der dem Element hinzugefügt wird, da dies kein echtes Problem bei NumberFormatter oder pecl-intl ist. – nofreeusername