2011-10-12 11 views
8

muszę przyciąć ciąg w Javie, tak aby:trymowania String w Javie natomiast zachować pełną słowo

Szybki brązowy lis przeskoczył nad psem laz.

staje

Szybki brązowy ...

W powyższym przykładzie, mam przycinanie do 12 znaków. Jeśli po prostu użyć podciąg chciałbym uzyskać:

Szybkie br ...

Mam już sposób to zrobić przy użyciu podciąg, ale chciałem wiedzieć, co jest najszybszy (najbardziej wydajny) sposób, aby to zrobić, ponieważ strona może mieć wiele operacji przycinania.

Jedyny sposób, w jaki mogę myśleć, to podzielić sznur na spacje i złożyć go z powrotem, dopóki jego długość nie przekroczy zadanej długości. Czy istnieje inny sposób? Być może bardziej efektywny sposób, w jaki mogę użyć tej samej metody, aby wykonać "miękkie" wykończenie, w którym zachowuję ostatnie słowo (jak pokazano w powyższym przykładzie) i twarde wykończenie, które jest raczej podłańcuchem.

Dzięki,

Odpowiedz

11

Poniżej znajduje się metoda, której używam do przycinania długich ciągów w moich aplikacjach internetowych. "Miękki" boolean, jak go ustawisz, jeśli jest ustawiony na true, zachowa ostatnie słowo. Jest to najbardziej zwięzły sposób robienia tego, co mogłem wymyślić, który używa StringBuffer, który jest o wiele bardziej wydajny niż odtworzenie łańcucha, który jest niezmienny.

public static String trimString(String string, int length, boolean soft) { 
    if(string == null || string.trim().isEmpty()){ 
     return string; 
    } 

    StringBuffer sb = new StringBuffer(string); 
    int actualLength = length - 3; 
    if(sb.length() > actualLength){ 
     // -3 because we add 3 dots at the end. Returned string length has to be length including the dots. 
     if(!soft) 
      return escapeHtml(sb.insert(actualLength, "...").substring(0, actualLength+3)); 
     else { 
      int endIndex = sb.indexOf(" ",actualLength); 
      return escapeHtml(sb.insert(endIndex,"...").substring(0, endIndex+3)); 
     } 
    } 
    return string; 
} 

Aktualizacja

Zmieniłem kod tak, że ... jest dołączany w StringBuffer, to aby uniknąć niepotrzebnych projekty String niejawnie który jest powolny i rozrzutny.

Uwaga:escapeHtml jest statyczny import z Apache Commons:

import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;

Można go usunąć i kod powinien działać tak samo.

+0

Jak 'StringBuffer' pomaga wydajność tutaj? Nie ma powodu, dla którego 'substring',' indexOf' i 'length' byłyby szybsze w' StringBuffer' niż w 'String'. –

+0

Pozwól mi wyjaśnić, pytający powiedział, że tokenizuje, a następnie ponownie łączy łańcuch. Za każdym razem, gdy dołącza nowy token z powrotem do łańcucha, cały ciąg jest niszczony i odtwarzany. W przypadku długich łańcuchów operacja ta jest znacznie droższa niż użycie 'StringBuffer'. Chociaż zgadzam się, różnica w wydajności jest prawdopodobnie znikoma, biorąc pod uwagę, że 'StringBuffer' jest tworzony i kiedy wracamy, efektywnie tworzymy ciąg co najmniej 3 razy (podłańcuch, dopisywanie kropek, ucieczka [, przycinanie]). – Ali

+1

Problem polega na tym, że w twoim kodzie nic nie dodajesz do 'StringBuffer'. –

0

Spróbuj wyszukać ostatniej występowania przestrzeni, która jest w stanie mniej lub więcej niż 11 i przyciąć ciąg tam, dodając „...”.

0

Twoje wymagania nie są jasne. Jeśli masz problemy z wyrażeniem ich w naturalnym języku, nie jest zaskoczeniem, że będą trudne do przetłumaczenia na język komputerowy, taki jak Java.

"Zachowaj ostatnie słowo" oznacza, że ​​algorytm będzie wiedział, czym jest "słowo", więc musisz najpierw o tym powiedzieć. Podział to sposób na zrobienie tego. Innym jest skaner/parser z gramatyką.

Martwię się, że sprawię, że zadziała, zanim zacznę się zajmować wydajnością.Spraw, aby działało, zmierz, a następnie zobacz, co możesz zrobić z wydajnością. Wszystko inne to spekulacja bez danych.

+0

Wystarczająco fair. Co mam na myśli przez "zachowaj ostatnie słowo" to nie chcę obcinać łańcucha na jakiejkolwiek postaci z wyjątkiem białej przestrzeni? Czy to ma sens? – AMZFR

0

Jak o:

mystring = mystring.replaceAll("^(.{12}.*?)\b.*$", "$1..."); 
+0

Czy możesz wyjaśnić wyrażenie regularne? Czy zachowałoby to ostatnie słowo, czy nie? Twój regex różni się od czeskiego. – AMZFR

+0

Wykonaj pierwsze 12 znaków, a następnie kolejne, aby ukończyć słowo i dodać ... –

+0

Naprawdę zapomniałem dodać coś na końcu wzorca, aby usunąć resztę ciągu znaków. Edytujemy teraz, by naprawić. –

7

Oto prosty, regex opartych rozwiązanie 1-linia:

str.replaceAll("(?<=.{12})\\b.*", "..."); // How easy was that!? :) 

Objaśnienie:

  • (?<=.{12}) jest negatywnym spojrzenie za, który zapewnia, że ​​jest co najmniej 12 znaków po lewej stronie meczu, ale jest organizacją non-przechwytywania (tj zerowej szerokości) mecz
  • \b.* dopasowuje pierwszy granicę słowa (po co najmniej 12 znaków - powyżej) do końca

ta zastępuje się wyrazami „...”

Oto test:

public static void main(String[] args) { 
    String input = "The quick brown fox jumps over the lazy dog."; 
    String trimmed = input.replaceAll("(?<=.{12})\\b.*", "..."); 
    System.out.println(trimmed); 
} 

wyjściowa:

The quick brown... 
+0

Czy możesz wyjaśnić wyrażenie regularne? Podoba mi się to rozwiązanie, chociaż muszę się przekonać, w jaki sposób układa się zgodnie z odpowiedzią Ali poniżej. – AMZFR

+0

@AMZFR nie używaj wyrażenia regularnego, jeśli martwisz się szybkością. Będzie to znacznie wolniejsze niż 'indexOf' +' substring' (10-100 razy wolniejsze). –

+1

Dzięki @Banthar, opierałem się tylko dlatego, że lubię wiedzieć, co dzieje się w kodzie, ale rozwiązanie regex jest dość eleganckie. – AMZFR

4

Spróbuj poniższy kod:

private String trim(String src, int size) { 
    if (src.length() <= size) return src; 
    int pos = src.lastIndexOf(" ", size - 3); 
    if (pos < 0) return src.substring(0, size); 
    return src.substring(0, pos) + "..."; 
} 
+0

To jest ładne i proste. Dzięki! –

0

Używam tego Hack: załóżmy, że przycięte łańcuch musi mieć 120 Długość:

String textToDisplay = textToTrim.substring(0,(textToTrim.length() > 120) ? 120 : textToTrim.length()); 

     if (textToDisplay.lastIndexOf(' ') != textToDisplay.length() &&textToDisplay.length()!=textToTrim().length()) { 

      textToDisplay = textToDisplay + textToTrim.substring(textToDisplay.length(),textToTrim.indexOf(" ", textToDisplay.length()-1))+ " ..."; 
     } 
Powiązane problemy