【问题标题】:Trim String in Java while preserve full word在Java中修剪字符串,同时保留完整的单词
【发布时间】:2011-12-05 23:50:09
【问题描述】:

我需要在 java 中修剪一个字符串,以便:

敏捷的棕色狐狸跳过懒惰的狗。

变成

快速的棕色...

在上面的示例中,我将修剪到 12 个字符。如果我只使用子字符串,我会得到:

快速的...

我已经有了使用子字符串的方法,但我想知道最快(最有效)的方法是什么,因为一个页面可能有很多修剪操作。

我能想到的唯一方法是将字符串拆分为空格并将其重新组合在一起,直到其长度超过给定长度。还有其他方法吗?也许是一种更有效的方法,我可以使用相同的方法进行“软”修剪,保留最后一个单词(如上面的示例所示)和一个几乎是子字符串的硬修剪。

谢谢,

【问题讨论】:

    标签: java string substring trim


    【解决方案1】:

    以下是我用来在我的 web 应用程序中修剪长字符串的方法。 正如你所说的“软”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 commons 静态导入的:

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

    您可以删除它,代码应该可以正常工作。

    【讨论】:

    • StringBuffer 如何帮助提高性能? substringindexOflength 没有理由在 StringBuffer 上比在 String 上更快。
    • 让我澄清一下,提问者说它正在标记化,然后将字符串重新组合在一起。每次他在字符串上附加一个新标记时,整个字符串都会被销毁并重新创建。对于长字符串,此操作比使用StringBuffer 要昂贵得多。虽然我同意,但考虑到 StringBuffer 已创建,并且当我们返回时,我们有效地创建了至少 3 次字符串(子字符串、附加点、转义 [、修剪]),性能差异可能可以忽略不计。
    • 问题是在你的代码中你没有向StringBuffer附加任何东西。
    • 谢谢,你说得对,至少应该在 StringBuffer 中附加点。我会在测试确保没有错误后更新我的答案。
    • @TranDinhThoai escapeHtml 是静态导入。 import static org.apache.commons.lang.StringEscapeUtils.escapeHtml; 你可以删除它,它的工作原理是一样的。我在那里有它,因为我在 web 应用程序中使用它并且需要转义 html 实体。
    【解决方案2】:

    这是一个简单的、基于正则表达式的单行解决方案:

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

    解释:

    • (?&lt;=.{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...
    

    如果性能是一个问题,预编译正则表达式,只需编译一次即可将速度提高大约 5 倍 (YMMV):

    static Pattern pattern = Pattern.compile("(?<=.{12})\\b.*");
    

    并重复使用它:

    String trimmed = pattern.matcher(input).replaceAll("...");
    

    【讨论】:

    • 你能解释一下正则表达式吗?我喜欢这个解决方案,但我必须看看它如何在下面阿里的回答中提高速度。
    • @AMZFR 如果您担心速度,请不要使用正则表达式。它会比 indexOf + substring 慢得多(慢 10-100 倍)。
    • 感谢@Banthar,我之所以反对只是因为我喜欢知道代码中发生了什么,但正则表达式解决方案仍然非常优雅。
    • 一个不错的答案。当性能不是主要因素时的更简单的解决方案
    • @SaifAsif 如果需要性能,我添加了一个更快的版本,虽然原始版本只会在几微秒内执行,所以除非你需要它运行得非常快,否则我会喜欢一个 -衬里静态编译正则表达式。
    【解决方案3】:

    请尝试以下代码:

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

    【讨论】:

    • 这很好很简单。谢谢!
    【解决方案4】:

    尝试搜索最后一次出现的位置小于或大于 11 的空格,并通过添加“...”修剪那里的字符串。

    【讨论】:

      【解决方案5】:

      您的要求不明确。如果您在用自然语言表达它们时遇到困难,那么难于将它们翻译成像 Java 这样的计算机语言也就不足为奇了。

      “保留最后一个单词”意味着算法会知道“单词”是什么,所以你必须先告诉它。拆分是一种方法。具有语法的扫描器/解析器是另一个。

      在我关心效率之前,我会担心让它发挥作用。让它发挥作用,衡量它,然后看看你能对性能做些什么。其他一切都是没有数据的猜测。

      【讨论】:

      • 很公平。 “保留最后一个单词”的意思是我不想截断除空格以外的任何字符上的字符串?这有意义吗?
      【解决方案6】:

      怎么样:

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

      【讨论】:

      • 你能解释一下正则表达式吗?这会保留最后一句话吗?您的正则表达式与 Bohemian 的不同。
      • 取前 12 个字符,之后的最少字符来补全单词,然后添加 ...
      • 我实际上忘记在模式的末尾添加一些东西来删除字符串的其余部分。立即编辑以修复。
      【解决方案7】:

      我使用这个技巧:假设修剪后的字符串必须有 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))+ " ...";
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-22
        • 1970-01-01
        • 2019-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多