2012-05-22 13 views
7

Chcę podzielić ciąg z odstępem białym. ale powinien inteligentnie obsługiwać cytowane ciągi. Na przykład. w przypadku ciągu takiego jakPodział cytowanego ciągu znaków z ogranicznikiem

"John Smith" Ted Barry 

Powinno zwrócić trzy ciągi: John Smith, Ted i Barry.

+2

Najprawdopodobniej musisz najpierw podzielić zacytowane załączone ciągi, a następnie podzielić pozostałą część ciągu na białe znaki. Tutaj musi być kilka pytań o to, jak zrobić pierwszy krok. Drugi krok jest banalny. – jahroy

+1

I co próbowaliście? –

+2

Przyzwoita biblioteka parsera CSV będzie dobrze działać. Większość pozwoli na wybór ogranicznika i będzie respektować i unikać dzielenia cytowanego tekstu. –

Odpowiedz

10

Po zamieszaniu, możesz użyć Regex do tego. Uruchom odpowiednik "pasuje do wszystkich" na:

((?<=("))[\w ]*(?=("(\s|$))))|((?<!")\w+(?!")) 

Java Przykład:

import java.util.regex.Pattern; 
import java.util.regex.Matcher; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     String someString = "\"Multiple quote test\" not in quotes \"inside quote\" \"A work in progress\""; 
     Pattern p = Pattern.compile("((?<=(\"))[\\w ]*(?=(\"(\\s|$))))|((?<!\")\\w+(?!\"))"); 
     Matcher m = p.matcher(someString); 

     while(m.find()) { 
      System.out.println("'" + m.group() + "'"); 
     } 
    } 
} 

wyjściowa:

'Multiple quote test' 
'not' 
'in' 
'quotes' 
'inside quote' 
'A work in progress' 

Regularny podział wyrażenie na przykładzie używanego powyżej można obejrzeć tutaj :

http://regex101.com/r/wM6yT9


Mimo wszystko, regularne wyrażenia nie powinny być rozwiązaniem dla wszystkiego - po prostu dobrze się bawiłem. Ten przykład ma wiele przypadków skrajnych, takich jak obsługa znaków Unicode, symboli itp. Lepiej byłoby użyć wypróbowanej i prawdziwej biblioteki dla tego rodzaju zadania. Spójrz na inne odpowiedzi, zanim skorzystasz z tego.

+0

Nie jestem pewien, czy dane wejściowe zawierają kodowanie Unicode czy nie, ale twój kod nie będzie w stanie poradzić sobie z tym. – nhahtdh

+0

to jest dobry przykład. +1, dlaczego nie wstawisz, jeśli chcesz sprawdzić, czy m.group() zwraca puste miejsce, w ten sposób nie musisz wypisać pustych miejsc. –

+0

Brilliant ... +1 –

4

Spróbuj tego paskudnego fragmentu kodu.

String str = "hello my dear \"John Smith\" where is Ted Barry"; 
    List<String> list = Arrays.asList(str.split("\\s")); 
    List<String> resultList = new ArrayList<String>(); 
    StringBuilder builder = new StringBuilder(); 
    for(String s : list){ 
     if(s.startsWith("\"")) { 
      builder.append(s.substring(1)).append(" "); 
     } else { 
      resultList.add((s.endsWith("\"") 
        ? builder.append(s.substring(0, s.length() - 1)) 
        : builder.append(s)).toString()); 
      builder.delete(0, builder.length()); 
     } 
    } 
    System.out.println(resultList);  
+0

Znacznie lepiej niż mój kod. +1 –

+0

Nadmiar pustego miejsca spowoduje, że program wygeneruje puste ciągi. – nhahtdh

+0

@nhahtdh: O'yeah. Właśnie podałem wskazówkę. Nie w 100% działające rozwiązanie. Trevor Senior, dobrze to załatwił. Ale ma też ten sam problem z pustymi miejscami. Ale to nie jest prawdziwy problem i można go łatwo naprawić. –

1

commons-lang ma klasę StrTokenizer, która zrobi to za Ciebie, istnieje również biblioteka java-csv.

Przykład z StrTokenizer:

String params = "\"John Smith\" Ted Barry" 
// Initialize tokenizer with input string, delimiter character, quote character 
StrTokenizer tokenizer = new StrTokenizer(params, ' ', '"'); 
for (String token : tokenizer.getTokenArray()) { 
    System.out.println(token); 
} 

wyjściowa:

John Smith 
Ted 
Barry 
+0

@BasilioGerman Dodałem przykład, aby rozważyć usunięcie komentarza. –

3

dobrze, zrobiłem mały snipet że nie, co chcesz i jeszcze kilka rzeczy. ponieważ nie określiłeś więcej warunków, nie przeszedł przez kłopoty. Wiem, że to jest brudny sposób i prawdopodobnie możesz uzyskać lepsze wyniki z czegoś, co już zostało zrobione. ale dla zabawy programowania tutaj jest przykład:

String example = "hello\"John Smith\" Ted Barry lol\"Basi German\"hello"; 
    int wordQuoteStartIndex=0; 
    int wordQuoteEndIndex=0; 

    int wordSpaceStartIndex = 0; 
    int wordSpaceEndIndex = 0; 

    boolean foundQuote = false; 
    for(int index=0;index<example.length();index++) { 
     if(example.charAt(index)=='\"') { 
      if(foundQuote==true) { 
       wordQuoteEndIndex=index+1; 
       //Print the quoted word 
       System.out.println(example.substring(wordQuoteStartIndex, wordQuoteEndIndex));//here you can remove quotes by changing to (wordQuoteStartIndex+1, wordQuoteEndIndex-1) 
       foundQuote=false; 
       if(index+1<example.length()) { 
        wordSpaceStartIndex = index+1; 
       } 
      }else { 
       wordSpaceEndIndex=index; 
       if(wordSpaceStartIndex!=wordSpaceEndIndex) { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, wordSpaceEndIndex)); 
       } 
       wordQuoteStartIndex=index; 
       foundQuote = true; 
      } 
     } 

     if(foundQuote==false) { 
      if(example.charAt(index)==' ') { 
       wordSpaceEndIndex = index; 
       if(wordSpaceStartIndex!=wordSpaceEndIndex) { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, wordSpaceEndIndex)); 
       } 
       wordSpaceStartIndex = index+1; 
      } 

      if(index==example.length()-1) { 
       if(example.charAt(index)!='\"') { 
        //print the word in spaces 
        System.out.println(example.substring(wordSpaceStartIndex, example.length())); 
       } 
      } 
     } 
    } 

to sprawdza także słów, które nie zostały rozdzielone spacją przed lub po cudzysłowu, takich jak słowa „Hello” przed „John Smith” i po "Basi niemiecki".

gdy łańcuch jest zmodyfikowany "John Smith" Ted Barry wyjście jest trzy struny, 1) "John Smith" 2) Ted 3) Barry

Ciąg w przykładzie jest cześć "John Smith" Ted Barry lol "Basi German" cześć i drukuje 1) cześć 2) "John Smith" 3) Ted 4) Barry 5) lol 6) "Basi German" 7) cześć

Nadzieja pomaga

+1

To jest najlepszy kod spośród wszystkich tych. Może obsłużyć dane wejściowe Unicode i nie generuje pustych ciągów, gdy występują nadmierne spacje. Zachowa wszystko w cudzysłowie nietknięte (cóż, może to być plus lub minus). Myślę, że kod można nieco zmodyfikować, aby usunąć cytaty. Dalsza ekspansja może polegać na: dodaniu obsługi wycofywanego cudzysłowu. – nhahtdh

+0

Oczywiście, cytaty można usunąć. tylko zrobiłem to, żeby zachować cytaty. Dodałem komentarze, gdzie usunąć cytaty. –

1

To jest moja własna wersja, oczyść ją z http://pastebin.com/aZngu65y (w komentarzu). Może zająć się Unicode. Sprzątnie wszystkie przestrzenie (nawet w cudzysłowie) - w zależności od potrzeby może być dobre lub złe. Brak obsługi wycofanych cytatów.

private static String[] parse(String param) { 
    String[] output; 

    param = param.replaceAll("\"", " \" ").trim(); 
    String[] fragments = param.split("\\s+"); 

    int curr = 0; 
    boolean matched = fragments[curr].matches("[^\"]*"); 
    if (matched) curr++; 

    for (int i = 1; i < fragments.length; i++) { 
    if (!matched) 
     fragments[curr] = fragments[curr] + " " + fragments[i]; 

    if (!fragments[curr].matches("(\"[^\"]*\"|[^\"]*)")) 
     matched = false; 
    else { 
     matched = true; 

     if (fragments[curr].matches("\"[^\"]*\"")) 
     fragments[curr] = fragments[curr].substring(1, fragments[curr].length() - 1).trim(); 

     if (fragments[curr].length() != 0) 
     curr++; 

     if (i + 1 < fragments.length) 
     fragments[curr] = fragments[i + 1]; 
    } 
    } 

    if (matched) { 
    return Arrays.copyOf(fragments, curr); 
    } 

    return null; // Parameter failure (double-quotes do not match up properly). 
} 

próbki wejściowe dla porównania:

"sdfskjf" sdfjkhsd "hfrif ehref" "fksdfj sdkfj fkdsjf" sdf sfssd 


asjdhj sdf ffhj "fdsf fsdjh" 
日本語 中文 "Tiếng Việt" "English" 
    dsfsd  
    sdf  " s dfs fsd f " sd f fs df fdssf "日本語 中文" 
"" ""  "" 
" sdfsfds " "f fsdf 

(2 linia jest pusta, 3. linia obowiązuje, ostatnia linia jest uszkodzony). Proszę oceniać na podstawie własnych oczekiwanych wyników, ponieważ może się różnić, ale linia bazowa jest taka, że ​​pierwszy przypadek powinien powrócić [sdfskjf, sdfjkhsd, hfrif ehref, fksdfj sdkfj fkdsjf, sdf, sfssd].

Powiązane problemy