Getting String from StringBuilder - java

I was working with StringBuilder to eliminate some unnecessary chars, I got some strange result.
String value = "1.045,00";
StringBuilder sanitized = new StringBuilder();
boolean decimalSeparatorFound = false;
char[] chars = value.toCharArray();
for (int i = chars.length-1; i >= 0; i--) {
if (chars[i] == ',' || chars[i] == '.') {
if (decimalSeparatorFound) continue; // skip this char
decimalSeparatorFound = true;
sanitized.append('.');
} else {
sanitized.append(chars[i]);
}
}
here I will get 00.5401 as a result in sanitized but when I was converting it to string like
String s = sanitized.reverse.toString();
and It is expected to print the value of s as 1045.00 but it get printed as 00.5401.
then I tried it as
StringBuilder sb = sanitized.reverse();
String s1 = sb.toString();
now this time it got printed correctly.
here my question why the StringBuilder is behaving this way? Isn't it performing reverse operation while assigning the value to String s?

"my question why the StringBuilder is behaving this way?"
What's happening is that if you have both ways in the same code, it will reverse once, then reverse again
StringBuilder sb = sanitized.reverse(); // first reverse
String s1 = sb.toString();
String s = sanitized.reverse().toString(); // second reverse
System.out.println(s1);
System.out.println(s);
OUTPUT
1045.00
00.5401
But if you take out the first reverse and just use the second reverse by itself, you get the correct output
String s = sanitized.reverse().toString();
System.out.println(s);
OUPUT
1045.00

Change append to insert
sanitized.insert(0, '.');
} else {
sanitized.insert(0, chars[i]);
}
I would do it simpler
String decimalSeparator = s.indexOf(',') > s.indexOf('.') ? "." : ",";
s = s.replace(decimalSeparator, "");

In this loop, You are reversing the string by appending to StringBuilder from chars[chars.length-1] to chars[0]
for (int i = chars.length-1; i >= 0; i--) {
if (chars[i] == ',' || chars[i] == '.') {
if (decimalSeparatorFound) continue; // skip this char
decimalSeparatorFound = true;
sanitized.append('.');
} else {
sanitized.append(chars[i]);
}
}
This is the actual reason for the reversion. You should change the loop like this
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ',' || chars[i] == '.') {
if (decimalSeparatorFound) continue; // skip this char
decimalSeparatorFound = true;
sanitized.append('.');
} else {
sanitized.append(chars[i]);
}
}
So, it will work as you expect

Can you please try this:
Use StringBuilder's or StringBuffer's method... reverse()
public class StringReverse
{
public static void main(String[] args)
{
String string=args[0];
String reverse = new StringBuilder(string).reverse().toString();
System.out.println("\nString before reverse: "+string);
System.out.println("String after reverse: "+reverse);
}
}
StringBuffer is thread-safe, where as StringBuilder is Not thread safe.....
StringBuilder was introduced from Java 1.5, as to do those operations faster which doesn't have any Concurrency to worry about....
Hope this helps..

You didn't call reverse method in the right way.
You should call it reverse() with braces.
Your line should be like this:
// now they will give you the same results
String s1 = sanitized.reverse().toString();
System.out.println(s1) //1045.00
StringBuilder sb = sanitized.reverse();
String s1 = sb.toString();
System.out.println(s1) //1045.00

Instead of doing this
for (int i = chars.length-1; i >= 0; i--)
you should try this
for (int i = 0; i <chars.length; i++)
May be you are using reverse two times.

Related

I want to remove the special character and convert the next letter to uppercase "the-stealth-warrior" in Java

public class Main {
public static void main(String[] args) {
String name = "the-stealth-warrior";
for (int i = 0; i < name.length();i++){
if (name.charAt(i) == '-'){
char newName = Character.toUpperCase(name.charAt(i+1));
newName += name.charAt(i + 1);
i++;
}
}
}
}
I try to loop in every char and check if the I == '-' convert the next letter to be uppercase and append to a new String.
We can try using a split approach with the help of a stream:
String name = "the-stealth-warrior";
String parts = name.replaceAll("^.*?-", "");
String output = Arrays.stream(parts.split("-"))
.map(x -> x.substring(0, 1).toUpperCase() + x.substring(1))
.collect(Collectors.joining(""));
output = name.split("-", 2)[0] + output;
System.out.println(output); // theStealthWarrior
I think the most concise way to do this would be with regexes:
String newName = Pattern.compile("-+(.)?").matcher(name).replaceAll(mr -> mr.group(1).toUpperCase());
Note that Pattern.compile(...) can be stored rather than re-evaluating it each time.
A more verbose (but probably more efficient way) to do it would be to build the string using a StringBuilder:
StringBuilder sb = new StringBuilder(name.length());
boolean uc = false; // Flag to know whether to uppercase the char.
int len = name.codePointsCount(0, name.length());
for (int i = 0; i < name.len; ++i) {
int c = name.codePointAt(i);
if (c == '-') {
// Don't append the codepoint, but flag to uppercase the next codepoint
// that isn't a '-'.
uc = true;
} else {
if (uc) {
c = Character.toUpperCase(c);
uc = false;
}
sb.appendCodePoint(c);
}
}
String newName = sb.toString();
Note that you can't reliably uppercase single codepoints in specific locales, e.g. ß in Locale.GERMAN.

Splitting this string to get the max count to a corresponding character

I am currently implementing Run Length Encoding for text compression and my algorithm does return Strings of the following form:
Let's say we have a string as input
"AAAAABBBBCCCCCCCC"
then my algorithm returns
"1A2A3A4A5A1B2B3B4B1C2C3C4C5C6C7C8C"
Now I want to apply Java String split to solve this, because I want to get the highest number corresponding to character. For our example it would be
"5A4B8C"
My function can be seen below
public String getStrfinal(){
String result = "";
int counter = 1;
StringBuilder sb = new StringBuilder();
sb.append("");
for (int i=0;i<str.length()-1;i++) {
char c = str.charAt(i);
if (str.charAt(i)==str.charAt(i+1)) {
counter++;
sb.append(counter);
sb.append(c);
}
else {
counter = 1;
continue;
}
}
result = sb.toString();
return result;
}
public static String getStrfinal(){
StringBuilder sb = new StringBuilder();
char last = 0;
int count = 0;
for(int i = 0; i < str.length(); i++) {
if(i > 0 && last != str.charAt(i)) {
sb.append(count + "" + last);
last = 0;
count = 1;
}
else {
count++;
}
last = str.charAt(i);
}
sb.append(count + "" + last);
return sb.toString();
}
Here is one possible solution. It starts with the raw string and simply iterates thru the string.
public static void main(String[] args) {
String input = "AAAABBBCCCCCCCDDDEAAFBBCD";
int index = 0;
StringBuilder sb = new StringBuilder();
while (index < input.length()) {
int count = 0;
char c = input.charAt(index);
for (; index < input.length(); index++) {
if (c != input.charAt(index)) {
count++;
}
else {
break;
}
}
sb.append(Integer.toString(count));
sb.append(c);
count = 0;
}
System.out.println(sb.toString());
}
But one problem with this method and others is what happens if there are digits in the text? For example. What if the string is AAABB999222AAA which would compress to 3A2B39323A. That could also mean AAABB followed by 39 3's and 23 A's
Instead of string Buffer you can use a map it will be much easier and clean to do so.
public static void main(String[] args) {
String input = "AAAAABBBBCCCCCCCCAAABBBDDCCCC";
int counter=1;
for(int i=1; i<input.length(); i++) {
if(input.charAt(i-1)==input.charAt(i)) {
counter=counter+1;
}else if(input.charAt(i-1)!=input.charAt(i)){
System.out.print(counter+Character.toString(input.charAt(i-1)));
counter=1;
}if(i==input.length()-1){
System.out.print(counter+Character.toString(input.charAt(i)));
}
}
}
This will gives
5A4B8C3A3B2D4C
UPDATES
I Agree with #WJS if the string contains number the out put becomes messy
hence if the System.out in above code will be exchange with below i.e.
System.out.print(Character.toString(input.charAt(i-1))+"="+counter+" ");
then for input like
AAAAABBBBCCCCCCCCAAABBBDD556677CCCCz
we get out put as below
A=5 B=4 C=8 A=3 B=3 D=2 5=2 6=2 7=2 C=4 z=1
This is one of the possible solutions to your question. We can use a LinkedHashMap data structure which is similar to HashMap but it also maintains the order. So, we can traverse the string and store the occurrence of each character as Key-value pair into the map and retrieve easily with its maximum occurrence.
public String getStrFinal(String str){
if(str==null || str.length()==0) return str;
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
StringBuilder sb=new StringBuilder(); // to store the final string
for(char ch:str.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1); // put the count for each character
}
for(Map.Entry<Character,Integer> entry:map.entrySet()){ // iterate the map again and append each character's occurence into stringbuilder
sb.append(entry.getValue());
sb.append(entry.getKey());
}
System.out.println("String = " + sb.toString()); // here you go, we got the final string
return sb.toString();
}

Java: Formatting issue. Grabbing unique characters from an array of strings and returning them

I'm having a problem getting the unique letters and digits out of an array of strings, and then returning them. I am having a formatting issue.
The given input is: ([abc, 123, efg]) and is supposed to return abcefg123,
however, mine returns: abc123efg
how can I fix this since arrays.sort() will end up putting the numbers first and not last?
Here is my method so far:
public static String getUniqueCharsAndDigits(String[] arr) {
String str = String.join(",", arr);
String myString = "";
myString = str.replaceAll("[^a-zA-Z0-9]", "");
for(int i = 0; i < str.length(); i++) {
if(Character.isLetterOrDigit((i))){
if(myString.indexOf(str.charAt(i)) == -1) {
myString = myString + str.charAt(i);
}
}
}
return myString;
}
What you want to do is create two strings, one with the letters, one with the digits.
public static String getUniqueCharsAndDigits(String[] arr) {
String str = String.join("", arr);
String myLetters, myDigits;
myLetters = myDigits = "";
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(Character.isLetter(c)){
if(myLetters.indexOf(c) == -1) {
myLetters += c;
}
} else if(Character.isDigit(c)){
if(myDigits.indexOf(c) == -1) {
myDigits += c;
}
}
}
//if they need to be sorted, sort each one individually here
return myLetters + myDigits;
}
I've modified your code and deleted the unnecessary parts of it.

Censor word from a string [duplicate]

I want to replace all the characters in a Java String with * character. So it shouldn't matter what character it is, it should be replaced with a *.
I know there are heaps of examples there on internet but have not one that replaces every character and I have tried myself but no success.
Java 11 and later
str = "*".repeat(str.length());
Note: This replaces newlines \n with *. If you want to preserve \n, see solution below.
Java 10 and earlier
str = str.replaceAll(".", "*");
This preserves newlines.
To replace newlines with * as well in Java 10 and earlier, you can use:
str = str.replaceAll("(?s).", "*");
The (?s) doesn't match anything but activates DOTALL mode which makes . also match \n.
Don't use regex at all, count the String length, and return the according number of stars.
Plain Java < 8 Version:
int len = str.length();
StringBuilder sb = new StringBuilder(len);
for(int i = =; i < len; i++){
sb.append('*');
}
return sb.toString();
Plain Java >= 8 Version:
int len = str.length();
return IntStream.range(0, n).mapToObj(i -> "*").collect(Collectors.joining());
Using Guava:
return Strings.repeat("*", str.length());
// OR
return CharMatcher.ANY.replaceFrom(str, '*');
Using Commons / Lang:
return StringUtils.repeat("*", str.length());
System.out.println("foobar".replaceAll(".", "*"));
public String allStar(String s) {
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
sb.append('*');
}
return sb.toString();
}
How abt creating a new string with the number of * = number of last string char?
StringBuffer bf = new StringBuffer();
for (int i = 0; i < source.length(); i++ ) {
bf.append('*');
}
There may be other faster/better ways to do it, but you could just use a string buffer and a for-loop:
public String stringToAsterisk(String input) {
if (input == null) return "";
StringBuffer sb = new StringBuffer();
for (int x = 0; x < input.length(); x++) {
sb.append("*");
}
return sb.toString();
}
If your application is single threaded, you can use StringBuilder instead, but it's not thread safe.
I am not sure if this might be any faster:
public String stringToAsterisk(String input) {
if (input == null) return "";
int length = input.length();
char[] chars = new char[length];
while (length > 0) chars[--length] = "*";
return new String(chars);
}
Without any external library and without your own loop, you can do:
String input = "Hello";
char[] ca = new char[input.length()];
Arrays.fill(ca, '*');
String output = new String(ca);
BTW, both Arrays.fill() and String(char []) are really fast.
Recursive method
String nCopies(String s, int n) {
return n == 1 ? s.replaceFirst(".$", "") : nCopies(s + s, --n);
}
String text = "Hello World";
System.out.println( text.replaceAll( "[A-Za-z0-9]", "*" ) );
output : ***** *****

Cannot return modified String from static method

Im very new to coding and cant seem to be able to return anything. I need to convert upper case characters to lower case and vice versa. Here's my code:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
invString(str);
sc.close();
}
private static String invString(String str) {
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch > 97) {
ch = Character.toUpperCase(ch);
return str;
} else {
ch = Character.toLowerCase(ch);
return str;
}
}
return null;
}
What am i doing wrong? ( in terms of returning, the code isnt complete yet)
EDIT****************
thanks for the helpful remarks, as i understood i do not have a place where my modifications are stored, so i added String res = ""; and kept adding the values into String res but in the end, when returning res, i still dont get any output...Here is the whole thing:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String st = invString(str);
sc.close();
}
private static String invString(String str) {
String res = "";
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (65 <= ch && ch <= 90) {
ch += 32;
res += ch;
} else if (97 <= ch && ch <= 122) {
ch -= 32;
res += ch;
}
}
return res;
}
ps. Im not using the ready methods because my task asks for it.
There are a number of flaws in your code. Firstly, you are attempting to return the original string str in every if statement. So what happens is the method invString( String ) simply returns the original string that is passed as argument. Instead, you should keep adding the characters to a new String variable (as #Massimo said). Also, you are returning null in the end. Why even do that? You would want to return the new String variable instead.
private static String invString(String str) {
String s=""; //new String variable
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch > 97) {
ch = Character.toUpperCase(ch);
s+=ch; //do this instead of returning str
} else {
ch = Character.toLowerCase(ch);
s+=ch; //same here
}
}
return s; //return the new String
}
Secondly, in your main method, simply calling the method is wrong as it returns a value. You should assign the value returned by invString() to a String variable.
public static void main(String[] args){
...
String st = invString(str); //st stores the value of str with
//letters' cases changed
}
You return you str object without updating it at all.
You should generate a new string in which put the characters for which you reverse the case.
Check the last answers in
How can I invert the case of a String in Java?
If you want to use the inverted string, you need to actually use the returned value, e.g:
str = invString (str)
Strings are immutable so you can't change the characters within them. You can only replace the string variable with a new string.
Modifying the characters you are accessing doesn't affect the string. You need to build a new string (look up StringBuilder) and return it.

Categories

Resources