I am trying to align text to the left where each line has an input of a maximum number of characters, if the characters of the word exceed the total count, I want it to print on the same line and NOT get split across lines.
Input: `String[] paragraphs = FileUtil.readFile("C:\Users\Desktop\test_pratchett.txt"); String sampleText = Arrays.toString(paragraphs);
System.out.println(util.format(sampleText));`
Main Code:
private int maxChars;
private String alignment;
private int charsAdded = 0;
public StringAlignUtils(String alignmentType ,int maxChars) {
this.alignment = alignmentType;
if (maxChars < 0) {
throw new IllegalArgumentException("maxChars must be positive.");
}
this.maxChars = maxChars;
}
public StringBuffer format(Object input, StringBuffer where, FieldPosition ignore) {
String s = input.toString();
List<String> strings = splitInputString(s);
ListIterator<String> listItr = strings.listIterator();
while (listItr.hasNext())
{
String wanted = listItr.next();
// System.out.println("Wanted 1: " wanted);
//Get the spaces in the right place.
switch (alignment)
{
case "L":
//System.out.println("Where 2: " where);
//System.out.println("Wanted 2: " wanted);
where.append(wanted);
//System.out.println("Wanted 3: " wanted);
//System.out.println("Where 3: " where);
//pad(where, maxChars - wanted.length());
break;
}
where.append("\n");
}
return where;
}
protected final void pad(StringBuffer to, int howMany)
{
for (int i = 0; i <howMany; i )
to.append(' ');
}
String format(String s) {
return format(s, new StringBuffer(), null).toString();
}
public Object parseObject(String source, ParsePosition pos) {
return source;
}
private List<String> splitInputString(String str) {
System.out.println("Str: " str);
List<String> list = new ArrayList<String>();
ArrayList<String> tempList = new ArrayList<String>();
ArrayList<String> addWordsList = new ArrayList<String> ();
if (str == null)
return list;
/*
* System.out.println("SplitInputString: " str); // String split[] =
* str.split(" ?(?<!\\G)((?<=[^\\p{Punct}])(?=\\p{Punct})|\\b) ?"); String
* split[] = str.split(" "); tempList.addAll(Arrays.asList(split));
* System.out.println("Temp List: " tempList);
*
* for(int i=0; i< tempList.size(); i ) { String word = tempList.get(i); int
* wordLength = word.length(); charsAdded = charsAdded wordLength;
* if(charsAdded <maxChars) { addWordsList.add(word);
*
* } System.out.println("AddWordsList: " addWordsList);
*
* }
*/
for (int i = 0; i < str.length(); i = maxChars) {
int endindex = Math.min(i maxChars, str.length());
String tempString = str.substring(i, endindex).trim();
list.add(tempString); //trim removes leading spaces
System.out.println("List: " list);
}
return list;
My Output: (If max chars is 80)
- Many things went on at the Unseen University and, regrettably teaching had to be
- one of them. The faculty had long ago confronted this fact and had perfected va
- rious devices for avoiding it.
Expected output:
- Many things went on at the Unseen University and, regrettably teaching had to be
- one of them. The faculty had long ago confronted this fact and had perfected various
- devices for avoiding it.
CodePudding user response:
One of the things you want to avoid is processing the lines more than once. That means reading them in, converting to a long string or buffer, and the formatting based on desired length. This is inefficient. I recommend reading them in a character at a time (since it is buffered input, this is not expensive) and building the lines to the required length.
This works as follows:
- Using try with-resources, open the file for reading.
- read in a character.
- if it is a new line (
\n
), replace with a space. - if it is a return, (
\r
), ignore it and continue to next character
- if it is a new line (
- if the
StringBuilder
is of required length and the current character is a blank, trim white space, print it, and reset theStringBuilder
. - then append the current character to the buffer.
- continue until no more characters in the file
- then print current
StringBuilder
if it contains characters.
String inputFile = "...your input file...";
try (BufferedReader br = new BufferedReader(new FileReader(
inputFile))) {
int lineSize = 80;
StringBuilder sb = new StringBuilder();
int ch;
int lineNo = 1;
while ((ch = br.read()) != -1) {
if (ch == '\n') {
ch = ' ';
}
if (ch == '\r') {
continue;
}
if (sb.length() >= lineSize && ch == ' ') {
System.out.printf("-. %s%n", lineNo , sb.toString().trim());
sb.setLength(0);
}
sb.append((char) ch);
}
String last = sb.toString();
if (!last.isBlank()) {
System.out.printf("-. %s%n", lineNo, sb.toString().trim());
}
} catch (IOException ie) {
ie.printStackTrace();
}
Give a file with the following lines.
Many things went on at the
Unseen University and, regrettably
teaching had to be one of them. The
faculty had long ago confronted this
fact and had perfected various
devices for avoiding it.
Here is what is printed
1. Many things went on at the Unseen University and, regrettably teaching had to be
2. one of them. The faculty had long ago confronted this fact and had perfected various
3. devices for avoiding it.
CodePudding user response:
It can be done in one line:
List<String> lines = Pattern.compile("\\S(.{79}\\S*|.*)").matcher(s).results()
.map(MatchResult::group).collect(toList());
See live demo.
How this works:
The regular expression \S(.{79}\S*|.*)
is an alternation (|
mean OR
in regex) that matches a non-whitespace (\S
) then either:
- 79 characters, any non-space characters after that point, or
- the remaining input
Spaces are trimmed from the ends of lines extracted.
All non-whitespace count as words, so "long" lines retain their periods if the 80-char mark occurs on the last word of a sentence.
Alternations are made left to right, so option 2 is only matched if option 1 can't be matched.
The results()
method of Matcher
streams all the match results, which are then converted to strings via Matcher#group
and finally collected into a List
.