Java String += Shorthand explanation needed - java

While I was creating a program to compress a string I ran into this strange problem, I will paste the code snippets with their outputs, I would like someone to clearly explain why this is happening.
The first code snippet: here if same letter appears consecutively, then the successive occurrences of the letter is replaced by the total count of same letters. Ex: aaabbb should be written as a3b3.
public static String compress(String str){
String compressed = "";
char prev = str.charAt(0);
int count = 1;
for (int i = 1; i < str.length(); i++) {
char curr = str.charAt(i);
if (curr == prev) { // in case curr is equal to prev
count++;
} else { // in case curr is not equal to prev
//compressed=compressed+prev+count;
compressed+=prev+count; // Shorthand used here
count=1;
prev=curr;
}
}
compressed=compressed+prev+count; // Shorthand not used
System.out.println(compressed);
return compressed;
}
the output for this above code when inputted with aabbccaabbccaabbccaabb is 99100101991001019910010199b2, observe the last two elements of the output, this is because outside the loop, shorthand is not used. If I write the expression as compressed = compressed +prev+count inside the loop, I'll get the intended output.
I thought this output is because the operation is messing with the address of the String. But the next code confused me again.
String prev= "abc";
String curr = "def";
String result="";
result+=prev+curr;
System.out.println(result);
I think this is because the right hand operation is performing an ASCII addition, I cannot come to a conclusion, can anyone clarify.
I am sleep deprived and hence I am not able to come to a conclusion, hence asking someone to clarify my trivial doubt.

It has nothing to do with the reference. When you did prev+count ascii value of the character in prev is added with the integer count. In this case :
ascii of "a" is 97, and it occurred twice... so 97 +2 = 99 ..
ascii of "b" is 98, and it occurred twice... so 98 +2 = 100 ..
ascii of "c" is 99, and it occurred twice... so 99 +2 = 101 ..
that's why the output is 99100101991001019910010199100
try this : compressed+=(""+prev)+count; // Shorthand used here
In this case, or in compressed+=""+prev+count case, since the operation happens from left to right, the + operator is applied on a string ("") and char(prev) and behaves like append and also returns a string. The resulting string is then appened with another int (prev)
A better way is using a StringBuilder

Take a look at this subject and at JLS 15.18.1 section :
You see this behavior as a result of the combination of operator
precedence and string conversion.
JLS 15.18.1 states:
If only one operand expression is of type String, then string conversion (§5.1.11) is performed on the other operand to produce a
string at run time.
Therefore the right hand operands in your first expression are
implicitly converted to string: string = string + ((char)65) + 5;
For the second expression however string += ((char)65) + 5; the +=
compound assignment operator has to be considered along with +.
Since += is weaker than +, the + operator is evaluated first.
There we have a char and an int which results in a binary numeric
promotion to int. Only then += is evaluated, but at this time
the result of the expression involving the + operator has already been evaluated.

Whenever you add a char to an int in java first it converts the character into its equivalent ASCII value and then adds it to the integer
eg suppose the following scenario ,
char c = 'a'; // ASCII value of 'a' is 97
int i = c + 5 ; // result will be 97 + 5 = 102
I think this answers your first half question
Now the Second part ,
Whenever you use the shorthand operator in Java the expression at right hand side is evaluated first.
Hence , for expresion
result += prev + curr it is evaluated as
result = result + (prev + curr);
Therefore ,
result+=prev+curr; // Here first it appends "abc" with "def" and then the resultant "abcdef" is appended to as result .

you can convert your charater value "prev" to string and than append count to it.
compressed += Character.toString(prev) + count;

Related

How to insert spaces into binary String if binary number changes

I want to change this binary string "100110001" into "1 00 11 000 1".
I tried finding the answer to that and had no luck finding it. I've tried to approach this problem using split() method.
You can use split() but you need a regex that identifies the correct points to split. Afterward, you can combine the parts again with a space in between:
String input = "100110001";
String result = String. join(" ", input.split("(?<=(.))(?!\\1)"));
System.out.println(result);
Output:
1 00 11 000 1
Edit: The regex simply checks if the current character is not occurring again in the next position. If the character is not occurring back to back we want to split.
It can be done without need to resort to regular expressions by utilizing a plain for loop and StringBuilder in a single pass through the given string, i.e. in O(n) time.
This approach is more simple but a bit more verbose than regex-based solution. The overall performance is almost the same.
The logic:
cut out cases when the given string contains less than two characters;
declare a local variable prev that will store a character at the previous position and initialize it with the first character of the given string;
iterate though the given string and in every case when previous and next characters don't match append an empty space to the result.
The code might look like this:
public static String insertSpaces(String source) {
if (source.length() < 2) { // space can't be inserted
return source;
}
StringBuilder result = new StringBuilder();
char prev = source.charAt(0);
for (int i = 0; i < source.length(); i++) {
char next = source.charAt(i);
if (next != prev) {
result.append(" ");
prev = next;
}
result.append(next);
}
return result.toString();
}
main()
public static void main(String[] args) {
String source = "100110001";
System.out.println(insertSpaces(source));
}
output
1 00 11 000 1

What happens when if statement goes true (in this code)?

There is a problem in codingbat.com which you're supposed to remove "yak" substring from the original string. and they provided a solution for that which I can't understand what happens when the if statement goes true!
public String stringYak(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Look for i starting a "yak" -- advance i in that case
if (i+2<str.length() && str.charAt(i)=='y' && str.charAt(i+2)=='k') {
i = i + 2;
} else { // Otherwise do the normal append
result = result + str.charAt(i);
}
}
return result;
}
It just adds up i by 2 and what? When it appends to the result string?
Link of the problem:
https://codingbat.com/prob/p126212
The provided solution checks for all single characters in the input string. For this i is the current index of the checked character. When the current char is not a y and also the (i+2) character is not a k the current char index is advanced by 1 position.
Example:
yakpak
012345
i
So here in the first iteration the char at i is y and i+2 is a k, so we have to skip 3 chars. Keep in mind i is advanced by 1 everytime. So i has to be increased by 2 more. After this iteration i is here
yakpak
012345
i
So now the current char is no y and this char will get added to the result string.
But it's even simpler in Java as this functionality is build in with regex:
public String stringYak(String str) {
return str.replaceAll("y.k","");
}
The . means every char.
If i is pointing at a y and there is as k two positions down, then it wants to skip the full y*k substring, so it add 2 to i so i now refers to the k. WHen then loop continues, i++ will skip past the k, so in effect, the entire 3-letter y*k substring has been skipped.

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'

Can't convert to char in ? : operator

I want to give user with 2 choices which are whether reading the node in alphabets or numbers. It will say something like "From node A to B" or "From node 1 to 2". So I wrote codes like the //2 code(I want to make it simple so I let the condition to be "true"). But the result is "66" instead of "B". However, the //1 code works fine. How can I wrote the code that allows me to change the letter and display correctly the way I want? Thanks.
System.out.println(true?(char)(65+1):65);//1
int a=65;
System.out.println(true?(char)(65+1):a);//2
Results
B
66
*Try to make it clearer: I want to make a loop to print out
From node A to node B
From node A to node C
From node A to node D
...
So I will write
for (int i=1;i<26;i++)System.out.println("From node A to node "+ (char)(65+i));
But I also want to make it able to print out this if user decide to:
From node 1 to node 2
From node 1 to node 3
From node 1 to node 4
...
So, I make a question about the format the user wants as a boolean format variable. And I edit the code to be
boolean format=true;//I simplify it
for (int i=1;i<26;i++)System.out.println("From node "+(format?"A":1)+ " to node "+ (format?(char)(65+i):i));
Here is there result
From node A to node 66
From node A to node 67
From node A to node 68
...
This is not what I want. It should be "From node A to node B", etc...
I changed the short type in //2 to int as recommended, but it(type) is not the point I'm asking. So please don't mind it.
I can't understand what you're trying to achieve (and why you're using short variables), but the behavior you're observing is explained in the Java Language Specification:
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.
That explains what you see in the first example: 65 is a constant expression of type int, (char)(65+1) is a char, and the type of the ternary expression is thus char.
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.
That explains what you see in the second example: one is of type short and the other is of type char: they're both promoted to int and the result is thus of type int.
To do what you want to achieve, I'd do something like:
private String formatNode(int node) {
return formatAsInteger ? Integer.toString(node + 1) : Character.toString((char) (node + 'A'));
}
// ...
for (int i = 1; i < 26; i++) {
System.out.println("From node " + formatNode(0) + " to node " + formatNode(i));
}
There are two problems in your code, different types for the second and third expressions in the ?:, and dead code due to the use of true. I fixed the first problem two different ways. The first println selects between two int expressions, and casts the result to char. The second cases each of the selected expressions. I fixed the second problem by using a boolean whose value the compiler does not know.
public class Test {
public static void main(String[] args) {
boolean test = args.length < 1;
System.out.println((char) (test ? (65 + 1) : 65));
System.out.println(test ? (char) (65 + 1) : (char) 65);
}
}
Try :
System.out.println(true?(char)(65+1):65);//1
char a=65;
System.out.println(true?(char)(65+1):a);//2
If I understand your question correctly, this is what you should write:
System.out.println((char)(false?(65+1):65));
You need to cast the result.

Comparing String Integers Issue

I have a scanner that reads a 7 character alphanumeric code (inputted by the user). the String variable is called "code".
The last character of the code (7th character, 6th index) MUST BE NUMERIC, while the rest may be either numeric or alphabetical.
So, I sought ought to make a catch, which would stop the rest of the method from executing if the last character in the code was anything but a number (from 0 - 9).
However, my code does not work as expected, seeing as even if my code ends in an integer between 0 and 9, the if statement will be met, and print out "last character in code is non-numerical).
example code: 45m4av7
CharacterAtEnd prints out as the string character 7, as it should.
however my program still tells me my code ends non-numerically.
I'm aware that my number values are string characters, but it shouldnt matter, should it?
also I apparently cannot compare actual integer values with an "|", which is mainly why im using String.valueOf, and taking the string characters of 0-9.
String characterAtEnd = String.valueOf(code.charAt(code.length()-1));
System.out.println(characterAtEnd);
if(!characterAtEnd.equals(String.valueOf(0|1|2|3|4|5|6|7|8|9))){
System.out.println("INVALID CRC CODE: last character in code in non-numerical.");
System.exit(0);
I cannot for the life of me, figure out why my program is telling me my code (that has a 7 at the end) ends non-numerically. It should skip the if statement and continue on. right?
The String contains method will work here:
String digits = "0123456789";
digits.contains(characterAtEnd); // true if ends with digit, false otherwise
String.valueOf(0|1|2|3|4|5|6|7|8|9) is actually "15", which of course can never be equal to the last character. This should make sense, because 0|1|2|3|4|5|6|7|8|9 evaluates to 15 using integer math, which then gets converted to a String.
Alternatively, try this:
String code = "45m4av7";
char characterAtEnd = code.charAt(code.length() - 1);
System.out.println(characterAtEnd);
if(characterAtEnd < '0' || characterAtEnd > '9'){
System.out.println("INVALID CRC CODE: last character in code in non-numerical.");
System.exit(0);
}
You are doing bitwise operations here: if(!characterAtEnd.equals(String.valueOf(0|1|2|3|4|5|6|7|8|9)))
Check out the difference between | and ||
This bit of code should accomplish your task using regular expressions:
String code = "45m4av7";
if (!code.matches("^.+?\\d$")){
System.out.println("INVALID CRC CODE");
}
Also, for reference, this method sometimes comes in handy in similar situations:
/* returns true if someString actually ends with the specified suffix */
someString.endsWith(suffix);
As .endswith(suffix) does not take regular expressions, if you wanted to go through all possible lower-case alphabet values, you'd need to do something like this:
/* ASCII approach */
String s = "hello";
boolean endsInLetter = false;
for (int i = 97; i <= 122; i++) {
if (s.endsWith(String.valueOf(Character.toChars(i)))) {
endsInLetter = true;
}
}
System.out.println(endsInLetter);
/* String approach */
String alphabet = "abcdefghijklmnopqrstuvwxyz";
boolean endsInLetter2 = false;
for (int i = 0; i < alphabet.length(); i++) {
if (s.endsWith(String.valueOf(alphabet.charAt(i)))) {
endsInLetter2 = true;
}
}
System.out.println(endsInLetter2);
Note that neither of the aforementioned approaches are a good idea - they are clunky and rather inefficient.
Going off of the ASCII approach, you could even do something like this:
ASCII reference : http://www.asciitable.com/
int i = (int)code.charAt(code.length() - 1);
/* Corresponding ASCII values to digits */
if(i <= 57 && i >= 48){
System.out.println("Last char is a digit!");
}
If you want a one-liner, stick to regular expressions, for example:
System.out.println((!code.matches("^.+?\\d$")? "Invalid CRC Code" : "Valid CRC Code"));
I hope this helps!

Categories