2011-10-12 35 views
8

我需要在Java修剪字符串,因此:修剪字符串,同時保留完整的單詞

敏捷的棕色狐狸跳過LAZ狗。

上面變得

敏捷的棕色......

在這個例子中,我修剪到12個字符。如果我只是用子我會得到:

快速BR ...

我已經有這樣子使用的方法,但我想知道什麼是最快的(最有效)的方式來做到這一點,因爲一個頁面可能有很多修剪操作。

我能想到的唯一方法是將字符串拆分爲空格並將其放回到一起,直到其長度超過給定的長度。有沒有其他方法?也許是一種更有效的方法,我可以使用相同的方法在保留最後一個單詞(如上面的示例中所示)的情況下進行「軟」修剪以及幾乎是子字符串的硬修剪。

感謝,

回答

11

下面是我用來修剪我的webapps中的長字符串的方法。 「軟」boolean正如你所說,如果設置爲true將保留最後一個字。 這是最簡潔的做法,我可以想出使用StringBuffer,比重新創建一個不可變的字符串更有效。

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; 
} 

更新

我已經改變了代碼,以便在... StringBuffer的追加,這是爲了防止不必要的String創作含蓄緩慢且浪費。

注:escapeHtml是來自Apache的公共靜態導入:

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

你可以刪除它,代碼應該工作一樣。

+0

如何'StringBuffer'幫助這裏的表現?沒有任何理由說明爲什麼'StringBuffer'上的'substring','indexOf'和'length'會比'String'快。 –

+0

讓我澄清一下,提問者說,這是標記,然後把繩子放在一起。每次他在字符串上追加新的令牌時,整個字符串都會被銷燬並重新創建。對於長字符串,這個操作比使用'StringBuffer'要昂貴得多。雖然我同意,考慮到StringBuffer被創建,並且當我們返回時,我們有效地創建了一個字符串至少3次(substring,append dots,escape [,trim]),性能差異可能忽略不計。 – Ali

+1

問題是,在你的代碼中,你不會追加任何東西到'StringBuffer'。 –

0

嘗試搜索是在一個位置小於或大於11的空間的最後一次出現和修剪字符串有加入「...」。

0

您的要求不明確。如果用自然語言表達它們時遇到困難,那麼它們很難翻譯成像Java這樣的計算機語言也就不足爲奇了。

「保留最後一個詞」意味着算法會知道「單詞」是什麼,因此您必須首先告訴它。拆分是一種方法。掃描儀/語法分​​析器是另一種語法。

在擔心效率問題之前,我會擔心它的工作原理。讓它工作,衡量它,然後看看你能做些什麼關於表現。其他一切都是沒有數據的猜測。

+0

夠公平的。我所說的「保留最後一句話」的意思是我不想在任何字符上截斷除空格之外的字符串?那有意義嗎? – AMZFR

0

如何:

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

你能解釋一下正則表達式嗎?這會保留最後一個字嗎?你的正則表達式與波希米亞的不同。 – AMZFR

+0

取出前12個字符,然後在最小值之後完成該單詞,然後添加... –

+0

我實際上忘了在模式的末尾添加某些內容以刪除字符串的其餘部分。現在編輯修復。 –

7

下面是一個簡單的,基於正則表達式-,1線的解決方案:

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

說明:

  • (?<=.{12})的背後是負外觀,它聲稱在比賽的左邊至少有12個字符,但它是一個非捕獲(即零寬度)匹配
  • \b.*的第一個字邊界一致(至少12個字符之後 - 以上)到最後

這被替換爲「...」

這是一個測試:

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); 
} 

輸出:

The quick brown... 
+0

你能解釋一下正則表達式嗎?我喜歡這個解決方案,但我必須看看它如何在下面的阿里答案中加快速度。 – AMZFR

+0

@AMZFR不使用正則表達式,如果你擔心速度。它會比'indexOf' +'substring'慢(慢10-100倍)。 –

+1

謝謝@Banthar,我只是因爲我喜歡知道代碼中發生了什麼,仍然是正則表達式解決方案非常優雅。 – AMZFR

4

請嘗試以下代碼:

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

這很好,很簡單。謝謝! –

0

我使用這個技巧:假設修整字符串的長度必須爲120:

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))+ " ..."; 
     }