2012-11-03 16 views
5

Attualmente sto cercando di risolvere un problema da codingbat.com con espressioni regolari.Iterazione tramite stringa con .find() in Java espressione regolare

Sono nuovo per questo, quindi le spiegazioni passo-passo sarebbero apprezzate. Potrei risolvere questo problema con metodi String in modo relativamente semplice, ma sto cercando di usare espressioni regolari.

Ecco il prompt: Dato una stringa e una stringa di parole non vuota, restituisce una stringa composta da ciascun carattere appena prima e subito dopo ogni aspetto della parola nella stringa. Ignora i casi in cui non vi è alcun carattere prima o dopo la parola e un carattere può essere incluso due volte se si trova tra due parole.

wordEnds("abcXY123XYijk", "XY") → "c13i" 
wordEnds("XY123XY", "XY") → "13" 
wordEnds("XY1XY", "XY") → "11" 

ecc

Il mio codice finora:

String regex = ".?" + word+ ".?"; 
Pattern p = Pattern.compile(regex); 
Matcher m = p.matcher(str); 

String newStr = ""; 
while(m.find()) 
    newStr += m.group().replace(word, ""); 

return newStr; 

Il problema è che quando ci sono più istanze di parola in una riga, il programma manca il carattere che precede la parola perché m. find() va oltre.

Ad esempio: wordEnds("abc1xyz1i1j", "1") dovrebbe restituire "cxziij", ma il mio metodo restituisce "cxzij", non ripetere il "i"

Gradirei una soluzione non-disordinato con una spiegazione posso applicare ad altri problemi regex generale.

+0

Vai a questa risposta sulle espressioni look-giro regolare http: // StackOverflow. com/a/2995621/324900 – Reddy

+0

davvero utile, grazie – Rishi

+0

felice di essere di aiuto! :) – Reddy

risposta

1

Si tratta di una soluzione one-liner:

String wordEnds = input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3"); 

Questo corrisponde al tuo caso limite come uno sguardo in avanti all'interno di un gruppo non-cattura, corrisponde poi la solita caso (consumando).

Nota che i tuoi requisiti non richiedono iterazione, solo il titolo della tua domanda presuppone che sia necessario, il che non lo è.

Si noti anche che per essere assolutamente sicuro, si dovrebbe sfuggire a tutti i caratteri in word nel caso qualcuno di loro sono speciali caratteri "espressioni regolari", quindi se non si può garantire che, è necessario utilizzare Pattern.quote(word) invece di word.

Ecco una prova della solita caso e il caso limite, mostrando funziona:

public static String wordEnds(String input, String word) { 
    word = Pattern.quote(word); // add this line to be 100% safe 
    return input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3"); 
} 

public static void main(String[] args) { 
    System.out.println(wordEnds("abcXY123XYijk", "XY")); 
    System.out.println(wordEnds("abc1xyz1i1j", "1")); 
} 

uscita:

c13i 
cxziij 
+0

Questo non è giusto - tornerò su questo più avanti – Bohemian

+0

ora ho capito quanto è efficace la regex, grazie – Rishi

+0

@Bohemian che non è corretto ha bisogno di 'cxziij' come output non' cxzi'..che è il la ragione yi aveva usato i lookaround ... – Anirudha

0

Usa lookbehind positivo e lookahead postive che sono asserzioni di lunghezza zero

(?<=(.)|^)1(?=(.)|$) 
    ^ ^ ^-looks for a character after 1 and captures it in group2 
    |  |->matches 1..you can replace it with any word 
    | 
    |->looks for a character just before 1 and captures it in group 1..this is zero width assertion that doesn't move forward to match.it is just a test and thus allow us to capture the values 

$1 e $2 contiene il vostro value..Go sulla ricerca fino alla fine

quindi questo dovrebbe essere come

String s1 = "abcXY123XYiXYjk"; 
String s2 = java.util.regex.Pattern.quote("XY"); 
String s3 = ""; 
String r = "(?<=(.)|^)"+s2+"(?=(.)|$)"; 
Pattern p = Pattern.compile(r); 
Matcher m = p.matcher(s1); 
while(m.find()) s3 += m.group(1)+m.group(2); 
//s3 now contains c13iij 

opere here

+0

grazie! probabilmente dovrebbe fare ancora un po 'di lettura ... – Rishi

+4

-1 Waaaaaay troppo complicato, e in realtà sbagliato. Non hai bisogno di guardare intorno! Basta usare '(.)' - dice "non combaciano se non c'è un personaggio", ma hai finito di incassare abbinando inizio e fine, che in realtà * non * è ciò che l'OP dice che vuole – Bohemian

+0

@ Bohemian Mi è piaciuta la tua risposta originale per la sua semplicità, quindi ti sarei grato se potessi postare (con str.replace) – Rishi

0

Usa espressione regolare come segue:

Matcher m = Pattern.compile("(.|)" + Pattern.quote(b) + "(?=(.?))").matcher(a); 
for (int i = 1; m.find(); c += m.group(1) + m.group(2), i++); 

check this demo.

Problemi correlati