2013-05-08 9 views
9

Próbuję analizować zlokalizowane łańcuchy walut do waluty i wartości zmiennoprzecinkowej.Jak zmienić zachowanie NumberFormatter :: parseCurrency() dotyczące akceptowania białej przestrzeni i braku łamania przestrzeni?

Wszystko działa dobrze przez jakiś czas, teraz mamy pewne problemy. Wydaje się, że NumberFormatter :: parseCurrency wykorzystuje dodatkową niewidoczny znak:

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 
)); 

wyjściowa:

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... 
} 

Jak widać, istnieje różnica w długości łańcucha produkcji 3 i 4.

Otrzymuję takie same wyniki w PHP 5.3 (ubuntu z włączonym mbstringiem) i 5.4 (serwer Zend na Mac OS X).

Głównym problemem jest to, wartości wejściowe z mojej postaci (ZF1 Application) są w równym stopniu do wyjścia z indeksem 4 ...

jakieś sugestie? z góry dzięki

Edit1:

hexdump wartości robocze:

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

hexdump non wartości roboczej:

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

Edit2:

Wydaje się, że jest to problem z używanym whitepsace. c2 a0 to NO-BREAK SPACE i (może?) wymagane przez NumberFormatter :: parseCurrency(). ale 0x20 jest domyślną przestrzenią (która jest wprowadzana w formularzu wejściowym). Obecny obejście jest zastąpienie spacje z NO-break przestrzeń z $value = str_replace("\x20", "\xC2\xA0", $value);

Edit3:

na innym systemie (Mac OS X z Zend Server 5.6, mbstring włączona, PHP 5.3.14) wszystko działa zgodnie z oczekiwaniami :

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:

główną różnicą pomiędzy pracą z S Tempo i pracy z braku konfiguracji przestrzeni przerwa jest wersja ICU:

wersja robocza:

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 

wersja nie działa:

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

Pomysł: czy znak € od kodera UTF-8 jest zakodowany (0x20AC), a od klawiatury Latin-1 (0x80)? O ile wiem, funkcja strlen() nie zna znaków Unicode. Jeśli jest używane wewnętrznie przez var_dump(), to wyjaśniałoby to dodatkowy znak. – CodeZombie

+0

Moja aplikacja terminalu (iTerm2) używa Unicode (UTF-8) jako emulacji terminalu. Również ten błąd/zachowanie dzieje się z danych wejściowych z przeglądarki poprzez pola wprowadzania tekstu w formacie HTML. Dodałem wyjście heksowe do wyjaśnienia. – nofreeusername

+0

to plik zapisany jako UTF-8? –

Odpowiedz

3

NumberFormatter::parseCurrency jest cienka otoki wokół funkcji biblioteki ICU unum_parseDoubleCurrency (see source).

Funkcja biblioteczna ICU jest restrykcyjna, ponieważ analizuje tylko łańcuchy, które wynikałyby z jej podwójnej funkcji: unum_formatDoubleCurrency. Format jest sterowany przez dane regionalne w formacie Unicode, które określają niepodzieloną przestrzeń między wartością waluty a wartością numeryczną. Najwyraźniej wcześniejsza wersja biblioteki przyjęła inne białe znaki.

Podsumowując, nie można wykonać NumberFormatter::parseCurrency akceptacji spacji. Jednak Zend_Currency powinna również wyjść non-breaking obowiązuje domyślnie:

$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 
); 

pytanie brzmi, która część aplikacji jest wyprowadzanie miejsca i sposobu jego rozwiązania. Wspominasz, że jest to część twojego formularza, więc może mógłbyś spojrzeć na to, że formularz zwraca walutę i wartość jako oddzielne pola, abyś nie musiał się martwić o przetwarzanie liczby. Jeśli użytkownik wprowadza ciąg "88,22 €", może potencjalnie napotkać więcej problemów niż tylko kwestię białych znaków. Po tym, obejście, o którym wspomniałeś (zastąpienie \x20 przez \xc2\xa0) jest jedynym sposobem na rozwiązanie tego problemu, jeśli chcesz używać NumberFormatter.

+0

thx za wyjaśnienie! Zend_Currency zwraca poprawną wartość. Ale moja forma pozwala na bezpośrednie wprowadzanie danych przez użytkownika z floatem w lokalnym formacie z symbolem waluty. Pełne rozwiązanie z Zend Framework to niestandardowy filtr dodawany do elementu, ponieważ nie jest to prawdziwy problem w NumberFormatter lub pecl-intl. – nofreeusername

Powiązane problemy