Java - 将文本划分为n个相等的行

时间:2014-07-20 19:30:52

标签: java algorithm word-wrap

我们说我有这个字符串

String myText="I think that stackoverflow is a very great website";

如果我想将它分成两行,我会有类似

的东西
I think that stackoverflow

is a very great website.

所以String现在就是("我认为stackoverflow \ n是一个非常棒的网站"

如果我希望它分成3行,那就像

I think that

stackoverflow is a

very great website

我尝试过的只是划分文字,每一行都有总字数/ n(n是我要分割文字的行数)。

但这是一件坏事,我会得到像

这样的结果
String myText="I me him is veryverylong wordvery longestwordever thisisevenlonger"

结果将是(如果我想将其划分为2行),如

"i you me is\nveryverylong wordvery longestwordever thisisevenlonger"

你们有什么建议我试试?

我尝试过常见的apache算法 http://pastebin.com/68zycavf

但我的输出文本将是每个单词用\ n分隔。如果我使用wrap(text,2)..

3 个答案:

答案 0 :(得分:4)

正如Eran在他的回答中指出的那样,你想要在大约行长除以所需行数的情况下进行分割,但必须调整为在单词中间的那个。

我认为他的解决方案并不总是能给出最好的解决方案,因为有时最好在单词之前进行拆分而不是在他正在进行之后进行拆分。

分而治之的方法将是一种递归算法,大致如下:

N为所需的行数,LENGTH为输入字符串中的字符数(首先标准化为单个空格)。

如果LENGTH/N处的字符是空格,请在那里进行第一次剪切,然后递归调用将余数拆分为N-1行,否则在包含此字符的单词的每一端找到空格并通过递归调用再次在两个点进行试用,完成两个切割。以某种方式对结果进行评分并选择更好。

我已经实现了如下。对于评分功能,我选择最小化分割中的最大线条长度。更复杂的评分函数可能会改善结果,但这似乎适用于所有情况。

public class WordWrapper {

    public String wrapWords(String input, int lines) {
        return splitWords(input.replaceAll("\\s+", " "), lines);
    }

    private String splitWords(String input, int lines) {
        if (lines <= 1) {
            return input;
        }

        int splitPointHigh = findSplit(input, lines, 1);
        String splitHigh = input.substring(0, splitPointHigh).trim() + "\n" + splitWords(input.substring(splitPointHigh).trim(), lines - 1);

        int splitPointLow = findSplit(input, lines, -1);
        String splitLow = input.substring(0, splitPointLow).trim() + "\n" + splitWords(input.substring(splitPointLow).trim(), lines - 1);

        if (maxLineLength(splitLow) < maxLineLength(splitHigh))
            return splitLow;
        else return splitHigh;
    }

    private int maxLineLength(String split) {
        return maxLength(split.split("\n"));
    }

    private int maxLength(String[] lines) {
        int maxLength = 0;
        for (String line: lines) {
            if (line.length() > maxLength)
                maxLength = line.length();
        }
        return maxLength;
    }

    private int findSplit(String input, int lines, int dir) {
        int result = input.length() / lines;
        while (input.charAt(result) != ' ')
            result+= dir;
        return result;
    }
}

我实际上并没有特别关注在空间上简单分割着陆的幸运情况的特殊情况,并且为此添加特殊处理可能会使它更快一些。在这种情况下,此代码将生成两个相同的“试用拆分”和“选择一个”。

当然,您可能希望将所有这些方法设置为静态,并且递归可能会为大输入和大行数提供堆栈溢出。

我没有声称这是最好的算法,但似乎有效。

答案 1 :(得分:2)

您可以根据字符数除以n进行拆分。 然后,对于每一行,你应该添加最后一个单词的结尾(这是下一行的开头,如果当前行没有以空格结尾而下一行不以一个空格开头)空间),所以没有任何单词在中间分开。

所以如果你有:

  

我,他是非常长的一句话,非常长,而且还有更长的时间

你想把它分成两行,你得到:

  

我是他,非常非常永远   最长的时间,这个更长的

在这种情况下,第二行已经以空格开头,所以我们知道中间没有任何单词被拆分,我们就完成了。

如果将它拆分为三行,首先得到:

  

我是他,非常非常   ng wordvery longestwor
  dever thisisevenlonger

这里有些单词是分开的,所以你移动&#34; ng&#34;到第一行,然后移动&#34; dever&#34;到第二行。

  

我是他非常长的   wordvery longestwordever
  thisisevenlonger

答案 2 :(得分:1)

这是我使用split()函数的解决方案。

public class Textcut {

public static void main(String arg[]) {

    String myText="I think that stackoverflow is a very great website";

    int n = 2;

    String[] textSplit = myText.split(" ");

    int wordNumber = textSplit.length;

    int cutIndex = wordNumber/n;

    int i = cutIndex;
    int j = 0;

    while(i <= wordNumber) {
        for(; j < i; j++) {
            System.out.print(textSplit[j] + " ");
        }

        System.out.println("\n");

        i = i+cutIndex;
    }

}

}