我可以用番石榴将文本包装到给定宽度吗?

问题描述

| 我希望能够将长字符串包装成固定长度。在番石榴有办法吗? Apache Commons / Lang具有完全符合我需要的方法does0ѭ。番石榴是否有简单的方法来实现这一目标? 我知道我可以用ѭ1进行硬包装,但我想进行软包装。 更新:现在有一个悬赏这个问题。 显然,该功能在Guava中是不可用的,因此赏金会转到使用Guava中最简单(或最完整)和类似Guava的答案。除了Guava之外,没有库。     

解决方法

我们(Guava)强烈建议您使用ICU4J的
BreakIterator
类来处理在用户文本中查找断点的机制。     ,这是我自己的答案,以寻求灵感:
public final class TextWrapper {

    enum Strategy implements WrapStrategy {
        HARD {

            @Override
            public String wrap(final Iterable<String> words,final int width) {
                return Joiner.on(\'\\n\')
                             .join(Splitter
                                    .fixedLength(width)
                                    .split(
                                        Joiner.on(\' \').join(words)));
            }
        },SOFT {
            @Override
            public String wrap(final Iterable<String> words,final int width) {
                final StringBuilder sb = new StringBuilder();
                int lineLength = 0;
                final Iterator<String> iterator = words.iterator();
                if (iterator.hasNext()) {
                    sb.append(iterator.next());
                    lineLength=sb.length();
                    while (iterator.hasNext()) {
                        final String word = iterator.next();
                        if(word.length()+1+lineLength>width) {
                            sb.append(\'\\n\');
                            lineLength=0;
                        } else {
                            lineLength++;
                            sb.append(\' \');
                        }
                        sb.append(word);
                        lineLength+=word.length();
                    }
                }
                return sb.toString();
            }
        }
    }

    interface WrapStrategy {
        String wrap(Iterable<String> words,int width);
    }

    public static TextWrapper forWidth(final int i) {
        return new TextWrapper(Strategy.SOFT,CharMatcher.WHITESPACE,i);
    }

    private final WrapStrategy  strategy;

    private final CharMatcher   delimiter;

    private final int           width;

    TextWrapper(final WrapStrategy strategy,final CharMatcher delimiter,final int width) {
        this.strategy = strategy;
        this.delimiter = delimiter;
        this.width = width;
    }

    public TextWrapper hard(){
        return new TextWrapper(Strategy.HARD,this.delimiter,this.width);
    }
    public TextWrapper respectExistingBreaks() {
        return new TextWrapper(
            this.strategy,CharMatcher.anyOf(\" \\t\"),this.width);
    }

    public String wrap(final String text) {
        return this.strategy.wrap(
            Splitter.on(this.delimiter).split(text),this.width);
    }

}
用法示例1 :(以80个字符进行硬包装)
TextWrapper.forWidth(80)
        .hard()
        .wrap(\"Lorem ipsum dolor sit amet,consectetur adipiscing elit.\\n\" +
            \"Maecenas porttitor risus vitae urna hendrerit ac condimentum \" +
            \"odio tincidunt.\\nDonec porttitor felis quis nulla aliquet \" +
            \"lobortis. Suspendisse mattis sapien ut metus congue tincidunt. \" +
            \"Quisque gravida,augue sed congue tempor,tortor augue rhoncus \" +
            \"leo,eget luctus nisl risus id erat. Nunc tempor pretium gravida.\");
输出:
Lorem ipsum dolor sit amet,consectetur adipiscing elit. Maecenas porttitor risu
s vitae urna hendrerit ac condimentum odio tincidunt. Donec porttitor felis quis
 nulla aliquet lobortis. Suspendisse mattis sapien ut metus congue tincidunt. Qu
isque gravida,tortor augue rhoncus leo,eget luctus ni
sl risus id erat. Nunc tempor pretium gravida.
用法示例2 :(在60个字符或之前,自动换行,保留现有的换行符)
TextWrapper.forWidth(60)
    .respectExistingBreaks()
    .wrap(\"Lorem ipsum dolor sit amet,consectetur adipiscing elit.\\n\" +
    \"Maecenas porttitor risus vitae urna hendrerit ac condimentum \" +
    \"odio tincidunt.\\nDonec porttitor felis quis nulla aliquet \" +
    \"lobortis. Suspendisse mattis sapien ut metus congue tincidunt. \" +
    \"Quisque gravida,tortor augue rhoncus \" +
    \"leo,consectetur adipiscing
elit.
Maecenas porttitor risus vitae urna hendrerit ac
condimentum odio tincidunt.
Donec porttitor felis quis nulla
aliquet lobortis. Suspendisse mattis sapien ut metus congue
tincidunt. Quisque gravida,tortor
augue rhoncus leo,eget luctus nisl risus id erat. Nunc
tempor pretium gravida.
    ,为什么不使用番石榴来使用番石榴做更简单的事情? 实际上,
Splitter
类允许您使用
fixedLength()
方法进行硬包装,否则可以根据分隔符
char
String
拆分字符串。如果要使用番石榴,可以依靠
Splitter.on(\' \').split(string)
,但还必须将结果结合起来,具体取决于maxLength值,以\'\\ n \'替换\'\'。 无需使用番石榴,您也可以做自己想做的事。几行代码,没有依赖性。基本上,您可以使用commons-lang方法来简化它。这是我的包装方法:
public static String wrap(String str,int wrapLength) {
    int offset = 0;
    StringBuilder resultBuilder = new StringBuilder();

    while ((str.length() - offset) > wrapLength) {
        if (str.charAt(offset) == \' \') {
            offset++;
            continue;
        }

        int spaceToWrapAt = str.lastIndexOf(\' \',wrapLength + offset);
        // if the next string with length maxLength doesn\'t contain \' \'
        if (spaceToWrapAt < offset) {
            spaceToWrapAt = str.indexOf(\' \',wrapLength + offset);
            // if no more \' \'
            if (spaceToWrapAt < 0) {
                break;
            }
        }

        resultBuilder.append(str.substring(offset,spaceToWrapAt));
        resultBuilder.append(\"\\n\");
        offset = spaceToWrapAt + 1;
    }

    resultBuilder.append(str.substring(offset));
    return resultBuilder.toString();
}
是的,它与原始的commons-lang方法非常相似,但是我猜它更短,更容易并且根据您的需求。也许,此解决方案也比您的解决方案更有效,不是吗? 我已经用您的文字对其进行了测试,将我的结果与commons-lang结果进行了比较。似乎有效:
public static void main(String[] args) {

    String string = \"Lorem ipsum dolor sit amet,consectetur adipiscing elit.\\n\"
            + \"Maecenas porttitor risus vitae urna hendrerit ac condimentum \"
            + \"odio tincidunt.\\nDonec porttitor felis quis nulla aliquet \"
            + \"lobortis. Suspendisse mattis sapien ut metus congue tincidunt. \"
            + \"Quisque gravida,tortor augue rhoncus \"
            + \"leo,eget luctus nisl risus id erat. Nunc tempor pretium gravida.\";

    for (int maxLength = 2; maxLength < string.length(); maxLength++) {
        String expectedResult = WordUtils.wrap(string,maxLength);
        String actualResult = wrap(string,maxLength);

        if (!expectedResult.equals(actualResult)) {
            System.out.println(\"expectedResult: \\n\" + expectedResult);
            System.out.println(\"\\nactualResult: \\n\" + actualResult);
            throw new RuntimeException(
                    \"actualResult is not the same as expectedResult (maxLength:\"
                            + maxLength + \")\");
        }
    }
}
因此,问题是:您真的要使用番石榴来做到这一点吗?这种选择有什么好处?     ,我这样做很有趣,只是为了尽可能多地食用番石榴。尽管javanna的答案更好,
import java.util.Iterator;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;


public class SoftSplit {

    public static String softSplit(String string,int length) {
        //break up into words
        Iterable<String> words = Splitter.on(\' \').split(string);

        //an iterator that will return the words with appropriate
        //white space added
        final SoftSplitIterator softIter = new SoftSplitIterator(words,length);
        return Joiner.on(\"\").join(new Iterable<String>() {
            @Override
            public Iterator<String> iterator() {
                return softIter;
            }
        });
    }

    static class SoftSplitIterator implements Iterator<String> {
        private final int maxLength;
        private final PeekingIterator<String> words;
        private int currentLineLength;

        SoftSplitIterator(Iterable<String> words,int maxLength) {
            this.words = Iterators.peekingIterator(words.iterator());
            this.maxLength = maxLength;
        }

        @Override
        public boolean hasNext() {
            return words.hasNext();
        }

        @Override
        public String next() {
            String current = words.next();

            //strip leading spaces at the start of a line
            if(current.length() == 0 && currentLineLength == 0) {
                return \"\";
            }
            //nothing left after us
            if(!words.hasNext()) {
                return current;
            }
            String next = words.peek();

            if(currentLineLength + current.length() + next.length() < maxLength) {
                //this word and the next one won\'t put us over limit
                currentLineLength += current.length();
                return current + \" \";
            } else {
                //the next word will put us over the limit 
                //add a line break
                currentLineLength = 0;
                return current + \"\\n\";
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    public static void main(String[] args) {
        String text = 
            \"Lorem ipsum dolor sit amet,consectetur adipiscing elit. \" +
            \"Maecenas porttitor risus vitae urna hendrerit ac condimentum \" +
            \"odio tincidunt. Donec porttitor felis quis nulla aliquet \" +
            \"lobortis. Suspendisse mattis sapien ut metus congue tincidunt. \" +
            \"Quisque gravida,eget luctus nisl risus id erat. Nunc tempor pretium gravida.\";
        System.out.println(softSplit(text,60));
    }
}