2010-11-17 15 views
6

Więc załóżmy mam:Jak znaleźć znaki wspólne dla dwóch ciągów w Javie przy użyciu pojedynczego replaceAll?

String s = "1479K"; 
String t = "459LP"; 

i chcę wrócić

String commonChars = "49"; 

wspólnych znaków między dwa ciągi.

Oczywiście jest to możliwe do zrobienia za pomocą standardowego pętli jak:

String commonChars = ""; 
for (i = 0; i < s.length; i++) 
{ 
    char ch = s.charAt(i); 
    if (t.indexOf(ch) != -1) 
    { 
     commonChars = commonChars + ch; 
    } 
} 

Jednak chciałbym, aby móc to zrobić w jednej linii przy użyciu replaceAll. Można to zrobić w następujący sposób:

String commonChars = s.replaceAll("["+s.replaceAll("["+t+"]","")+"]",""); 

Moje pytanie brzmi: czy to możliwe, aby to zrobić za pomocą jednego wywołanie replaceAll? A jaki byłby wyraz regularny? Przypuszczam, że muszę użyć jakiegoś rodzaju przodka, ale mój mózg zamienia się w papkę, kiedy nawet o tym myślę.

Odpowiedz

4
String commonChars = s.replaceAll("[^"+t+"]",""); 

Należy pamiętać, że może być konieczne pominięcie znaków specjalnych w t, np. używając Pattern.quote(t) zamiast powyższego t.

+0

teraz czuję się bardzo głupi – Kidburla

4

Przyjęty odpowiedź:

String commonChars = s.replaceAll("[^"+t+"]",""); 

ma błąd !!!

Co się stanie, jeśli ciąg znaków t ma meta-znak regularny? W takim przypadku błąd replaceAll kończy się niepowodzeniem.

See this program jako przykład gdzie ciąg t ma ] w nim i ] jest regex meta-znaków, które oznacza koniec klasy postaci. Oczywiście program nie wytwarza oczekiwanych wyników.

Dlaczego?

Rozważmy:

String s = "1479K"; 
String t = "459LP]"; 

Teraz regex będzie (tylko zastąpić t):

String commonChars = s.replaceAll("[^459LP]]",""); 

który mówi zastąpić dowolny znak inny niż 4, 5, 9, L, Pnastępnie a] bez niczego. Co oczywiście nie jest tym, czego chcesz.

Aby rozwiązać problem, należy uciec przed numerem ] pod numerem t. Możesz to zrobić ręcznie jako:

String t = "459LP\\]"; 

i regex works fine.

Jest to częsty problem przy użyciu regex, więc klasa java.util.regex.Pattern zapewnia metodę statyczną o nazwie quote który może być używany do dokładnie to zrobić: Cytat regex-metaznaki tak, że są one traktowane dosłownie.

więc przed użyciem t w replaceAll cytujesz je jako:

t = Pattern.quote(t); 

Program using quote method działa zgodnie z oczekiwaniami.

+0

Czy to znaczy, że należy zrobić: commonChars String = s.replaceAll ("[^" + Pattern.quote (t) +” ] "," "); zamiast tego? Czy to nadal będzie sprawdzać indywidualnie każdą postać? – Kidburla

1
public class common { 

    public static void main(String args[]) { 
     String s = "FIRST"; 
     String s1 = "SECOND"; 
     String common = s.replaceAll("[^" + s1 + "]", ""); 
     System.out.println(common); 
    } 
} 
2

Przyjęta odpowiedź jest niepoprawna. Ponieważ replaceAll jest wzorcem, musimy wziąć pod uwagę składnię. Co się stanie, jeśli s1 = "\\t"? A co się stanie, jeśli s1 = "]{"?

Jeśli wszystkie znaki są w przedziale [0 - 255], możemy działać tak:

  1. byte[] tmp = new byte[255];
  2. pętli każdy char w pierwszym ciągiem

    for (char c : str1.toCharArray())
    // or use charAt(i) here if (tmp[c] == 0) tmp[c] = 1;

  3. pętli każdy znak w drugim ciągu znaków

    for (char c : str2.toCharArray()) if (tmp[c] == 1) tmp[c] = 2;

  4. zapętlić tablicę tmp, znaleźć elementy o wartości 2, indeks to właściwy znak, którego szukamy.

Innym rozwiązaniem jest użycie HashSet.retainAll(Collection<?> c);

Powiązane problemy