2013-01-23 10 views
10

Sto cercando un modo per confrontare due stringhe Java che sono lessicograficamente equivalenti ma non identiche a livello di byte.Confronta due stringhe lessicograficamente equivalenti ma non identiche a livello di byte

Più precisamente prendere il seguente nome file "baaaé.png", a livello di byte che può essere rappresentato in due modi diversi:

[98, 97, 97, 97, -61, -87 , 46, 112, 110, 103] -> il "é" è codificato con 2 byte

[98, 97, 97, 97, 101, -52, -127, 46, 112, 110, 103] -> il "é" è codificato con 3 byte

byte[] ch = {98, 97, 97, 97, -61, -87, 46, 112, 110, 103}; 
    byte[] ff = {98, 97, 97, 97, 101, -52, -127, 46, 112, 110, 103}; 

    String st = new String(ch,"UTF-8"); 
    String st2 = new String(ff,"UTF-8"); 
    System.out.println(st); 
    System.out.println(st2); 
    System.out.println(st.equals(st2)); 

Genererà il seguente risultato:

baaaé.png 
baaaé.png 
false 

C'è un modo per fare il confronto in modo che il metodo equals restituisce true?

+5

Non rendono lo stesso qui. –

+3

@dystroy che ci porta a riconsiderare la frase "_lexicographically equivalent_" :) – Fallup

+3

@dystroy Il modulo di normalizzazione (fortemente) preferito per il web è NFC. A quanto pare il tuo browser web prende la scorciatoia facile e supporta solo NFC, non NFD. Per quello che vale, il mio fa lo stesso. Apparentemente i browser Web non si preoccupano di implementare NFD. Tuttavia, posso copiare e incollare entrambi gli esempi in un'applicazione diversa che supporta sia NFC che NFD e vengono visualizzati in modo identico. – Celada

risposta

8

È possibile utilizzare la classe Collator con una resistenza applicabile per normalizzare elementi come accenti diversi. questo ti permetterà di confrontare le stringhe con successo.

In questo caso, un locale degli Stati Uniti e un punto di forza terziaria è sufficiente per ottenere le stringhe di essere uguali

Collator usCollator = Collator.getInstance(); 
usCollator.setStrength(Collator.TERTIARY); 
System.out.println(usCollator.equals(st, st2)); 

uscite

true 

È inoltre possibile utilizzare la classe di Java Normalizer per la conversione tra diversi forme di Unicode. Questo trasformerà le tue stringhe, ma finiranno per essere le stesse, permettendoti di usare gli strumenti standard per eseguire il confronto

Infine, potrebbe essere utile dare un'occhiata al progetto ICU (International Components for Unicode), che fornisce molti strumenti per lavorare con le stringhe Unicode in molti modi diversi.

+0

Ho testato la classe Normalizer e funziona perfettamente. Grazie. – Davz

7

Ci sono due tipi di Unicode normalization forms che avete bisogno di guardare in:

Ci

primo è NFC vs NFD. L'esempio che inserisci nella tua domanda è un eccellente esempio del diverso tra NFC e NFD. La prima stringa è in NFC mentre la seconda è in NFD.

In Unicode, molti caratteri accentati possono essere rappresentati in due modi diversi: come il carattere base seguito da un accento combinato o come carattere accentato precomposto. NFC utilizza i caratteri precomposti quando sono disponibili nell'area. NFD usa sempre moduli decomposti.

Normalmente non usiamo un mix di NFC e NFD. La maggior parte degli ambienti specifica quale è la forma preferita. Molto brevemente: i nomi di file MacOS X utilizzano NFD e praticamente tutto il resto usa NFC. Ma se ti viene fornito un input che potrebbe essere nel modulo di normalizzazione "altro", puoi facilmente convertirlo: il processo è semplice (utilizzando le informazioni fornite dal database dei caratteri Unicode) e senza perdita (cioè puoi andare avanti e indietro tra NFC e NFD se lo desideri senza perdere informazioni).

java fornisce una classe integrata denominata Normalizer che può convertire una stringa in un determinato modulo Unicode.

Esistono altre 2 forme di normalizzazione: NFKC e NFKD. Queste forme non sono intese per uso generale, ma solo per confronti lessicografici. Essi rappresentano il fatto che, per esempio, ¼ dovrebbe essere considerato uguale a 1/4 in una ricerca o confronto. Ma non implicano che 1/4 e 1/4 siano uguali o che uno debba generalmente essere convertito nell'altro.

La conversione da NFC a NFKC e da NFD a NFKD è di nuovo semplice (è necessario il database dei caratteri) ma questa volta è una perdita. È necessario mantenere il testo originale NFC/NFD e utilizzare NFKC/NFKD solo come chiave di ricerca/ordinamento.

+0

java fornisce una classe integrata chiamata [Normalizer] (http://docs.oracle.com/javase/6/docs/api/java/text/Normalizer.html) che può convertire una stringa in un dato modulo Unicode –

+0

+ 1 per la tua risposta dettagliata che spiega chiaramente la causa principale del problema. – Davz

Problemi correlati