Taking your code and adapting it by following up on Kevin Anderson's comment, this seems to do what you're looking for:
Scanner sc = new Scanner(System.in);
String str="b5l*a+i";
StringBuffer sb=new StringBuffer(str);
for(int i=0;i<sb.length();i++)
{
for(int j='a';j<='z';j++)
{
if(sb.charAt(i)==j)
{
System.out.println("Enter value for "+(char)j);
int ip=sc.nextInt();
sb.deleteCharAt(i);
sb.insert(i, ip);
}
}
}
Might I also suggest this code which would behave similarly?
Scanner sc = new Scanner(System.in);
String str="b5l*a+i";
StringBuffer sb=new StringBuffer(str);
for(int i=0;i<sb.length();i++)
{
char original = sb.charAt(i);
if(original >= 'a' && original <= 'z')
{
System.out.println("Enter value for "+original);
int ip=sc.nextInt();
sb.deleteCharAt(i);
sb.insert(i, ip);
}
}
It should be more efficient, as it will not have to loop through the characters.
EDIT
After seeing @Sebastien's excellent answer, and applying some more of my own changes, I believe the following is an even better solution than the above ones, if it fits your project's constraints.
Scanner sc = new Scanner(System.in);
String str = "b5l*a+i";
Matcher matcher = Pattern.compile("[a-z]").matcher(str);
StringBuilder sb = new StringBuilder(str);
while (matcher.find())
{
System.out.println("Enter value for " + matcher.group());
int ip = sc.nextInt();
sb.setCharAt(matcher.start(), Character.forDigit(ip, 10));
}
Here is what is better:
- Pattern matching with regular expressions. This way you don't need to manually search through each character of the
String
and check if it is a letter, then decide what to do with it. You can let the Matcher
do that for you. The regular expression [a-z]
means "exactly one character in the range of a to z. The matcher.find()
method returns true
each time it finds a new match for that expression as it moves through the String
, and false
when there are no more. Then, matcher.group()
gets the character from the past find()
operation (as a String
, but that doesn't matter to us). matcher.start()
gets the index for the match (the methods are named start()
and end()
because a typical match will be more than one character and have a start and end index, but only start()
matters to us).
Switched to StringBuilder
. StringBuilder
is considered the newer implementation of what StringBuffer
was designed for. It is generally preferred to use StringBuilder
, unless you need your application to be thread-safe (which you don't, unless you know for sure that you specifically do need it to be). In our case, it also makes the action a lot easier by providing the setCharAt
method, which does exactly what we need to do. Now we can just plop in the index of the char
we intend to change (which the Matcher
so conveniently provides us with), and the new character we got from the input. We must first make a character out of the int, using the convenient static method of the Character
class, forDigit
. The first part is the digit we read from input, and the second bit is the radix, which it needs to know to determine the digit's validity (for example, in base-10, the input 10
will be invalid, but in base-16, hexadecimal, it will return 'a'
), in our case we put 10, because base-10 is the most common English number system. If the input is invalid (i.e. more than one base-10 digit, like 10
, or less than 0), it will return a null character, so you may want to pop that out of the forDigit
argument and first check if it is null, and handle input accordingly, something like the following:
char ipChar = Character.forDigit(ip, 10);
if (ipChar == '\u0000') throw new MyCustomNotADigitException("error message");
sb.setCharAt(matcher.start(), ipChar);