在Java中,如何截断n个单词后的字符串?

在Java中,如何截断n个单词后的字符串?,java,string,Java,String,是否有一个库具有截断n个单词后的字符串的例程?我在寻找可以改变的东西: truncateAfterWords(3, "hello, this\nis a long sentence"); 进入 我可以自己写,但我认为类似的东西可能已经存在于一些开源字符串操作库中 下面是我期望任何解决方案都能通过的测试用例的完整列表: import java.util.regex.*; public class Test { private static final TestCase[] TEST_

是否有一个库具有截断n个单词后的字符串的例程?我在寻找可以改变的东西:

truncateAfterWords(3, "hello, this\nis a long sentence");
进入

我可以自己写,但我认为类似的东西可能已经存在于一些开源字符串操作库中

下面是我期望任何解决方案都能通过的测试用例的完整列表:

import java.util.regex.*;

public class Test {

    private static final TestCase[] TEST_CASES = new TestCase[]{
        new TestCase(5, null, null),
        new TestCase(5, "", ""),
        new TestCase(5, "single", "single"),
        new TestCase(1, "single", "single"),
        new TestCase(0, "single", ""),
        new TestCase(2, "two words", "two words"),
        new TestCase(1, "two words", "two"),
        new TestCase(0, "two words", ""),
        new TestCase(2, "line\nbreak", "line\nbreak"),
        new TestCase(1, "line\nbreak", "line"),
        new TestCase(2, "multiple  spaces", "multiple  spaces"),
        new TestCase(1, "multiple  spaces", "multiple"),
        new TestCase(3, " starts with space", " starts with space"),
        new TestCase(2, " starts with space", " starts with"),
        new TestCase(10, "A full sentence, with puncutation.", "A full sentence, with puncutation."),
        new TestCase(4, "A full sentence, with puncutation.", "A full sentence, with"),
        new TestCase(50, "Testing a very long number of words in the testcase to see if the solution performs well in such a situation.  Some solutions don't do well with lots of input.", "Testing a very long number of words in the testcase to see if the solution performs well in such a situation.  Some solutions don't do well with lots of input."),
    };

    public static void main(String[] args){
        for (TestCase t: TEST_CASES){
            try {
                String r = truncateAfterWords(t.n, t.s);
                if (!t.equals(r)){
                    System.out.println(t.toString(r));
                }
            } catch (Exception x){
                System.out.println(t.toString(x));
            }       
        }   
    }

    public static String truncateAfterWords(int n, String s) {
        // TODO: implementation
        return null;
    }
}


class TestCase {
    public int n;
    public String s;
    public String e;

    public TestCase(int n, String s, String e){
        this.n=n;
        this.s=s;
        this.e=e;
    }

    public String toString(){
        return "truncateAfterWords(" + n + ", " + toJavaString(s) + ")\n  expected: " + toJavaString(e);
    }

    public String toString(String r){
        return this + "\n  actual:   " + toJavaString(r) + "";
    }

    public String toString(Exception x){
        return this + "\n  exception: " + x.getMessage();
    }    

    public boolean equals(String r){
        if (e == null && r == null) return true;
        if (e == null) return false;
        return e.equals(r);
    }   

    public static final String escape(String s){
        if (s == null) return null;
        s = s.replaceAll("\\\\","\\\\\\\\");
        s = s.replaceAll("\n","\\\\n");
        s = s.replaceAll("\r","\\\\r");
        s = s.replaceAll("\"","\\\\\"");
        return s;
    }

    private static String toJavaString(String s){
        if (s == null) return "null";
        return " \"" + escape(s) + "\"";
    }
}
此网站上有其他语言的解决方案:


尝试在Java中使用正则表达式。仅检索n个单词的正则表达式是:.*?\s{n}

尝试使用以下代码:

String inputStr= "hello, this\nis a long sentence";
Pattern pattern = Pattern.compile("(.*?[\\s]){3}", Pattern.DOTALL); 
Matcher matcher = pattern.matcher(inputStr);
matcher.find(); 
String result = matcher.group(); 
System.out.println(result);
要了解有关软件包的更多信息:


尝试在Java中使用正则表达式。仅检索n个单词的正则表达式是:.*?\s{n}

尝试使用以下代码:

String inputStr= "hello, this\nis a long sentence";
Pattern pattern = Pattern.compile("(.*?[\\s]){3}", Pattern.DOTALL); 
Matcher matcher = pattern.matcher(inputStr);
matcher.find(); 
String result = matcher.group(); 
System.out.println(result);
要了解有关软件包的更多信息:


您可以使用简单的基于正则表达式的解决方案:

private String truncateAfterWords(int n, String str) {
   return str.replaceAll("^((?:\\W*\\w+){" + n + "}).*$", "$1");    
}
现场演示:

更新:根据您的意见解决性能问题: 在处理大量单词时,使用以下方法可提高性能:

private final static Pattern WB_PATTERN = Pattern.compile("(?<=\\w)\\b");

private String truncateAfterWords(int n, String s) {
   if (s == null) return null;
   if (n <= 0) return "";
   Matcher m = WB_PATTERN.matcher(s);
   for (int i=0; i<n && m.find(); i++);
   if (m.hitEnd())
      return s;
   else
      return s.substring(0, m.end());
}

您可以使用简单的基于正则表达式的解决方案:

private String truncateAfterWords(int n, String str) {
   return str.replaceAll("^((?:\\W*\\w+){" + n + "}).*$", "$1");    
}
现场演示:

更新:根据您的意见解决性能问题: 在处理大量单词时,使用以下方法可提高性能:

private final static Pattern WB_PATTERN = Pattern.compile("(?<=\\w)\\b");

private String truncateAfterWords(int n, String s) {
   if (s == null) return null;
   if (n <= 0) return "";
   Matcher m = WB_PATTERN.matcher(s);
   for (int i=0; i<n && m.find(); i++);
   if (m.hitEnd())
      return s;
   else
      return s.substring(0, m.end());
}

我找到了一种使用该类的方法:


我找到了一种使用该类的方法:


下面是一个版本,它使用正则表达式查找循环中的下一组空格,直到有足够的单词为止。类似于BreakIterator解决方案,但使用正则表达式对单词breaks进行迭代

// Any number of white space or the end of the input
private final static Pattern SPACES_PATTERN = Pattern.compile("\\s+|\\z");

private static String truncateAfterWords(int n, String s) {
    if (s == null) return null;
    Matcher matcher = SPACES_PATTERN.matcher(s);
    int matchStartIndex = 0, matchEndIndex = 0, wordsFound = 0;
    // Keep matching until enough words are found, 
    // reached the end of the string, 
    // or no more matches
    while (wordsFound<n && matchEndIndex<s.length() && matcher.find(matchEndIndex)){
        // Keep track of both the start and end of each match
        matchStartIndex = matcher.start();
        matchEndIndex = matchStartIndex + matcher.group().length();
        // Only increment words found when not at the beginning of the string
        if (matchStartIndex != 0) wordsFound++;
    }
    // From the beginning of the string to the start of the final match
    return s.substring(0, matchStartIndex);
}

下面是一个版本,它使用正则表达式查找循环中的下一组空格,直到有足够的单词为止。类似于BreakIterator解决方案,但使用正则表达式对单词breaks进行迭代

// Any number of white space or the end of the input
private final static Pattern SPACES_PATTERN = Pattern.compile("\\s+|\\z");

private static String truncateAfterWords(int n, String s) {
    if (s == null) return null;
    Matcher matcher = SPACES_PATTERN.matcher(s);
    int matchStartIndex = 0, matchEndIndex = 0, wordsFound = 0;
    // Keep matching until enough words are found, 
    // reached the end of the string, 
    // or no more matches
    while (wordsFound<n && matchEndIndex<s.length() && matcher.find(matchEndIndex)){
        // Keep track of both the start and end of each match
        matchStartIndex = matcher.start();
        matchEndIndex = matchStartIndex + matcher.group().length();
        // Only increment words found when not at the beginning of the string
        if (matchStartIndex != 0) wordsFound++;
    }
    // From the beginning of the string to the start of the final match
    return s.substring(0, matchStartIndex);
}


我不认为有这样的功能,看起来很特别。你可以使用split,split-words-at,然后数一数,当它们超过3时,丢弃剩下的。但是没有,我从来没有遇到过像这样的东西。我想过分裂,但它倾向于扔掉你分裂的东西。我想保留字符串中的空格和新行。与其使用string.spilt,不如接下来使用Scanner类。当水溅出来时。阅读更多有关此内容的信息我下面的答案将与您编辑的输入字符串很好配合您好,这也是一个很长的句子。我不认为有这样的功能,看起来很特别。您可以使用拆分,拆分单词,然后计数,当它们超过3时,丢弃其余的。但是没有,我从来没有遇到过像这样的东西。我想过分裂,但它倾向于扔掉你分裂的东西。我想保留字符串中的空格和新行。与其使用string.spilt,不如接下来使用Scanner类。当水溅出来时。请阅读更多信息。下面的我的答案将适用于您编辑的输入字符串你好,这\n也是一个很长的句子。好主意,但正则表达式不适用于我。这不会产生输出:Matcher m=Pattern.compile.*?\\b{3}.matcherhello,这是一个长句;m、 发现;System.out.printlnm.group0;使用这个代码@StephenOstermiller:它起作用了。。。。String inputStr=hello,这是一个很长的句子;Pattern=Pattern.compile.*?[\\s\\n]{3},Pattern.DOTALL;Matcher Matcher=pattern.matcherinputStr;matcher.find;字符串结果=matcher.group;系统输出打印结果;我编写了一整套测试用例,并将其添加到问题中。此解决方案失败了其中的几个,并且在长输入时进入无限循环。很抱歉响应延迟。将正则表达式用作。*[\\s\\n]{1,}。前面的模型是一个如何解决问题的示例,但不是一个成熟的正则表达式。谢谢这是一个输入错误。请使用这个正则表达式。*?[\\s\\n]{1,}好主意,但这个正则表达式对我不起作用。这不会产生输出:Matcher m=Pattern.compile.*?\\b{3}.matcherhello,这是一个长句;m、 发现;System.out.printlnm.group0;使用这个代码@StephenOstermiller:它起作用了。。。。String inputStr=hello,这是一个很长的句子;Pattern=Pattern.compile.*?[\\s\\n]{3},Pattern.DOTALL;Matcher Matcher=pattern.matcherinputStr;matcher.find;字符串结果=matcher.group;系统输出打印结果;我编写了一整套测试用例,并将其添加到问题中。此解决方案失败了其中的几个,并且在长输入时进入无限循环。很抱歉响应延迟。将正则表达式用作。*[\\s\\n]{1,}。前面的模型是一个如何解决问题的示例,但不是一个成熟的正则表达式。谢谢这是一个输入错误。请使用此正则表达式。*?[\\s\\n]{1,}不幸的是,此解决方案的性能有问题。下面是一个似乎进入无限循环的测试用例:truncateAfterWords50,将测试作为测试更多测试的测试。@StephenStermiller:立即检查我的更新。这不编译-未定义启动。我原以为你可能是指萨特先生,但如果是我的话,那就抛出了一个例外
nates,因为没有找到更多的匹配项。我得到了一个类似于您的第二个解决方案的版本,并将其作为解决方案发布在这里:哦,对不起,我已经很晚了,实际上它应该是m.end。进行了另一次编辑,请立即检查。不幸的是,此解决方案的性能有问题。下面是一个似乎进入无限循环的测试用例:truncateAfterWords50,将测试作为测试更多测试的测试。@StephenStermiller:立即检查我的更新。这不编译-未定义启动。我想你可能是指m.sart,但当它终止时会抛出一个异常,因为找不到更多匹配项。我得到了一个类似于你的第二个解决方案的版本,并将其作为解决方案发布在这里:哦,对不起,我已经很晚了,实际上它应该是m.end。已进行另一次编辑,请立即检查。