Java text wrap issue, caused by input width - java

I am trying to wrap text based on a width of 10 characters. After looking at other questions, I have the following:
StringBuilder sb = new StringBuilder(s);
int i = 0;
while (i + 10 < sb.length() && (i = sb.lastIndexOf(" ", i + 10)) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());
This works until a word in my string is longer than the specified width. When this occurs, the rest of the string is printed on line line instead of still following the line width rule. Any ideas? I tried an "else" with a separate condition but I couldn't get it to work. Apologies if this seems rather trivial.

There is a ready solution for that.
https://mvnrepository.com/artifact/org.apache.commons/commons-text
WordUtils.wrap(s, 10);

When you have a word that's longer than 9 characters, sb.lastIndexOf("", i + 10) gives you -1. That's because index of the next space is greater than i + 10 and sb.lastIndexOf("", i + 10) starts from index i + 10 and looks for a space until the beginning of the string and cannot find any spaces (they have all been replaced with new lines). You can fix your code like below to make it work.
StringBuilder sb = new StringBuilder(s);
int i = 0;
while (i + 10 < sb.length() &&
(i = Math.max( sb.indexOf(" ", i), sb.lastIndexOf(" ", i + 10))) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());

You could convert your string to an array of characters and visit them and ask if the variable iterator % 10 (in this case in 9 because i = 0), if so You enter a line break plus the character, all this will be added to a StringBuilder ... might be a solution
char[] a="ABCDFGHIKLMNOPQRSTUVWXYZ".toCharArray(); //String convert to charArray
StringBuilder sb = new StringBuilder(a.length);
for (int i = 0; i < a.length; i++) {
if(i%9==0) sb.append("\n" + a[i]); //
sb.append(a[i]);
}
System.out.println(sb.toString());

Related

Trying to get my string to rotate left. What am I doing wrong here?

I am new to Java and am trying to get my code to work and am a bit stuck. I want to have a string rotate a random amount to the left, but I keep running into errors. Here is what I have currently:
String rotateLeft(String input, int i) {
if (input == null) {
return null;
}
if (input.length() == 0) {
return input;
}
int r = i % input.length();
String one = input.substring(input.length() - r);
String two = input.substring(0, input.length() - r);
return one + two;
}
If I could get some help fixing it that would be amazing!
Edit: I changed my code around a bit and this is now what it looks like:
// String Rotate Left
String rotateLeft(String s, int rotate) {
// Sanity checks
char[] rotatedString = new char[s.length()];
for (int i = 0; i < s.length(); i++) {
int newPosition = (i + rotate) % s.length();
assert newPosition >= 0 && newPosition < s.length() : "Bad index " + newPosition;
rotatedString[newPosition] = s.charAt(i);
}
return new String(rotatedString);
}
System.out.println(rotateLeft("CS125", 1));
Instead of it printing out S125C, it prints out 5CS12. How would I change it to print out what I want?
To carry out a rotate to the left on a string, one way to do it is indeed with a concatenation of two sub-strings from the supplied input string basically just like you are using but you've over complicated it:
String leftRotatedString = input.substring(numberOfCharsToRotate)
+ input.substring(0, numberOfCharsToRotate);
I can't for the life of me however see how there is anything in your code that is random. If you want to rotate by a random number of string characters then perhaps utilize the Random class along with its nextInt() method, for example:
// The input string:
String input = "MississippiRiver";
// Generate a random 'index' value of the input string:
int rnd = new Random().nextInt(input.length() - 1) + 1;
// Carry out the rotation:
String leftRotation = input.substring(rnd) + input.substring(0, rnd);
// Display the random rotation value (the number of characters to rotate left by):
System.out.println("Random Number Of Characters To Rotate By: --> " + rnd);
// Display the rotated result string:
System.out.println("Result: --> " + leftRotation);
EDIT: Based on your posted Edit update:
You would do a right rotation instead, for example:
System.out.println(s.substring(s.length() - 2)
+ s.substring(0, s.length() - 2));
The output will be:
5CS12

Remove every 8th char from a string

I have a string, which I want to iterate through and remove every 8th char. I have been trying with an modulo operation which check if i % 8 == 0. However, since I remove every 8th char the length of the string decreases, and I am therefore unable to perform that operation.
StringBuilder str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
for (int i = 0; i < str.length(); i++) {
// Every 8th element should be discarded
if (i > 7 && i % 8 == 0) {
str.deleteCharAt(i);
}
}
System.out.println(str + " " + str.length());
The length of the string is in the beginning 64, and after the for loop 57, which should be 56.
The main problem with your code is that you don't adjust i when removing characters.
Let's visualize that. You want to remove the following marked characters ("every 8th element"):
1100110001011011000000000000000000000000000000000000000000000000
^ ^ ^ ^ ^ ^ ^ ^
Now we're at i = 7 and remove that character, but because you don't adjust i accordingly the markers keep the same:
110011001011011000000000000000000000000000000000000000000000000
^ ^ ^ ^ ^ ^ ^ ^
Let's do that for 1 = 15 to i = 55:
11001100101101100000000000000000000000000000000000000000000000 //i = 15
1100110010110110000000000000000000000000000000000000000000000 //i = 23
110011001011011000000000000000000000000000000000000000000000 //i = 31
11001100101101100000000000000000000000000000000000000000000 //i = 39
1100110010110110000000000000000000000000000000000000000000 //i = 47
110011001011011000000000000000000000000000000000000000000 //i = 55
^ ^ ^ ^ ^ ^ ^ ^
As you can see, all but the last marker point to a valid character but you won't reach i = 63 because after the first time you remove a character there only are 63 left in the string and thus a max index of 62.
That's why your resulting string has 57 instead of 56 characters, the last "remove" operation doesn't run (and the others except the first remove the wrong elements).
To fix that iterate backwards, i.e. from i = str.length() - 1 to i = 0. Then you can remove every element where (i + 1) % 8 == 0.
Alternatively, as I said in my comment, use a regex: String shortened = str.replaceAll( "(.{7}).", "$1" );
This will match any sequence of 7 characters followed by another (8th) character and replaces that with the first group of 7 (thus skipping the 8th).
There is not deleteCharAt method in String, so I suppose you meant StringBuilder?
You can just reverse the direction of the for loop, so that it starts from the end of the string:
String str = "11111111811111118";
StringBuilder builder = new StringBuilder(str);
System.out.println(str + " " + str.length());
for (int i = str.length() - 1; i >= 0; i--) {
// Every 8th element should be discarded
if (i > 7 && i % 8 == 0) {
builder.deleteCharAt(i);
}
}
System.out.println(builder+ " " + builder.length());
By deleting chars from the end of the string, the indices of the chars to be removed no longer changes as you move along the string.
Why don't you use regex and achieve it in two lines of code like this,
public static void main(String[] args) {
String str = "1100110001011011000000000000000000000000000000000000000000000000";
String replacedStr = str.replaceAll("([01]{7})[01]", "$1");
System.out.println(str.toString() + " " + str.length());
System.out.println(replacedStr.toString() + " " + replacedStr.length());
}
This gives perfectly correct output,
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Alternatively, you can follow this traditional solution like you attempted.
Strings in java are immutable. So instead you should create a StringBuilder object and keep copying every character, except 8th character.
For correctly counting every 8th character, initialize your for loop index run from 1 rather than 0, like in this code, which will eradicate every 8th character effectively where you wanted to do if (i%8==0)
public static void main(String[] args) {
String str = "1100110001011011000000000000000000000000000000000000000000000000";
StringBuilder sb = new StringBuilder();
System.out.println(str + " " + str.length());
for (int i = 1; i <= str.length(); i++) {
// Every 8th element should be discarded
if (i % 8 == 0) {
// str.deleteCharAt(i);
} else {
sb.append(str.charAt(i-1));
}
}
System.out.println(sb.toString() + " " + sb.length());
}
And this gives following output,
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
You can verify here where only every 8th character is gone in this output.
The problem is that Strings are starting with 0. Therefore the 8th element has the index 7 and has to be removed as well, which you don't do in your loop. I'd write it like that (but noting that this might not be the most elegant solution):
public static void main(String[] args)
{
String str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
int idx = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
idx++;
if (idx == 8) {
idx = 0;
continue;
}
sb.append(str.charAt(i));
}
System.out.println(sb.toString() + " " + sb.length());
}
Outputs:
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Assuming that the string does not contain the char with ASCII value 0, convert the string to a char array and change every 8th char with the char with ASCII value 0, then reconstruct the string and replace all chars with ASCII value 0 with "":
String str = "0123456701234567012345670123456701234567012345670123456701234567";
System.out.println("initial = " + str);
char[] array = str.toCharArray();
for (int i = 7; i < array.length; i = i + 8) {
array[i] = 0;
}
str = String.valueOf(array).replace(String.valueOf(Character.toChars(0)), "");
System.out.println("final = " + str);
will print:
initial = 0123456701234567012345670123456701234567012345670123456701234567
final = 01234560123456012345601234560123456012345601234560123456
An alternative way is using substring() method.
substring(int beginIndex, int endIndex) Returns a new string that is a
substring of this string.
In every turn add 7 chars of the string to the new string and skip the 8th element of the string: sb.append(str.substring(start, start+7));
In first turn:
str.substring(0, 7) -> "1100110"
start += 8; -> start = 8;
In second turn:
str.substring(8, 15) -> "0101101"
start += 8; -> start = 23;
...
So the 8th element/the element has the index 7 ("0") has been skipped.
String str = "1100110001011011000000000000000000000000000000000000000000000000";
int length = str.length();
int start = 0;
StringBuilder sb = new StringBuilder();
while((start+7)<length) {
sb.append(str.substring(start, start+7));
start += 8;
}
if(start<length) {
sb.append(str.substring(start, length));
}
System.out.println(sb + " " + sb.length());
System.out.println(str + " " + str.length());
Output:
11001100101101000000000000000000000000000000000000000000 56
1100110001011011000000000000000000000000000000000000000000000000 64
String doesn't have a deleteCharAt() method. If it did, it would return the update string, since String is immutablem so code would have had to be str = str.deleteCharAt(i);.
You could use StringBuilder instead, since it does have a deleteCharAt() method.
To delete every 8th character, start at the end. That way index values are unaffected by already deleted characters, which is your current problem.
String str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
StringBuilder buf = new StringBuilder(str);
for (int i = (buf.length() - 1) / 8 * 8; i >= 0; i -= 8)
buf.deleteCharAt(i);
str = buf.toString();
System.out.println(str + " " + str.length());
Output
1100110001011011000000000000000000000000000000000000000000000000 64
10011001011011000000000000000000000000000000000000000000 56
UPDATE
The above code deletes the 1st, 9th, 17th, ... character, i.e. characters at index 0, 8, 16, ..., which is in accordance with "remove every 8th char" and "check if i % 8 == 0" mentioned in the question.
If code should delete the 8th, 16th, 24th, ... character, i.e. characters at index 7, 15, 23, ..., then change initialization of i as follows:
for (int i = (buf.length() - 8) & ~7 | 7; i >= 0; i -= 8)
buf.deleteCharAt(i);
Output
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Since StringBuilder::deleteCharAt changes the size of the underlying sequence, you need to process the target string in reverse order.
This solution is based on streams.
// create target string
String s = Stream.generate(() -> IntStream.range(0, 10))
.limit(10)
.map(stream -> stream.mapToObj(Objects::toString).collect(Collectors.joining()))
.collect(Collectors.joining());
StringBuilder sb = new StringBuilder(s);
// delete first element or not?
boolean removeFirst = false;
IntStream.range(removeFirst ? 0 : 1, s.length())
.boxed()
.sorted(Collections.reverseOrder()) // reverse number stream
.filter(i -> i % 8 == 0) // only keep multiples of 8
.forEach(sb::deleteCharAt);
System.out.println(s);
System.out.println(sb.toString());
This is the output it produces
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
123456790123457890123567890134567891234567901234578901235678901345678912345679012345789
The first element missing is the 8, then 6 (16), then the 4 (24), etc.

bad result of my code

I seem to have a problem, where the output I expect is:
9000 + 200 + 50 + 6
But I get:
90000 + 2000 + 500 + 60
Here is my code:
class Kata
{
public static String expandedForm(int num) {
String s = String.valueOf(num);
StringBuilder result = new StringBuilder();
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == '0') continue;
result.append(s.charAt(i) + makesZero(s.length() - i));
if(i != s.length() - 1) result.append(" + ");
}
return result.toString();
}
public static String makesZero(int num) {
StringBuilder result = new StringBuilder();
for(int i = 0; i < num; i++)
result.append("0");
return result.toString();
}
}
public class Main {
public static void main(String args[]) {
System.out.println(Kata.expandedForm(9256));
}
}
At
result.append(s.charAt(i) + makesZero(s.length() - i));
line you are appending character at position i and length - i zeroes. Lets see what happens for s="9256".
If i=0
s.charAt(i)->s.charAt(0)->'9' (that looks OK)
makesZero(s.length() - i) -> makesZero(4 - 0)) -> makesZero(4) -> "0000".
So as you see you are adding one extra zero because you didn't take into account that while 9 represents thousands, but thousands despite having 4 digits should have 3 zeroes. So you need to reduce one zero with
makesZero(s.length() - i - 1).
BTW builder.append(foo + bar) (when + represents concatenation, not addition) should be written as builder.append(foo).append(bar). Otherwise you are ending with something like
builder.append(new StringBuilder().append(foo).append(bar).toString())
which means you still need to create separate builder for each +.
We are using StringBuilder#append precisely so we could avoid + and such unnecessary object creation.
You're dealing with a classic off-by-one error. This is easily solved, but the larger problem with your approach is that you are solving the problem in an unnatural way, which makes your code more difficult to understand and debug. Determining how many zeroes to add is fundamentally a math problem but you are treating it like a string problem, which reduces the expressiveness of your code.
Here is a suggested rewrite of your expandedForm method that approaches this problem in a different way.
public static String expandedForm(int num) {
if (num == 0)
return "0";
int zeroes = (int) Math.log10(num);
StringBuilder result = new StringBuilder();
while (zeroes >= 0) {
int multiple = (int) Math.pow(10, zeroes);
int digit = num / multiple;
result.append(String.valueOf(digit * multiple));
if (zeroes > 0)
result.append(" + ");
num = num % multiple;
--zeroes;
}
return new String(result);
}
Just start your loop with i = 1 and i <= s. length()

Android Java Check Length of String - Multiple of 30

My situation: I have a string (called str). The length of the string must be a multiple of 30 (e.g 30, 60, 90). If the length of the str is not a multiple of 30, add spaces " " to the end of it.
Something like this:
if (str.length() / 30 != ????) {
//add spaces to the end
}
Of course, the code above is not correct. It would be very appreciated if you could help me with this.
Thanks in advance!
You can quite simply do:
if(str.length()%30!=0)
str = String.format("%1$-"+(((str.length()/30)*30)+30)+"s", str);
str.length()%30 gives the remainder on dividing the length by 30. If it is not 0, then you have to add spaces.
String.format("%1$-"+(((str.length()/30)*30)+30)+"s", str) adds the spaces to the right of the String.
Or even simply, you can do:
while(str.length()%30 !=0)
str+= ' ';
this code is not tested but i guess it will work:
int a = str.length()%30;
for(int i=0; i<=a; i++)
str = str + " ";
What would you do to check if a number is a multiple of 30 in simple Maths?
Yes, you would divide and check if the remainder is 0 or not, right?
That's how you'll do it in Java. To get the remainder in Java, Modulus(%) operator is used. So, you can do it like this :
if (str.length() % 30 != 0) {
//add spaces to the end
str += " ";
}
or if you want to add spaces to make the length a multiple of 30, then do this:
int remainder = str.length() % 30;
if (remainder != 0) {
//add spaces to the end
int numSpacesRequired = 30-remainder; //no. of spaces reuired to make the length a multiple of 30
for(int i = 0; i < numSpacesRequired; i++)
str += " ";
}
Read more about the basic operators in Java here.
You can use Modulo to achieve that:
if (str.length() % 30 != 0) {
//add spaces to the end
str += ' ';
}
Simply: (Tested and worked)
public static void main(String[] args) {
String str = "AYOA"; //Length is only 4
//If the remainder of the str's length is not 0 (Not a multiple)
if (str.length() % 30 != 0){
str += ' ';
}
System.out.println("[" + str + "]"); //A space is added at the back
}
If you want to add the space continuously until the length is a multiple of 30:
public static void main(String[] args) {
String str = "AYOA"; //Length is only 4
//If the remainder of the str's length is not 0 (Not a multiple)
//Repeat until is multiple of 30
while(str.length % 30 != 0){
str += ' ';
}
System.out.println("[" + str + "]"); //A space is added at the back
}
use StringBuilder to build whitespaces
String str="multiple of 30";
int spacesNum=str.length()%30; //get the remainder
StringBuilder spaces=new StringBuilder(); //build white spaces
for(int j=0;j<spacesNum;j++){
spaces.append(' ');
}
System.out.println(str+spaces.toString());

Why doesn't this print the last character of the word?

I'm using java. I'm trying pull out the last letter of a word of 8 characters or less. Then pulling out each character after
lengthOfWord = word.length();
lc = word.charAt(lengthOfWord -1);
if (lengthOfWord == 1)
System.out.println(lc);
When I try to use a word with one character, it says "String index out of range: -1" and when I try using a word of two characters, it says build successfully, but doesn't print anything.
lengthOfWord is past the bounds of word. Use:
lc = word.charAt(lengthOfWord - 1);
Remember that .length() returns the number of characters of an object, but the index of an object starts at 0 and ends at length()-1.
UPDATE
Try this to check all characters in the word:
for (int i = 0; i < word.length(); i++) {
System.out.println("Char " + i + ": " + word.charAt(i));
}
lengthOfWord is 0 based, so you might wanna try lc = word.charAt(lengthOfWord - 1);

Categories