2009-06-29 3 views
28

Durante la ricerca di un modo corretto per tagliare lo spazio non interrotto dall'HTML analizzato, per prima cosa sono incappato nella definizione spartana di Java di String.trim() che è almeno adeguatamente documentata. Volevo evitare di elencare esplicitamente caratteri idonei per il ritaglio, quindi ho pensato che usare i metodi di supporto Unicode sulla classe Personaggio avrebbe fatto il lavoro per me.Perché lo spazio non-breaking non è un carattere di spazio bianco in java?

Questo è quando ho scoperto che Character.isWhitespace(char) esclude esplicitamente spazi unificatori:

E 'un Unicode carattere di spazio (SPACE_SEPARATOR, LINE_SEPARATOR, o PARAGRAPH_SEPARATOR) ma non è anche uno spazio unificatore ('\u00A0' , '\u2007', '\u202F').

Perché è quello?

L'implementazione di corresponding .NET equivalent è meno discriminante.

risposta

20

Character.isWhitespace(char) è vecchio. Davvero vecchio Molte cose fatte nei primi giorni di Java seguivano convenzioni e implementazioni da C.

Ora, più di un decennio dopo, queste cose sembrano errate. Consideralo come prova di quanto siano arrivate le cose, anche tra i primi giorni di Java e i primi giorni di .NET.

Java aspira a essere compatibile al 100% con le versioni precedenti. Quindi, anche se il team di Java pensava che sarebbe stato utile correggere il loro errore iniziale e aggiungere spazi non interrotti all'insieme di caratteri che restituisce true da Character.isWhitespace (char), non possono, perché esiste quasi sicuramente un software che si affida all'attuale implementazione funzionando esattamente come fa.

+3

Per quanto riguarda la retrocompatibilità: sono d'accordo, ma non vi è alcun motivo per non aggiungere, per esempio, Character.isWhitespaceNew (char) per acquisire la situazione attuale. – Jirka

+13

In fondo a questa strada giace PHP. – Eric

+7

E giù per l'altra strada bugie, beh, Java. Un linguaggio che ha aperto la strada a coloro che seguirono (che hanno imparato dai suoi errori), ma perché qualcuno lo userebbe volontariamente se avessero altre opzioni è al di là della mia comprensione. – Eloff

2

Sembra che il nome del metodo (isWhitespace) non sia coerente con la sua funzione (per rilevare i separatori). La funzionalità "separatore" è abbastanza evidente se si guarda l'elenco completo dei personaggi dalla pagina Javadoc hai citato:

* It is a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) but is not also a non-breaking space ('\u00A0', '\u2007', '\u202F'). 
* It is '\u0009', HORIZONTAL TABULATION. 
* It is '\u000A', LINE FEED. 
* It is '\u000B', VERTICAL TABULATION. 
* It is '\u000C', FORM FEED. 
* It is '\u000D', CARRIAGE RETURN. 
* It is '\u001C', FILE SEPARATOR. 
* It is '\u001D', GROUP SEPARATOR. 
* It is '\u001E', RECORD SEPARATOR. 
* It is '\u001F', UNIT SEPARATOR. 

Una funzione di spazio unificatore si suppone che sia spazio visivo tra le parole che non è separata da algoritmi di sillabazione.

7

Direi che l'implementazione di Java è più corretta di .NET. Lo spazio senza interruzioni è essenzialmente un carattere non di uno spazio bianco che sembra uno. Cioè, se hai le stringhe "foo" e "bar", e metti tra loro qualsiasi carattere tradizionale di spazi vuoti, otterrai un'interruzione di parole. Uno spazio senza interruzione, tuttavia, non rompe i due.

+4

Uno spazio non interruttivo è ancora un limite di parole. La "rottura" in "spazio non frazionato" si riferisce a come dovrebbe essere interpretato ai fini della ** linea ** - rottura, non interruzioni di parole. – richardtallent

6

L'unica volta che uno spazio irrinunciabile deve essere trattato in modo speciale è con il codice progettato per eseguire il word-wrapping del testo.

Per tutti gli altri scopi, compresi il conteggio delle parole, il taglio e la divisione generica lungo i confini delle parole, uno spazio non interruttivo è ancora uno spazio bianco.

Qualsiasi argomentazione che uno spazio non interrompente "assomiglia" a uno spazio ma non è in conflitto con il punto intero di Unicode, che rappresenta i caratteri in base al loro significato, non a come vengono visualizzati.

Pertanto, IMHO, l'implementazione Java di String.trim() non funziona come previsto e la funzione sottostante di Character.isWhitespace() è in errore.

La mia ipotesi è che gli implementatori Java abbiano scritto isWhitespace() in base alla necessità di eseguire il text-wrapping all'interno dei controlli. Dovrebbero aver chiamato questa funzione è WordWrappingBoundary() o qualcosa di più chiaro, e usato un test di spazi bianchi meno restrittivo per trim().

+5

String.trim() è ancora più rotto di quello. Taglia solo i caratteri di controllo ASCII e nessuno spazio bianco Unicode, che si spezzi o no. – Thilo

13

Poiché Java 5 esiste anche un metodo isSpaceChar(int). Non fa quello che vuoi?

Determina se il carattere specificato (punto di codice Unicode) è un carattere di spazio Unicode. Un carattere è considerato un carattere di spazio se e solo se è specificato che è uno spazio con lo standard Unicode. Questo metodo restituisce true se il tipo di categoria generale del personaggio è uno dei seguenti: ...

+1

Non è tanto l'esistenza di un tale metodo che l'OP stava cercando; ma piuttosto una funzione di tipo 'trim' che * usa * quel metodo per determinare cosa spogliare. –

+0

Si noti che esiste anche un metodo 'isSpaceChar (char)' –

+0

Il metodo isSpaceChar() non include lo spazio bianco latente (scheda, ad esempio). – zendu

10

Come postato in precedenza, isSpaceChar(int) fornirà l'OP con una pista per la risposta. Sembra discretamente discretamente documentato, ma questo metodo è in realtà useable with regexes. Quindi:

"X\u00A0X X".replaceAll("\\p{javaSpaceChar}", "_"); 

produrrà una stringa "X_X_X". È lasciato come esercizio per il lettore di venire con la regex per tagliare una stringa. (Il modello con alcune bandiere dovrebbe fare il trucco.)

+0

Funziona greate, ha bisogno di extra "->" X \ u00A0XX ".replaceAll (" \\ p {javaSpaceChar} "," _ ")); – user85155

+0

\ p {javaSpaceChar} non sembra essere documentato ovunque. – zendu

+1

@zendu - lo è, anche se non in modo molto visibile: 1) https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#jcc: > Categorie che si comportano come java. lang.Character boolean I metodi ismethodname (tranne quelli deprecati) sono disponibili tramite la stessa sintassi \ p {prop} in cui la proprietà specificata ha il nome javamethodname. 2) https://docs.oracle.com/javase/7 /docs/api/java/lang/Character.html#isSpaceChar(char) –

2

Anche essere cauti quando si utilizza la funzione di apache comuni StringUtils.isBlank() (e funzioni correlate) che ha lo stesso strano comportamento isWhitespace, vale a dire uno spazio non interruzione è considerato non- vuoto.