2013-01-31 10 views
18

ho i seguenti caratteri che vorrei essere considerato "illegale":funzione di Java da restituire se stringa contiene caratteri non validi

~, #, @, *, +, %, {, }, <, >, [, ], |, , , \, _, ^

Vorrei scrivere un metodo che ispeziona una stringa e determina (true/false) se la stringa contiene questi illegals:

public boolean containsIllegals(String toExamine) { 
    return toExamine.matches("^.*[~#@*+%{}<>[]|\"\\_^].*$"); 
} 

Tuttavia, un semplice controllo matches(...) non è fattibile per questo. Ho bisogno del metodo per scansionare ogni carattere nella stringa e assicurarmi che non sia uno di questi personaggi. Certo, avrei potuto fare qualcosa orribile come:

public boolean containsIllegals(String toExamine) { 
    for(int i = 0; i < toExamine.length(); i++) { 
     char c = toExamine.charAt(i); 

     if(c == '~') 
      return true; 
     else if(c == '#') 
      return true; 

     // etc... 
    } 
} 

C'è un modo più elegante/efficiente di realizzare questo?

+5

perché non è possibile utilizzare "partite"? –

+0

perché non è bello! – thang

risposta

25

Si può fare uso di Pattern e Matcher di classe qui. Puoi inserire tutti i caratteri filtrati in una classe di caratteri e utilizzare il metodo Matcher#find() per verificare se il tuo modello è disponibile in stringa o meno.

Si può fare in questo modo: -

metodo
public boolean containsIllegals(String toExamine) { 
    Pattern pattern = Pattern.compile("[~#@*+%{}<>\\[\\]|\"\\_^]"); 
    Matcher matcher = pattern.matcher(toExamine); 
    return matcher.find(); 
} 

find() restituirà true, se il modello dato si trova nella stringa, anche una sola volta.


Un altro modo che non è ancora stato sottolineato sta utilizzando String#split(regex). Possiamo dividere la stringa sul modello dato e controllare la lunghezza della matrice. Se la lunghezza è 1, il pattern non era nella stringa.

public boolean containsIllegals(String toExamine) { 
    String[] arr = toExamine.split("[~#@*+%{}<>\\[\\]|\"\\_^]", 2); 
    return arr.length > 1; 
} 

Se arr.length > 1, questo significa che la stringa contiene uno dei personaggi nel modello, è per questo che è stata divisa. Ho passato limit = 2 come secondo parametro a split, perché siamo a posto con un solo split.

+0

Il più pulito e spiegato meglio. – IAmYourFaja

+0

Per coloro che seguono e vengono incastrati nei dettagli, si noti che con "matcher.find" si utilizza l'espressione regolare più breve con solo il contenuto all'interno delle parentesi, ma con "matcher.matches" si utilizzerà l'espressione più lunga. Entrambe le tecniche hanno superato i miei test unitari fintanto che viene utilizzata l'espressione regolare corretta per ciascuno. – Ted

+0

Il secondo metodo è molto bello! Bello –

10

Ho bisogno il metodo per eseguire la scansione di ogni carattere della stringa

Se devi farlo carattere per carattere, regexp non è probabilmente un buon modo per andare. Tuttavia, dal momento che tutti i personaggi sul "lista nera" avere codici inferiore a 128, è possibile farlo con una piccola boolean matrice:

static final boolean blacklist[] = new boolean[128]; 

static { 
    // Unassigned elements of the array are set to false 
    blacklist[(int)'~'] = true; 
    blacklist[(int)'#'] = true; 
    blacklist[(int)'@'] = true; 
    blacklist[(int)'*'] = true; 
    blacklist[(int)'+'] = true; 
    ... 
} 

static isBad(char ch) { 
    return (ch < 128) && blacklist[(int)ch]; 
} 
+0

Se non sbaglio, i booleani non inizializzati diventano falsi in Java, non è vero? – 11684

+0

@ 11684 Corretto - gli elementi degli array 'boolean' sono inizialmente' false'. – dasblinkenlight

+1

Forse questa potrebbe essere una parte della risposta, quindi anche i programmatori possono capirlo? – 11684

7

Se non è possibile utilizzare un dispositivo di corrispondenza, è possibile eseguire un'operazione di questo tipo, che è più pulita di una serie di istruzioni if ​​diverse o un array di byte.

for(int i = 0; i < toExamine.length(); i++) { 
    char c = toExamine.charAt(i); 
    if("~#@*+%{}<>[]|\"_^".contains(c)){ 
     return true; 
    } 
} 
5

Prova la negazione di una classe di caratteri che contiene tutti i personaggi nella lista nera:

public boolean containsIllegals(String toExamine) { 
    return toExamine.matches("[^~#@*+%{}<>\\[\\]|\"\\_^]*"); 
} 

Ciò restituirà true se la stringa contiene clandestini (la funzione originale sembrava di tornare false in quel caso).

Il cursore ^ appena a destra della staffa di apertura [ nega la classe di caratteri. Si noti che in String.matches() non sono necessari gli ancoraggi ^ e $ perché corrispondono automaticamente all'intera stringa.

2

Un modo piuttosto compatto di fare questo sarebbe quello di affidarsi al metodo di String.replaceAll:

public boolean containsIllegal(final String toExamine) { 
    return toExamine.length() != toExamine.replaceAll(
      "[~#@*+%{}<>\\[\\]|\"\\_^]", "").length(); 
} 
6

utilizzare una costante per evita ricompilare il regex in ogni convalida.

private static final Pattern INVALID_CHARS_PATTERN = 
           Pattern.compile("^.*[~#@*+%{}<>\\[\\]|\"\\_].*$"); 

E modificare il codice per:

public boolean containsIllegals(String toExamine) { 
    return INVALID_CHARS_PATTERN.matcher(toExamine).matches(); 
} 

Questo è il modo più efficiente con Regex.

Problemi correlati