How to replace all numeric characters with a specific value? - java

I want to replace all numbers inside a string with specific values.
Teststring: -SD12431;ABC333
How can I identify blocks of digits, and especially replace them with a (dynamic) new value?
For example after replacement:
-SDfirst;ABCsecond?

The replaceFirst() method will let you do this if you use it in a loop.
String myNewString = myString.replaceFirst("\\d+","first");
If you loop over the this statement, each invocation of replaceFirst() will replace the first group of digits with whatever you provide as a second argument.

You can do it this way
StringBuffer sb = new StringBuffer();
Matcher m = Pattern.compile("\\d+").matcher(str);
int n = 0;
while(m.find()) {
if (++n == 1) {
m.appendReplacement(sb, "first");
} else {
m.appendReplacement(sb, "second");
}
}
m.appendTail(sb);
s = sb.toString();

You can do something like this:
yourString = yourString.replaceFirst("\\d+",firstString).replaceFirst("\\d+",secondString); //and so on
or use a loop if it fits your needs better

You can use the replaceFirst(String regex, String replacement) function of the string class.
Look at
http://javarevisited.blogspot.fr/2011/12/java-string-replace-example-tutorial.html
So in first argument you have to use a regex for finding digit such as :
"[0-9]" will find a single digit
"[0-9]+" will find one or more digit
String testString = "-SD12431;ABC333";
ArrayList<String> remplaceBy= new ArrayList<String>();
remplaceBy.add("first");
remplaceBy.add("second");
remplaceBy.add("third");
String newString = testString;
String oldString ="";
int i =0;
while(!newString.equals(oldString))
{
oldString = new String(newString);
newString = newString.replaceFirst("[0-9]+",remplaceBy.get(i));
i++;
System.out.println("N1:"+newString);
System.out.println("O1:"+oldString);
}
System.out.println("New String"+newString);

Related

How would I replace this function with a regex replace

I have a file name with this format yy_MM_someRandomString_originalFileName.
example:
02_01_fEa3129E_my Pic.png
I want replace the first 2 underscores with / so that the example becomes:
02/01/fEa3129E_my Pic.png
That can be done with replaceAll, but the problem is that files may contain underscores as well.
#Test
void test() {
final var input = "02_01_fEa3129E_my Pic.png";
final var formatted = replaceNMatches(input, "_", "/", 2);
assertEquals("02/01/fEa3129E_my Pic.png", formatted);
}
private String replaceNMatches(String input, String regex,
String replacement, int numberOfTimes) {
for (int i = 0; i < numberOfTimes; i++) {
input = input.replaceFirst(regex, replacement);
}
return input;
}
I solved this using a loop, but is there a pure regex way to do this?
EDIT: this way should be able to let me change a parameter and increase the amount of underscores from 2 to n.
You could use 2 capturing groups and use those in the replacement where the match of the _ will be replaced by /
^([^_]+)_([^_]+)_
Replace with:
$1/$2/
Regex demo | Java demo
For example:
String regex = "^([^_]+)_([^_]+)_";
String string = "02_01_fEa3129E_my Pic.png";
String subst = "$1/$2/";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
String result = matcher.replaceFirst(subst);
System.out.println(result);
Result
02/01/fEa3129E_my Pic.png
Your current solution has few problems:
It is inefficient - because each replaceFirst need to start from beginning of string so it needs to iterate over same starting characters many times.
It has a bug - because of point 1. while iterating from beginning instead of last modified place, we can replace value which was inserted previously.
For instance if we want to replace single character two times, each with X like abc -> XXc after code like
String input = "abc";
input = input.replaceFirst(".", "X"); // replaces a with X -> Xbc
input = input.replaceFirst(".", "X"); // replaces X with X -> Xbc
we will end up with Xbc instead of XXc because second replaceFirst will replace X with X instead of b with X.
To avoid that kind of problems you can rewrite your code to use Matcher#appendReplacement and Matcher#appendTail methods which ensures that we will iterate over input once and can replace each matched part with value we want
private static String replaceNMatches(String input, String regex,
String replacement, int numberOfTimes) {
Matcher m = Pattern.compile(regex).matcher(input);
StringBuilder sb = new StringBuilder();
int i = 0;
while(i++ < numberOfTimes && m.find() ){
m.appendReplacement(sb, replacement); // replaces currently matched part with replacement,
// and writes replaced version to StringBuilder
// along with text before the match
}
m.appendTail(sb); //lets add to builder text after last match
return sb.toString();
}
Usage example:
System.out.println(replaceNMatches("abcdefgh", "[efgh]", "X", 2)); //abcdXXgh

Replace words in parenthesis

I have a question about replacing words. I have some strings, each of which looks like this:
String string = "today is a (happy) day, I would like to (explore) more about Java."
I need to replace the words that have parentheses. I want to replace "(happy)" with "good", and "(explore)" with "learn".
I have some ideas, but I don't know how.
for (int i = 0; i <= string.length(), i++) {
for (int j = 0; j <= string.length(), j++
if ((string.charAt(i)== '(') && (string.charAt(j) == ')')) {
String w1 = line.substring(i+1,j);
string.replace(w1, w2)
}
}
}
My problem is that I can only replace one word with one new word...
I am thinking of using a scanner to prompt me to give a new word and then replace it, how can I do this?
The appendReplacement and appendTail methods of Matcher are designed for this purpose. You can use a regex to scan for your pattern--a pair of parentheses with a word in the middle--then do whatever you need to do to determine the string to replace it with. See the javadoc.
An example, based on the example in the javadoc. I'm assuming you have two methods, replacement(word) that tells what you want to replace the word with (so that replacement("happy") will equal "good" in your example), and hasReplacement(word) that tells whether the word has a replacement or not.
Pattern p = Pattern.compile("\\((.*?)\\)");
Matcher m = p.matcher(source);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String word = m.group(1);
String newWord = hasReplacement(word) ? replacement(word) : m.group(0);
m.appendReplacement(sb, newWord); // appends the replacement, plus any not-yet-used text that comes before the match
}
m.appendTail(sb); // appends any text left over after the last match
String result = sb.toString();
Use below code for replacing the string.
String string = "today is a (happy) day, I would like to (explore) more about Java.";
string = string.replaceAll("\\(happy\\)", "good");
string = string.replaceAll("\\(explore\\)", "learn");
System.out.println(string);`
What you can do is run a loop from 0 to length-1 and if loop encounters a ( then assign its index to a temp1 variable. Now go on further as long as you encounter ).Assign its index to temp2 .Now you can replace that substring using string.replace(string.substring(temp1+1,temp2),"Your desired string")).
No need to use the nested loops. Better use one loop and store the index when you find opening parenthesis and also for close parenthesis and replace it with the word. Continue the same loop and store next index. As you are replacing the words in same string it changes the length of string you need to maintain copy of string and perform loop and replace on different,
Do not use nested for loop. Search for occurrences of ( and ). Get the substring between these two characters and then replace it with the user entered value. Do it till there are not more ( and ) combinations left.
import java.util.Scanner;
public class ReplaceWords {
public static String replaceWords(String s){
while(s.contains(""+"(") && s.contains(""+")")){
Scanner keyboard = new Scanner(System.in);
String toBeReplaced = s.substring(s.indexOf("("), s.indexOf(")")+1);
System.out.println("Enter the word with which you want to replace "+toBeReplaced+" : ");
String replaceWith = keyboard.nextLine();
s = s.replace(toBeReplaced, replaceWith);
}
return s;
}
public static void main(String[] args) {
String myString ="today is a (happy) day, I would like to (explore) more about Java.";
myString = replaceWords(myString);
System.out.println(myString);
}
}
This snippet works for me, just load the HashMap up with replacements and iterate through:
import java.util.*;
public class Test
{
public static void main(String[] args) {
String string = "today is a (happy) day, I would like to (explore) more about Java.";
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("\\(happy\\)", "good");
hm.put("\\(explore\\)", "learn");
for (Map.Entry<String, String> entry : hm.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
string = string.replaceAll(key, value);
}
System.out.println(string);
}
}
Remember, replaceAll takes a regex, so you want it to display "\(word\)", which means the slashes themselves must be escaped.

How to split a string by every other separator

There's a string
String str = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
How do I split it into strings like this
"ggg;ggg;"
"nnn;nnn;"
"aaa;aaa;"
"xxx;xxx;"
???????
Using Regex
String input = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
Pattern p = Pattern.compile("([a-z]{3});\\1;");
Matcher m = p.matcher(input);
while (m.find())
// m.group(0) is the result
System.out.println(m.group(0));
Will output
ggg;ggg;
nnn;nnn;
aaa;aaa;
xxx;xxx;
I assume that the you only want to check if the last segment is similar and not every segment that has been read.
If that is not the case then you would probably have to use an ArrayList instead of a Stack.
I also assumed that each segment has the format /([a-z])\1\1/.
If that is not the case either then you should change the if statement with:
(stack.peek().substring(0,index).equals(temp))
public static Stack<String> splitString(String text, char split) {
Stack<String> stack = new Stack<String>();
int index = text.indexOf(split);
while (index != -1) {
String temp = text.substring(0, index);
if (!stack.isEmpty()) {
if (stack.peek().charAt(0) == temp.charAt(0)) {
temp = stack.pop() + split + temp;
}
}
stack.push(temp);
text = text.substring(index + 1);
index = text.indexOf(split);
}
return stack;
}
Split and join them.
public static void main(String[] args) throws Exception {
String data = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
String del = ";";
int splitSize = 2;
StringBuilder sb = new StringBuilder();
for (Iterable<String> iterable : Iterables.partition(Splitter.on(del).split(data), splitSize)) {
sb.append("\"").append(Joiner.on(del).join(iterable)).append(";\"");
}
sb.delete(sb.length()-3, sb.length());
System.out.println(sb.toString());
}
Ref : Split a String at every 3rd comma in Java
Use split with a regex:
String data="ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
String [] array=data.split("(?<=\\G\\S\\S\\S;\\S\\S\\S);");
S: A non-whitespace character
G: last match/start of string, think of it of a way to skip delimiting if the
previous string matches current one.
?<=:positive look-behind will match semicolon which has string behind it.
Some other answer, that only works given your specific example input.
You see, in your example, there are two similarities:
All patterns seem to have exactly three characters
All patterns occur exactly twice
In other words: if those two properties are really met for all your input, you could avoid splitting - as you know exactly what to find in each position of your string.
Of course, following the other answers for "real" splitting are more flexible; but (theoretically), you could just go forward and do a bunch of substring calls in order to directly access all elements.

How to extract integers from a complicated string?

I am having a hard time figuring with out. Say I have String like this
String s could equal
s = "{1,4,204,3}"
at another time it could equal
s = "&5,3,5,20&"
or it could equal at another time
s = "/4,2,41,23/"
Is there any way I could just extract the numbers out of this string and make a char array for example?
You can use regex for this sample:
String s = "&5,3,5,20&";
System.out.println(s.replaceAll("[^0-9,]", ""));
result:
5,3,5,20
It will replace all the non word except numbers and commas. If you want to extract all the number you can just call split method -> String [] sArray = s.split(","); and iterate to all the array to extract all the number between commas.
You can use RegEx and extract all the digits from the string.
stringWithOnlyNumbers = str.replaceAll("[^\\d,]+","");
After this you can use split() using deliminator ',' to get the numbers in an array.
I think split() with replace() must help you with that
Use regular expressions
String a = "asdf4sdf5323ki";
String regex = "([0-9]*)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(a);
while (matcher.find())
{
String group = matcher.group(1);
if (group.length() > 0)
{
System.out.println(group);
}
}
from your cases, if the pattern of string is same in all cases, then something like below would work, check for any exceptions, not mentioned here :
String[] sArr= s.split(",");
sArr[0] = sArr[0].substring(1);
sArr[sArr.length()-1] =sArr[sArr.length()-1].substring(0,sArr[sArr.length()-1].length()-1);
then convert the String[] to char[] , here is an example converter method
You can use Scanner class with , delimiter
String s = "{1,4,204,3}";
Scanner in = new Scanner(s.substring(1, s.length() - 1)); // Will scan the 1,4,204,3 part
in.useDelimiter(",");
while(in.hasNextInt()){
int x = in.nextInt();
System.out.print(x + " ");
// do something with x
}
The above will print:
1 4 204 3

Regex to remove spaces inside quoted text

I need to remove all white space only within quoted sections of a string.
Give this:
10 00,400,"a1 b2 c3 ",zz xx,100
I need this:
10 00,400,"a1b2c3",zz xx,100
Obviously, restricting it to quoted areas only is why I'm having trouble.
The strings will vary in length and can have multiple quoted sections.
Doesn't use regex - but works
public String replaceWithinQuotes(String input) {
String[] output = input.split("\"");
StringBuilder builder = new StringBuilder();
for ( int i =0; i < output.length-1; i++ ) {
if ( i %2 == 0 ) {
builder.append(output[i]);
} else {
builder.append(output[i].replaceAll("[ ]+", ""));
}
builder.append("\"");
}
builder.append(output[output.length-1]);
return builder.toString();
}
Note - If you are using this - make sure length of the array is odd. If it is not, then you have unbalanced quotes and you have to handle that in whatever way is appropriate for your application.
Assuming that the quotes are balanced, then you could implement a method like this:
public static void main(String[] args) {
String str = "10 00,400,\"a1 b2 c3 \",zz xx,100, \"a b\"";
StringBuffer sb = new StringBuffer();
Matcher matcher = Pattern.compile("\"([^\"]+)\"").matcher(str);
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group().replaceAll("\\s+", ""));
}
System.out.println(sb.toString());
}
This prints:
10 00,400,"a1b2c3",zz xx,100, "ab"
Here is a small routine that seems to work just fine when there is a single set of quotes in the text:
public static String cropSpacesWithinQuotes(String expression) {
Pattern pattern = Pattern.compile("\"[\\S*\\s\\S*]*\"");
StringBuilder noSpaces=new StringBuilder();
int initialPosition=0;
Matcher matcher = pattern.matcher(expression);
while (matcher.find(initialPosition)) {
int pos=matcher.start();
noSpaces.append(expression.substring(initialPosition, pos-initialPosition));
initialPosition=matcher.end();
noSpaces.append(matcher.group().replaceAll(" ", ""));
}
noSpaces.append(expression.substring(initialPosition));
return(noSpaces.toString());
}
Performing some unit tests I realized that when there is more that one pair of quotes the text within the two sets also has its spaces cropped. Some manipulation on the variable initialPosition should solve your problem.
I hope this helps.

Categories

Resources