2011-11-25 13 views
43

Staram się wypracować sposób na dzielenie się napis w języku Java, który następuje wzór tak:Jak podzielić ciąg znaków między litery i cyfry (lub między cyframi i literami)?

String a = "123abc345def"; 

Wyniki powinno być następujące:

x[0] = "123"; 
x[1] = "abc"; 
x[2] = "345"; 
x[3] = "def"; 

jednak I jestem całkowicie zaskoczony, w jaki sposób mogę to osiągnąć. Czy ktoś może mi pomóc? Próbowałem wyszukiwać w Internecie dla podobnego problemu, ale bardzo trudno jest go poprawnie wyrazić w wyszukiwaniu.

Uwaga: Numer liter & numery mogą się różnić (np Nie może być ciągiem jak so '1234a5bcdef')

+0

Jeszcze niczego nie próbowałem - nie wiem nawet, od czego zacząć, ponieważ jest to pierwszy czas natknąłem się na coś podobnego. –

+0

Użytkownicy proszeni są o dodanie znacznika "praca domowa" do wszystkich pytań dotyczących problemów z pracą domową. – Michael

+0

@Michael to nie jest pytanie "praca domowa". Nigdy wcześniej nie spotkałem się z tego rodzaju problemem. –

Odpowiedz

74

można spróbować podzielić na (?<=\D)(?=\d)|(?<=\d)(?=\D), jak:

str.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); 

Pasuje do pozycji między liczbą a nie liczbą (w dowolnej kolejności).

+3

Pamiętaj, że to rozwiązanie będzie zagrażać postaciom, które nie są ani cyfrą, ani literą, jak literami, więc możesz chcieć zweryfikować swoje części. – Mario

+0

@Romain, to robi: http://ideone.com/XDsKn – Qtax

+0

@TimPietzcker Nie byłem tym, który zagłosował na to pytanie - nigdy nie widziałem tego w Javie i szczerze prosiłem o potwierdzenie, że działa w Javie . Teraz to przegrywam. – Romain

3

Użyj dwóch różnych wzorów: [0-9]* i [a-zA-Z]* i podziel dwa razy przez każdy z nich.

+0

Dzięki za pomoc w tej sprawie. Nie jestem pewien, czy w pełni rozumiem, co masz na myśli. Czy mógłbyś wyjaśnić nieco więcej szczegółów lub podać podstawowy przykład, aby zobaczyć, co masz na myśli? –

+0

Semantycznie, to byłoby '[0-9] +' i '[a-zA-Z] +' ... Chociaż oni zrobią to samo. – Romain

+0

Najpierw podzielisz ciąg na wzór cyfrowy i uzyskasz tablicę ciągów, po czym podzielisz ciąg na wzór literowy i otrzymasz tablicę liczb. Połącz dwie tablice, otrzymasz to, co chcesz. – mishadoff

1

Nie używał Java od wieków, więc po prostu jakiś pseudo-kod, który powinien pomóc Ci zacząć (szybciej dla mnie niż szukanie wszystkiego :)).

string a = "123abc345def"; 
string[] result; 
while(a.Length > 0) 
{ 
     string part; 
     if((part = a.Match(/\d+/)).Length) // match digits 
      ; 
     else if((part = a.Match(/\a+/)).Length) // match letters 
      ; 
     else 
      break; // something invalid - neither digit nor letter 
     result.append(part); 
     a = a.SubStr(part.Length - 1); // remove the part we've found 
} 
9

Jak o:

private List<String> Parse(String str) { 
    List<String> output = new ArrayList<String>(); 
    Matcher match = Pattern.compile("[0-9]+|[a-z]+|[A-Z]+").matcher(str); 
    while (match.find()) { 
     output.add(match.group()); 
    } 
    return output; 
} 
+0

Dzięki .. To moje prawdziwe wymaganie .. :) –

8

Możesz spróbować tego:

Pattern p = Pattern.compile("[a-z]+|\\d+"); 
Matcher m = p.matcher("123abc345def"); 
ArrayList<String> allMatches = new ArrayList<>(); 
while (m.find()) { 
    allMatches.add(m.group()); 
} 

wyniku (allMatches) będą:

["123", "abc", "345", "def"] 
+0

To nie jest poprawna składnia Java. –

+0

Dziękuję Christoffer, redagowałem. –

2

Jeśli szukasz rozwiązania bez używania Java String functi jedność (tj. split, match, itd.), A następnie dodaje powinno pomóc:

List<String> splitString(String string) { 
     List<String> list = new ArrayList<String>(); 
     String token = ""; 
     char curr; 
     for (int e = 0; e < string.length() + 1; e++) { 
      if (e == 0) 
       curr = string.charAt(0); 
      else { 
       curr = string.charAt(--e); 
      } 

      if (isNumber(curr)) { 
       while (e < string.length() && isNumber(string.charAt(e))) { 
        token += string.charAt(e++); 
       } 
       list.add(token); 
       token = ""; 
      } else { 
       while (e < string.length() && !isNumber(string.charAt(e))) { 
        token += string.charAt(e++); 
       } 
       list.add(token); 
       token = ""; 
      } 

     } 

     return list; 
    } 

boolean isNumber(char c) { 
     return c >= '0' && c <= '9'; 
    } 

To rozwiązanie zostanie podzielony liczb i słów „”, gdzie „słowa” są ciągi, które nie zawierają numerów. Jeśli jednak chcesz mieć tylko "słowa" zawierające angielskie litery, możesz je łatwo zmodyfikować, dodając więcej warunków (na przykład wywołanie metody isNumber) w zależności od wymagań (na przykład możesz pominąć słowa zawierające litery inne niż angielskie). Zauważ również, że metoda splitString zwraca ArrayList, która później może zostać przekształcona w tablicę String.

+0

Podoba mi się twój kod, jedna uwaga: return c> = '0' && c <= '9' jest lepsze imo. –

+0

@ LaurensOp'tZandt - dobry połów, edytowany. – sergeyan

1

Robiłem tego rodzaju rzeczy dla kodu krytycznego misji. Tak jak każda ułamek sekundy liczy się, ponieważ muszę przetworzyć 180k wpisów w niezauważalnym czasie. Tak więc pominąłem wyrażenie regularne i całkowicie się rozdzieliłem, co pozwoliło na wbudowane przetwarzanie każdego elementu (chociaż dodanie ich do wersji ArrayList<String> byłoby w porządku). Jeśli chcesz zrobić dokładnie to, czego potrzebujesz, to być czymś 20 razy szybszym ...

void parseGroups(String text) { 
    int last = 0; 
    int state = 0; 
    for (int i = 0, s = text.length(); i < s; i++) { 
     switch (text.charAt(i)) { 
      case '0': 
      case '1': 
      case '2': 
      case '3': 
      case '4': 
      case '5': 
      case '6': 
      case '7': 
      case '8': 
      case '9': 
       if (state == 2) { 
        processElement(text.substring(last, i)); 
        last = i; 
       } 
       state = 1; 
       break; 
      default: 
       if (state == 1) { 
        processElement(text.substring(last, i)); 
        last = i; 
       } 
       state = 2; 
       break; 
     } 
    } 
    processElement(text.substring(last)); 
} 
Powiązane problemy