Cannot return modified String from static method - java

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.

Related

charAt(0) gives java.lang.StringIndexOutOfBoundsException

String.charAt(0) is giving java.lang.StringIndexOutOfBoundsException even though the String is not empty
public class Mainc {
public static void main(String[] args) {
int T;
Scanner inp = new Scanner(System.in);
Scanner inp2 = new Scanner(System.in);
T = inp.nextInt();
for (int i = 0; i < T; i++) {
String u = "";
String l = "";
String s = inp2.nextLine();
while (s != null) {
char ch = s.charAt(0);
if (Character.isLowerCase(ch))
l += ch;
else
u += ch;
s = s.substring(1);
}
if (u.length() > l.length())
System.out.println(u);
else
System.out.println(l);
}
}
}
It's supposed to give an all uppercase String or all lowercase String depending on which is bigger or an all uppercase String if they were both equal length but it gives runtime error java.lang.StringIndexOutOfBoundsException
even though the String is not empty and the charAt() function is at index 0. Thanks in advance.
Your while loop loops through the string s, checks each character, adds that character to u or l, and then removes it from s. But what happens when all the characters are removed? s is now empty, but the while loop still executes, because s is not null (null and the empty string are different things!) This means that you would call s.charAt(0) when s is empty, which causes the crash.
To fix this, you can change the while loop conditions to "s is not empty" instead. You don't need to check if s is null because it comes from Scanner.nextLine, which shouldn't return null.
while (!s.isEmpty()) {
char ch = s.charAt(0);
if (Character.isLowerCase(ch))
l += ch;
else u += ch;
s = s.substring(1);
}
You can improve your code further by not removing the character from s in each iteration. Instead, use a for loop with an index to loop through the string. Also, you should use a StringBuilder when concatenating strings in a loop. Both of these will avoid creating unnecessary string objects.
StringBuilder u = new StringBuilder(); // notice the change to StringBuilder here
StringBuilder l = new StringBuilder();
String s = inp2.nextLine();
for (int j = 0 ; j < s.length() ; j ++) {
char ch = s.charAt(j);
if (Character.isLowerCase(ch))
l.append(ch);
else u.append(ch);
}
even your s value is ""(blank) its still going in while loop as its not null after finish all chars so use length while(s.length() > 0) should work.
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
int T;
Scanner inp=new Scanner(System.in);
Scanner inp2=new Scanner(System.in);
T=inp.nextInt();
for(int i=0;i<T;i++){
String u=""; String l="";
String s=inp2.nextLine();
while(s.length() > 0){
char ch=s.charAt(0);
if(Character.isLowerCase(ch))
l+=ch;
else u+=ch;
s = s.substring(1);}
if(u.length()>l.length())
System.out.println(u);
else System.out.println(l);
}
}
}

Return a string that has been created in a for loop

The objective was to create a String toUppercase method if it did not exist. I got most of the code, but how do you return a string that has been created in a for loop?
public String toUpperCase(String str)
{
for (int i = 0; i > str.length; i++){
char a = str.charAt(i);
char b = Character.toUpperCase(a);
String t = Character.toString(b);
}
return t;
}
Declare t outside of the loop and assign with += inside the loop.
public String toUpperCase(String str)
{
String t = "";
for (int i = 0; i < str.length(); i++){
char a = str.charAt(i);
char b = Character.toUpperCase(a);
t += Character.toString(b);
}
return t;
}
That's what you'd do in case such a method didn't exist. Also next step would have been to take care of performance and heap impact may be using StringBuilder. But all these basic operations are already available in java.lang.String why re-invent the wheel?
You have to create an empty string outside the loop and then append the character to it with +=
Example:
public String toUpperCase (String str) {
String res = "";
for (int i = 0; i < str.length(); i++) {
char a = str.charAt(i);
char b = Character.toUpperCase(a);
res += Character.toString(b);
}
return res;
}
Are you trying to write this function ?
public String toUpperCase(String str)
{
String t = "";
for (int i = 0; i < str.length(); i++){
char a = str.charAt(i);
char b = Character.toUpperCase(a);
t = t + Character.toString(b);
}
return t;
}
A simple :
str.toUpperCase()
isn't enough ?
You need to move your accumulator (t) outside the loop and initialize it with an empty value. However, I would start by making the method static (since it doesn't use any instance data). Next, I would prefer a StringBuilder as my accumulator. And I would use String.toCharArray() so I could use an enhanced for-each loop. Like,
public static String toUpperCase(String str) {
StringBuilder sb = new StringBuilder();
for (char ch : str.toCharArray()) {
sb.append(Character.toUpperCase(ch));
}
return sb.toString();
}

Replace two strings without overriding the other value

I have an assignment for school due at midnight today. I have finished almost all the assignment except for one question. I need to swap "r" and "q" with each other as values. So, if you enter "r" in the compiler you should get "q" if you enter "q" you get "r"(Using JOptionPane). For example, if your name is Quart, the compiler should print Ruaqt. I tried using the replace.All method, but once I can only swap "r" or "q" not both. I know I need a temporary variable, but do not know anything else...
We had to replace vowels with the letter after them so I did this:
String firstName = JOptionPane
.showInputDialog("What is your first name?");
String lastName = JOptionPane
.showInputDialog("What is your last name?");
String fullname = firstname + lastname;
String lowername = fullName.toLowerCase();
String encryptedname = lowername.replaceAll("a", "b")
.replaceAll("e", "f").replaceAll("i", "j").replaceAll("o", "p")
.replaceAll("u", "v");
Thanks
Dunno why the 2 answers using StringBuilder are both making the thing more complicated than needed.
Here is the way you can use StringBuilder to do that single character swap:
public static String swapChar(String string, char c1, char c2) {
StringBuilder sb = new StringBuilder(string);
for (int i = 0; i < sb.length(); ++i) {
if (sb.charAt(i) == c1) {
sb.setCharAt(i, c2);
} else if (sb.charAt(i) == c2) {
sb.setCharAt(i, c1);
}
}
return sb.toString();
}
Update :
Just found that what you are looking for is actually doing a bunch of replace of character at the same time. That can be cleanly done by providing a Map as parameter:
public static String replaceChars(String string, Map<Character,Character> cmap) {
StringBuilder sb = new StringBuilder(string);
for (int i = 0; i < sb.length(); ++i) {
if (cmap.containsKey(sb.charAt(i)) {
sb.setCharAt(i, cmap.get(sb.charAt(i));
}
}
return sb.toString();
}
to use it:
// or make a util method to make these even easier to create
Map<Character,Character> cmap = new HashMap<Character,Character>();
cmap.put('r','q');
cmap.put('q','r');
cmap.put('a','b');
cmap.put('e','f');
cmap.put('i','j');
cmap.put('o','p');
cmap.put('u','v');
and simply do a replace:
String result = replaceChars(inputString, cmap);
or even simpler, by making use of Apache Commons Lang:
String result = StringUtils.replaceChars(inputString, "rqaeiou", "qrbfjpv");
You can try this.
private static final char Q_STR = 'q';
private static final char R_STR = 'r';
public static String replaceString(String original, int position, char strToReplace) {
StringBuilder strBuilder = new StringBuilder(original);
if (strToReplace == Q_STR) {
strBuilder.setCharAt(position, R_STR);
} else if (strToReplace == R_STR){
strBuilder.setCharAt(position, Q_STR);
}
return strBuilder.toString();
}
public static void main(String[] args) {
String firstname = "Quart";
String lastname = " QuartLastName";
String fullname = firstname + lastname;
String lowername = fullname.toLowerCase();
//get all chars in String
char[] array = lowername.toCharArray();
//list to keep original position of Q char
List<Integer> allQPosition = new ArrayList<Integer>();
//list to keep original position of R char
List<Integer> allRPosition = new ArrayList<Integer>();
for (int i = 0; i < array.length; i++) {
if(array[i] == 'q') {
allQPosition.add(i);
} else if(array[i] == 'r') {
allRPosition.add(i);
}
}
//replace q
for (Integer integer : allQPosition) {
lowername = replaceString(lowername, integer, Q_STR);
}
//replace r
for (Integer integer : allRPosition) {
lowername = replaceString(lowername, integer, R_STR);
}
//replace others
String encryptedname = lowername.replace("a", "b")
.replace("e", "f")
.replace("i", "j")
.replace("o", "p")
.replace("u", "v");
System.out.println("Result: " + encryptedname);
}
My solution is:
Keep all position of 'q' and 'r' from original String.
Replace each of them
Replace the rest of other chars
Hope this help
public static void main(String[] args) {
String origin = "r and q";
System.out.println(newReplacement(origin, 'r', 'q'));
}
private static String newReplacement(String origin, char firstChar, char secondChar) {
StringBuffer stringBuffer = new StringBuffer(origin);
for(int i = 0; i < origin.length(); i++) {
if(origin.charAt(i) == firstChar) {
stringBuffer.replace(i, i+1, secondChar + "");
continue;
}
if(origin.charAt(i) == secondChar) {
stringBuffer.replace(i, i+1, firstChar + "");
}
}
return stringBuffer.toString();
}
Rewrite replace method with simple one.

Replacing characters

I have a String entered by the User.
I'm trying to replace all non-uppercase letters(i.e. numbers, or symbols) with spaces without using methods such as replace(), Stringbuilders, or arrays.
This is what I have so far :
public static void formatPlaintext(String sentence){
String sentenceUpper = sentence.toUpperCase();
System.out.println(sentenceUpper);
String emptyString = " ";
for(int i = 0; i< sentenceUpper.length() ; i++){
char ch = sentenceUpper.charAt(i);
if(ch < 'A' || ch > 'Z'){
ch = emptyString.charAt(0);
}
}
}//end of formatPlaintext
I keep getting the error that String index is out of range. I believe it has to do with :
ch = emptyString.charAt(0);
because emptyString doesn't have any characters. But even if I put an arbitrary constant in, it doesn't replace the non-letters with this arbitrary constant.
This isn't how you replace characters in a Java string. In Java, strings are immutable, so you can't set any given index. Additionally, the charAt() method doesn't and can't do anything to the string you're calling it on - all it does is just return the char at that position. Lastly, you probably shouldn't be using void - return the String with characters replaced at the end of the method, then use the return value. You can accomplish this by iterating through your initial string and build a new string, using the static isUpperCase method of the Character class:
public static String formatPlainText(String sentence)
{
String replacedSentence = "";
for(int i = 0; i< sentence.length() ; i++){
char ch = sentence.charAt(i);
if (Character.isUpperCase(ch)) {
replacedSentence += ch;
}
else {
replacedSentence += " ";
}
}
return replacedSentence;
}
If you're going to be using this frequently, or for particularly long Strings, you should absolutely use a StringBuilder instead - concatenating String on a character-by-character basis is deeply inefficient.
You have to remember that arguments in Java are passed as values, not as references, and in this case the String is an immutable object, i.e. an String cannot be changed, when you do a concatenation or replace you're effectively creating a new String.
What I would recommend is to modify your code a little bit to return the new String that was built.
public static String formatPlaintext(String sentence){
String sentenceUpper = sentence.toUpperCase();
System.out.println(sentenceUpper);
StringBuilder builder = new StringBuilder;
for(int i = 0; i< sentenceUpper.length() ; i++){
char ch = sentenceUpper.charAt(i);
if(ch < 'A' || ch > 'Z'){
builder.append(' ');
} else {
builder.append(ch);
}
}
return builder.toString();
}

Getting String from StringBuilder

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.

Categories

Resources