StringBuffer Append Space (" ") Appends "null" Instead - java

Basically what I'm trying to do is take a String, and replace each letter in the alphabet inside, but preserving any spaces and not converting them to a "null" string, which is the main reason I am opening this question.
If I use the function below and pass the string "a b", instead of getting "ALPHA BETA" I get "ALPHAnullBETA".
I've tried all possible ways of checking if the individual char that is currently iterated through is a space, but nothing seems to work. All these scenarios give false as if it's a regular character.
public String charConvert(String s) {
Map<String, String> t = new HashMap<String, String>(); // Associative array
t.put("a", "ALPHA");
t.put("b", "BETA");
t.put("c", "GAMA");
// So on...
StringBuffer sb = new StringBuffer(0);
s = s.toLowerCase(); // This is my full string
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
String st = String.valueOf(c);
if (st.compareTo(" ") == 1) {
// This is the problematic condition
// The script should just append a space in this case, but nothing seems to invoke this scenario
} else {
sb.append(st);
}
}
s = sb.toString();
return s;
}

compareTo() will return 0 if the strings are equal. It returns a positive number of the first string is "greater than" the second.
But really there's no need to be comparing Strings. You can do something like this instead:
char c = s.charAt(i);
if(c == ' ') {
// do something
} else {
sb.append(c);
}
Or even better for your use case:
String st = s.substring(i,i+1);
if(t.contains(st)) {
sb.append(t.get(st));
} else {
sb.append(st);
}
To get even cleaner code, your Map should from Character to String instead of <String,String>.

String.compareTo() returns 0 if the strings are equal, not 1. Read about it here
Note that for this case you don't need to convert the char to a string, you could do
if(c == ' ')

use
Character.isWhitespace(c)
that solves the issue. Best practice.

First, of all, what is s in this example? It's hard to follow the code. Then, your compareTo seems off:
if (st.compareTo(" ") == 1)
Should be
if (st.compareTo(" ") == 0)
since 0 means "equal" (read up on compareTo)

From the compareTo documentation: The result is a negative integer if this String object lexicographically precedes the argument string. The result is a positive integer if this String object lexicographically follows the argument string. The result is zero if the strings are equal;
You have the wrong condition in if (st.compareTo(" ") == 1) {

The compareTo method of a String returns -1 if the source string precedes the test string, 0 for equality, and 1 if the source string follows. Your code checks for 1, and it should be checking for 0.

Related

How to compare char with number in Java

I got a problem and I think it is in comparing a char with a number.
String FindCountry = "BB";
Map<String, String> Cont = new HashMap <> ();
Cont.put("BA-BE", "Angola");
Cont.put("9X-92", "Trinidad & Tobago");
for ( String key : Cont.keySet()) {
if (key.charAt(0) == FindCountry.charAt(0) && FindCountry.charAt(1) >= key.charAt(1) && FindCountry.charAt(1) <= key.charAt(4)) {
System.out.println("Country: "+ Cont.get(key));
}
}
In this case the code print "Angola", but if
String FindCountry = "9Z"
it doesn't print anything. I am not sure I think the problem is in that it can't compare that is '2' greater than 'Z'. In that example, I got only two Cont.put(), but in my file, I got much more and a lot of them are not only with chars. I got a problem with them.
What is the smartest and best way to compare char with a number ? Actually, if I set a rule like "1" is greater than "Z" it will be okay because I need this way of greater: A-Z-9-0.
Thanks!
You can use a lookup "table", I used a String:
private static final String LOOKUP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
And then compare the chars with indexOf(), but it seems messy and could probably be achieved more easily, I just can't come up with something easier at the moment:
String FindCountry = "9Z";
Map<String, String> Cont = new HashMap<>();
Cont.put("BA-BE", "Angola");
Cont.put("9X-92", "Trinidad & Tobago");
for (String key : Cont.keySet()) {
if (LOOKUP.indexOf(key.charAt(0)) == LOOKUP.indexOf(FindCountry.charAt(0)) &&
LOOKUP.indexOf(FindCountry.charAt(1)) >= LOOKUP.indexOf(key.charAt(1)) &&
LOOKUP.indexOf(FindCountry.charAt(1)) <= LOOKUP.indexOf(key.charAt(4))) {
System.out.println("Country: " + Cont.get(key));
}
}
If you only use the characters A-Z and 0-9, you could add a conversion method in between which will increase the values of the 0-9 characters so they'll be after A-Z:
int applyCharOrder(char c){
// If the character is a digit:
if(c < 58){
// Add 43 to put it after the 'Z' in terms of decimal unicode value:
return c + 43;
}
// If it's an uppercase letter instead: simply return it as is
return c;
}
Which can be used like this:
if(applyCharOrder(key.charAt(0)) == applyCharOrder(findCountry.charAt(0))
&& applyCharOrder(findCountry.charAt(1)) >= applyCharOrder(key.charAt(1))
&& applyCharOrder(findCountry.charAt(1)) <= applyCharOrder(key.charAt(4))){
System.out.println("Country: "+ cont.get(key));
}
Try it online.
Note: Here is a table with the decimal unicode values. Characters '0'-'9' will have the values 48-57 and 'A'-'Z' will have the values 65-90. So the < 58 is used to check if it's a digit-character, and the + 43 will increase the 48-57 to 91-100, putting their values above the 'A'-'Z' so your <= and >= checks will work as you'd want them to.
Alternatively, you could create a look-up String and use its index for the order:
int applyCharOrder(char c){
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".indexOf(c);
}
Try it online.
PS: As mentioned in the first comment by #Stultuske, variables are usually in camelCase, so they aren't starting with an uppercase letter.
As the others stated in the comments, such mathematical comparison operations on characters are based on the actual ASCII values of each char. So I'd suggest you refactor your logic using the ASCII table as reference.

Replacing a character in a string from another string with the same char index

I'm trying to search and reveal unknown characters in a string. Both strings are of length 12.
Example:
String s1 = "1x11222xx333";
String s2 = "111122223333"
The program should check for all unknowns in s1 represented by x|X and get the relevant chars in s2 and replace the x|X by the relevant char.
So far my code has replaced only the first x|X with the relevant char from s2 but printed duplicates for the rest of the unknowns with the char for the first x|X.
Here is my code:
String VoucherNumber = "1111x22xx333";
String VoucherRecord = "111122223333";
String testVoucher = null;
char x = 'x'|'X';
System.out.println(VoucherNumber); // including unknowns
//find x|X in the string VoucherNumber
for(int i = 0; i < VoucherNumber.length(); i++){
if (VoucherNumber.charAt(i) == x){
testVoucher = VoucherNumber.replace(VoucherNumber.charAt(i), VoucherRecord.charAt(i));
}
}
System.out.println(testVoucher); //after replacing unknowns
}
}
I am always a fan of using StringBuilders, so here's a solution using that:
private static String replaceUnknownChars(String strWithUnknownChars, String fullStr) {
StringBuilder sb = new StringBuilder(strWithUnknownChars);
while ((int index = Math.max(sb.toString().indexOf('x'), sb.toString().indexOf('X'))) != -1) {
sb.setCharAt(index, fullStr.charAt(index));
}
return sb.toString();
}
It's quite straightforward. You create a new string builder. While a x or X can still be found in the string builder (indexOf('X') != -1), get the index and setCharAt.
Your are using String.replace(char, char) the wrong way, the doc says
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar.
So you if you have more than one character, this will replace every one with the same value.
You need to "change" only the character at a specific spot, for this, the easiest is to use the char array that you can get with String.toCharArray, from this, this is you can use the same logic.
Of course, you can use String.indexOf to find the index of a specific character
Note : char c = 'x'|'X'; will not give you the expected result. This will do a binary operation giving a value that is not the one you want.
The OR will return 1 if one of the bit is 1.
0111 1000 (x)
0101 1000 (X)
OR
0111 1000 (x)
But the result will be an integer (every numeric operation return at minimum an integer, you can find more information about that)
You have two solution here, you either use two variable (or an array) or if you can, you use String.toLowerCase an use only char c = 'x'

compare 2 string in jave with special character

how to compare 2 string with special character?
I have the string as below, may I know how to compare both?
strA = "AC-11234X-DD+++1"
strB = "AC-11234X-DD+++1"
I tested matches(), equals(), equalsIgnoreCase() all not working.
if (strA.matches(strB)){
...
} else {
..
}
This code checks if those two strings are equal or not
String strA = "AC-11234X-DD+++1" ;
String strB = "AC-11234X-DD+++1";
if(strA.equals(strB))
//they are equal
else
//they are not
why dont you try for
System.out.println(strA.hashCode()==strB.hashCode());
if matches(), equals(), equalsIgnoreCase() are not working.
incase you are not satisfied with this result also, you could try to overwrite the compareTo method and have your own logic.
public static void main(String[] args)
{
String strA = "AC-11234X-DD+++1";
String strB = "AC-11234X-DD+++1";
System.out.println(strA.equals(strB));
}
This works perfectly.
Must use the compareTo method.
The value returned by this method is an int:
if it is > 0 means that the second string precedes the first in alphabetical order
if it is = 0 means that two string are equal;
if it is < 0 means that the fisrt string precedes the second in alphabetical order
An example (very rough) about your problem might be this:
int r = A.compareTo(B);
if(r > 0) {
System.out.println("B comes before A in alphabetical order");
} else if(r < 0) {
System.out.println("A comes before B string in alphabetical order");
} else {
System.out.println("The two strings are equal");
}

the sequence of one-line code of Reverse Words in a string on leetcode

I have a small question about one answer of this problem.
the problem is like
Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
The answer is
public class Solution {
public String reverseWords(String s) {
s = s.trim();
return helper(s,0).toString();}
private StringBuilder helper(String s, int index){
if(index>=s.length())
return new StringBuilder();
StringBuilder cur = new StringBuilder();
int lastIndex = index;
while(index < s.length() && s.charAt(index)!=' ')
{
cur.append(s.charAt(index++));
}
while(index < s.length() && s.charAt(index)==' ')
index++;
if(lastIndex == 0)
return helper(s,index).append(cur);
return helper(s,index).append(cur).append(' ');}
I got a question about the last line of this code. why append(cur) is before append(' ')? shouldn't it be after?
Consider this part of the code :
if(lastIndex == 0)
return helper(s,index).append(cur);
return helper(s,index).append(cur).append(' ');
The condition (lastIndex == 0) is true in the first call to helper, in which case cur contains the first word, and helper(s,index) returns the remaining words in reverse order.
Since you append, in this case, the first word to the rest of the reversed StringBuilder without adding a space, this means that helper(s,index) must append a space after the reversed sub-string.
For example, suppose you have a String :
One Two Three
helper(s,index) must return "Three Two ", to which you append "One" to get the reversed String.
The next call to helper would return "Three ", to which you append "Two" and then a space.
The next call returns an empty StringBuilder, to which you append "Three" and then a space.
You could replace the 3 lines above with this single line :
return helper(s,index).append(' ').append(cur);
However, in this case the output will have an extra space in the beginning, since the last call to helper returns an empty StringBuilder, so if you append a space after it, that space would be the first character of the output.
You can add a different condition to eliminate that extra space :
StringBuilder sub = helper(s,index);
if (sub.length() > 0)
sub.append(' '); // append a space only if it's not the
// first char of the output
return sub.append(cur);

String trim() method

In Java I have written below code for string trim() method.
if(" String ".trim() == "String")
System.out.println("Equal");
else
System.out.println("Not Equal");
It gives output Not Equals which I understood because " String ".trim() had returned new String object reference .
But when I trim and compare without white spaces it gives output Equals.
if("String".trim() == "String")
System.out.println("Equal");
else
System.out.println("Not Equal");
If String is not having white spaces what trim() method returns?
I know equals() I can use but in my exam I got this question.
Did you look at the API? This is clearly stated in documentation of trim() method:
Returns: A copy of this string with leading and trailing white space
removed, or this string if it has no leading or trailing white space.
You could have also gone through the source code. The trim() method returns this, if there are no whitespaces removed at either ends:
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
So, if both st > 0 and len < value.length are false, which would be case for strings that don't have whitespaces at either ends, it returns this.
Now, why "String" == "String" is true is by the virtue of String interning. You can get lot more information about this through google.
If the trim() method would do nothing (because the string is already trimmed), the same string object (ie this) is returned.
String interning means that the string constant "String" is the exact same object used throughout the code wherever "String" is used.
These two facts together is why == is true for the comparison of "String".trim() == "String".
The == operator checks if it is the same object.
To compare equality of the object, use .equals() method.
In your second case, the String which doesnt have whitespaces will no do anything to the Object. Hence it is equal, since the object is the same.

Categories