Hi I'm trying to insert a dash in between all of the characters in a string. I've done this, but it wont work:
public static String expand (String word)
{
int stringLength = word.length();
for (int x=0; x<stringLength; x++){
word = new StringBuffer(word).insert(x, "-").toString();
}
return word;
}
It results in the dashes before the word. I don't understand why it's not working. Thanks.
That's right, all dashes get inserted before the word. Here is how this happens: when you insert the first dash, what used to be at index one is moved by one character, so when you insert the dash at the next position, you insert it right after the previous dash: the word keeps moving away, so you loop behaves like a dog chasing its own tail!
There are several ways to fix this problem:
Insert dashes at even locations, i.e. 2*i
Start with an empty StringBuffer, go through the original characters in a loop, and add a character followed by a dash; when you are at the last character, do not add a dash.
Note that the second approach is more efficient, because it is linear in the number of characters in the original word. The first approach (i.e. one based on insertions) is less efficient, because it is O(n2) due to the need to shift the tail of the buffer on each insertion.
The issue is that you are adding a new character into the string, but not incrementing the index to account for that.
Try this (note, I haven't tested it, but it should work correctly. If you have an extra dash at start or finish, just remove them afterward):
public static String expand (String word)
{
int stringLength = word.length();
for (int x=1; x<(stringLength-1)*2; x+=2){
word = new StringBuffer(word).insert(x, "-").toString();
}
return word;
}
Form your output NOT using the input in this function, and make sure not to insert a hyphen after the last character:
public static String expand(String word) {
int stringLength = word.length();
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < stringLength - 1; i++) {
buffer.append(word.substring(i, i + 1));
buffer.append("-");
}
buffer.append(word.substring(stringLength - 1, stringLength));
return buffer.toString();
}
Try this:
String word = "hello";
char[] wordChar = word.toCharArray(); //split String into char array
StringBuffer result = new StringBuffer("");
for (char c : wordChar) {
result.append(c).append("-"); // iterate over the letters and append a dash
}
result.deleteCharAt(result.length() - 1); // remove last dash
System.out.println(result.toString());
Output: "h-e-l-l-o"
"Split" & Conquer ;)
Related
I have a string as follows:
String sentence = "I have bananas\r" +
"He has apples\r" +
"I own 3 cars\n" +
"*!"
I'd like to reverse this string so as to have an output like this:
"*!" +
"\ncars 3 own I" +
"\rapples has He" +
"\rbananas have I"
Here is a program I wrote.
public static String reverseWords(String sentence) {
StringBuilder str = new StringBuilder();
String[] arr = sentence.split(" ");
for (int i = arr.length -1; i>=0; i--){
str.append(arr[i]).append(" ");
}
return str.toString();
}
But I don't get the output as expected. What is wrong?
The problem is you are only splitting on spaces, but that is not the only type of whitespace in your sentence. You can use the pattern \s to match all whitespace. However, then you don't know what to put back in that position after the split. So instead we will split on the zero-width position in front of or behind a whitespace character.
Change your split to this:
String[] arr = sentence.split("(?<=\\s)|(?=\\s)");
Also, now that you are preserving the whitespace characters, you no longer need to append them. So change your append to this:
str.append(arr[i]);
The final problem is that your output will be garbled due to the presence of \r. So, if you want to see the result clearly, you should replace those characters. For example:
System.out.println(reverseWords(sentence).replaceAll("\\r","\\\\r").replaceAll("\\n","\\\\n"));
This modified code now give the desired output.
Output:
*!\ncars 3 own I\rapples has He\rbananas have I
Note:
Since you are freely mixing \r and \n, I did not add any code to treat \r\n as a special case, which means that it will be reversed to become \n\r. If that is a problem, then you will need to prevent or undo that reversal.
For example, this slightly more complex regex will prevent us from reversing any consecutive whitespace characters:
String[] arr = sentence.split("(?<=\\s)(?!\\s)|(?<!\\s)(?=\\s)");
The above regex will match the zero-width position where there is whitespace behind but not ahead OR where there is whitespace ahead but not behind. So it won't split in the middle of consecutive whitespaces, and the order of sequences such as \r\n will be preserved.
The logic behind this question is simple, there are two steps to achieve the OP's target:
reverse the whole string;
reverse the words between (words splitted by spaces);
Instead of using StringBuilder, I'd prefer char[] to finish this, which is easy to understand.
The local test code is:
public class WordReverse {
public static void main(String... args) {
String s = " We have bananas\r" +
"He has apples\r" +
"I own 3 cars\n" +
"*!";
System.out.println(reverseSentenceThenWord(s));
}
/**
* return itself if the #param s is null or empty;
* #param s
* #return the words (non-whitespace character compound) reversed string;
*/
private static String reverseSentenceThenWord(String s) {
if (s == null || s.length() == 0) return s;
char[] arr = s.toCharArray();
int len = arr.length;
reverse(arr, 0, len - 1);
boolean inWord = !isSpace(arr[0]); // used to track the start and end of a word;
int start = inWord ? 0 : -1; // is the start valid?
for (int i = 0; i < len; ++i) {
if (!isSpace(arr[i])) {
if (!inWord) {
inWord = true;
start = i; // just set the start index of the new word;
}
} else {
if (inWord) { // from word to space, we do the reverse for the traversed word;
reverse(arr, start, i - 1);
}
inWord = false;
}
}
if (inWord) reverse(arr, start, len - 1); // reverse the last word if it ends the sentence;
String ret = new String(arr);
ret = showWhiteSpaces(ret);
// uncomment the line above to present all whitespace escape characters;
return ret;
}
private static void reverse(char[] arr, int i, int j) {
while (i < j) {
char c = arr[i];
arr[i] = arr[j];
arr[j] = c;
i++;
j--;
}
}
private static boolean isSpace(char c) {
return String.valueOf(c).matches("\\s");
}
private static String showWhiteSpaces(String s) {
String[] hidden = {"\t", "\n", "\f", "\r"};
String[] show = {"\\\\t", "\\\\n", "\\\\f", "\\\\r"};
for (int i = hidden.length - 1; i >= 0; i--) {
s = s.replaceAll(hidden[i], show[i]);
}
return s;
}
}
The output is not in my PC as OP provided but as:
*!
bananas have I
However, if you set a breakpoint and debug it and check the returned string, it will be as:
which is the right answer.
UPDATE
Now, if you would like to show the escaped whitespaces, you can just uncomment this line before returning the result:
// ret = showWhiteSpaces(ret);
And the final output will be exactly the same as expected in the OP's question:
*!\ncars 3 own I\rapples has He\rbananas have I
Take a look at the output you're after carefully. You actually need two iteration steps here - you first need to iterate over all the lines backwards, then all the words in each line backwards. At present you're just splitting once by space (not by new line) and iterating over everything returned in that backwards, which won't do what you want!
Take a look at the example below - I've kept closely to your style and just added a second loop. It first iterates over new lines (either by \n or by \r, since split() takes a regex), then by words in each of those lines.
Note however this comes with a caveat - it won't preserve the \r and the \n. For that you'd need to use lookahead / lookbehind in your split to preserve the delimiters (see here for an example.)
public static String reverseWords(String sentence) {
StringBuilder str = new StringBuilder();
String[] lines = sentence.split("[\n\r]");
for (int i = lines.length - 1; i >= 0; i--) {
String[] words = lines[i].split(" ");
for (int j = words.length - 1; j >= 0; j--) {
str.append(words[j]).append(" ");
}
str.append("\n");
}
return str.toString();
}
My problem is that I'm getting a String and I need to check if there is a space in the 4th position but starting from the end. If in this position there is not a space, I should insert it.
For example:
I get this String: TW12EF, need to get it like this: TW1 2EF
First of all I get the 4 last characters in a char array because I also need to check if they are numbers or letters.
With this method I check if there is a space:
public static boolean isSpace(){
return String.valueOf(charArray[0]).matches("[ \\t\\n\\x0B\\f\\r]");
}
charArray contains the last 4 characters of the input String
If charArray[0] wouldn't be a space, I want to insert a space in the 2nd place (charArray[1])
If there is something that I can correct in the question to make it easier to understand, just let me know and I will try to make it better for next questions.
A simple and direct solution (most likely faster than using a regular expression) is to get the 4th to the last character (if it exists), and if it isn't a white-space, insert a space at that position.
public static void main(String[] args) {
String str = "TW12EF";
int insertPos = str.length() - 4;
if (insertPos >= 0) {
char ch = str.charAt(insertPos);
if (!Character.isWhitespace(ch)) {
str = new StringBuilder(str).insert(insertPos + 1, ' ').toString();
}
}
System.out.println(str);
}
A whitespace is determined by invoking isWhitespace, which returns true for space but also tabs or line feeds, like you did in your question. The character is inserted by leveraging the StringBuilder#insert method, which is more direct that taking 2 substrings and concatenating them.
A quick, dirty regex will help :
String p = "TW12EF";
System.out.println(p.replaceAll("(.)\\s*(\\S.{2})$", "$1 $2")); // Select a character followed by 0 or more spaces and followed by 3 non-space characters. And replace multiple spaces if they exist with a single space
O/P :
TW1 2EF
Also works if there are one or more spaces after the 3rd char (from the left)
As char is a primitive data type, the comparison can be done simply with
if (charArray[0] == ' ') {
char[] temp = new char[5];
temp[0] = ' ';
for (int i = 1; i <= 4; i++) {
temp[i] = charArray[i - 1];
}
charArray = temp;
}
You could use something like:
public static void main(String[] args) {
String str = "TW12EF";
processStr(str);
}
public static final int SPACE_POS = 4, OFFSET = 1;
public static String processStr(String str)
{
if(!Character.isWhitespace(str.charAt(str.length() - SPACE_POS)))
{
str = String.format("%s %s", str.substring(0, str.length() - SPACE_POS + OFFSET), str.substring(SPACE_POS - OFFSET));
}
return str;
}
Like this?
` String s="TW12EF";
String result="";
int length=s.length();
for(int i=length-1;i>-1;i--){
if(i==length-4&&s.charAt(i)!=' '){
result+=" ";
}
result+=s.charAt(length-i-1);
}
System.out.println(result);`
I am trying to print a substring using index value. I need to exclude the blank space while counting but it should print the output along with blank space. I want to display, say, n alphabets from the main string. The blank spaces will be as they are but the number of alphabets from the lower bound to upper bound index should be n. My code is
public class Test {
public static void main(String args[])
{
String Str=new String("Welcome to the class");
System.out.println("\nReturn value is:");
System.out.println(Str.substring(2,9));
}
}
Output:
lcome t
In the above mentioned code, it counts the space between the "Welcome" and "to". i need not want to count the space between them. My expected output is lcome to
You could use simple mathematics. Just substring it, remove all whitespaces and compare the original length to the String without whitespaces. Afterwards add the difference in size to your end index for the substring.
public static void main(String args[]) {
String Str = "Welcome to the class";
System.out.println("\nReturn value is:");
String sub = Str.substring(2, 9);
String wsRemoved = sub.replaceAll(" ", "");
String wsBegginingRemoved = sub.replaceAll("^ *", "");
String outputSub = Str.substring(2+(sub.length()-wsBegginingRemoved.length()), 9+(sub.length()-wsRemoved.length()+(sub.length() - wsBegginingRemoved.length())));
System.out.println(outputSub);
}
Edit: not ignoring leading whitespaces anymore
O/P
lcome to
O/P "My name is Earl"
name is E
One way would be to extract it to using a regex ^.{2}([^ ] *){7}.
Another option is to use a simple for loop to traverse the string and calculate the end point to use for substring.
int non_whitespace = 0; int i;
for(i = 2; non_whitespace < 7; ++non_whitespace, ++i) {
while (str.charAt(i) == ' ') ++i;
}
return str.substring(2, i);
It is up to you which method do you consider more readable, and assess which one leads to better performance if speed is a concern.
What you want to do is display n number of characters from the string including the spaces but n doesn't include the no. of blank spaces. For that, you could simply be using a loop instead of a library function.
The Logic: Keep displaying characters of the String str from index = 2 to index = 9-1 in a while loop. If the current character is a blank space, then increase the value of n, which is the upper bound of the string index for the sub string, by 1, i.e., the program will now display an extra character beyond the upper bound for each blank space encountered.
Consider the code below.
String str = "Welcome to the class";
int index = 2, n = 9;
while(index < n){
char c = str.charAt(index);
System.out.print(c);
if(c==' ')
n++;
index++;
}
Output: lcome to
Hope you can understand this code.
EDIT
As #Finbarr O'B said, a check to prevent StringIndexOutOfBoundsException would be necessary for the program for which, the loop will have to be defined as:
while(index < n && index < str.length()){
...
}
If you don't want to use regex, you can implement your own version of substring. The straightforward solution:
private static String substring(int begin, int end, String str) {
StringBuilder res = new StringBuilder();
while (begin < end) {
if (str.charAt(begin) == ' ') {
end++;
}
res.append(str.charAt(begin));
begin++;
}
return res.toString();
}
The trick here is to ignore the "count" of a space, by incrementing end when it's encountered, forcing the loop to make one extra iteration.
The code complexity is O(n).
System.out.println(substring(2, 9, "Welcome to the class"));
>> lcome to
You could use replaceFirst for this:
String Str = "Welcome to the class"; // remove new String()
Str = Str.replaceFirst("^ *", "");
System.out.println("\nReturn value is:");
System.out.println(Str.substring(2, 10)); // increment end index by 1
Output:
lcome to
I need to replace all commas after the 5th one. So if a String contains 10 commans, I want to leave only the first 5, and remove all subsequent commas.
How can I do this ?
String sentence = "Test,test,test,test,test,test,test,test";
String newSentence = sentence.replaceAll(",[6]","");
Just capture all the characters from the start upto the 5th comma and match all the remaining commas using the alternation operator |. So , after | should match all the remaining commas. By replacing all the matched chars with $1 will give you the desired output.
sentence.replaceAll("^((?:[^,]*,){5})|,", "$1");
DEMO
In case you were wondering how to solve this problem without using regular expressions... There are libraries that could make your life easier but here is the first thought that came to mind.
public String replaceSpecificCharAfter( String input, char find, int deleteAfter){
char[] inputArray = input.toCharArray();
String output = "";
int count = 0;
for(int i=0; i <inputArray.length; i++){
char letter = inputArray[i];
if(letter == find){
count++;
if (count <= deleteAfter){
output += letter;
}
}
else{
output += letter;
}
}
return output;
}
Then you would invoke the function like so:
String sentence = "Test,test,test,test,test,test,test,test";
String newSentence = replaceSpecificCharAfter(sentence, ',', 6);
How do I move char characters to left or to right in a string?
Reading the input string backwards you need to keep every character on an odd index of each word and any blank characters.
You could start with this snippet. See it as a PoC to demonstrate the logic. Optimisations are possible.
String encoded = "bxoqb swi eymrawn yim";
StringBuilder decoded = new StringBuilder();
boolean keep = true;
for (int i = encoded.length() - 1; i >= 0; i--) {
if (encoded.charAt(i) != ' ') {
if (keep) {
decoded.append(encoded.charAt(i));
}
keep = !keep;
} else {
decoded.append(' ');
keep = true;
}
}
System.out.println("decoded = " + decoded);
output
decoded = my name is bob
explanation
the for-loop processes the string backwards, so the characters are processed as miy nwarmye iws bqoxb
the variable i hold the current index position in the string encoded
as we want to keep only the characters on odd positions in a word the variable keep is used as a indicator
when the variable keep is true we append the current character (the one on position i in string encoded) to the string buffer decoded
if the current processed character is not a the value of keepis negated (true->false, false->true), so we append characters on every odd position
as we need to keep between the words also we have to treat this separately, each is appended to decoded and keep is set to true so the next non-blank character would be added too
Try this:
StringBuilder builder = new StringBuilder();
String[] charArray = encoded.split(" ");
for(int i = charArray.length-1 ; i >= 0; i--){
builder.append(charArray[i]);
}
String decoded = builder.toString();
You have to use StringBuffer to reverse the sentence.Then you can split your sentence word by word using the spaces between the words. After that basic java knowledge ...
String ss = "bxoqb swi eymrawn yim";
StringBuilder buffer = new StringBuilder(ss);
String word[] = buffer.reverse().toString().split(" ");
for (String word1 : word) {
char c[]=word1.toCharArray();
for(int x=0;x<c.length;x++){
if(x%2==0){
System.out.print(c[x]);
}
}
System.out.print(" ");
}