fastest way for replacing i-th occurance in a string - java

I have a string which consists of total n equal substrings. For example, string "hellooo dddd" has 3 "dd" substrings (I say it has occured 3 times). In a more general case which we have n equal substrings in a string, how can I replace i-th occurance in the string. A ,method like replace() for i-th substring. I want to implement it in my android code. (English isn’t my first language, so please excuse any mistakes.).

public static String replace(String input, String pattern, int occurence, String replacement){
String result = input;
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(result);
if(occurence == 0){
return result;
} else if(occurence == 1){
m.find();
result = result.substring(0,m.start()) + replacement + result.substring(m.end());
} else {
m.find();
int counter = 1;
try {
while((counter<occurence)&&m.find(m.start()+1)){
counter++;
}
result = result.substring(0,m.start()) + replacement + result.substring(m.end());
} catch(IllegalStateException ise){
throw new IllegalArgumentException("There are not this many occurences of the pattern in the String.");
}
}
return result;
}
Seems to do something similar to what you want if I understand correctly.
Using the matcher/pattern system it's open to much more complex regex.

Related

A function which increments a string, to create a new string

write a function which increments a string, to create a new string.
If the string already ends with a number, the number should be incremented by 1.
If the string does not end with a number. the number 1 should be appended to the new string.
Examples:
foo - foo1
foobar23 - foobar24
foo0042 - foo0043
foo9 - foo10
foo099 - foo100
Attention: If the number has leading zeros the amount of digits should be considered.
The program passed tests on the CodeWars platform, except for one
For input string: "1712031362069931272877416673"
she falls on it
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
but in IJ it works correctly ...
Any idea why?
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
System.out.println(incrementString("foo001"));
System.out.println(incrementString("33275375531813209960"));
System.out.println(incrementString("0000004617702678077138438340108"));
}
public static String incrementString(String str) {
boolean isNumeric = str.chars().allMatch( Character::isDigit );
if(str.isEmpty())
return "1";
else if (isNumeric) {
BigInteger b = new BigInteger(str);
return String.format("%0"+str.length() + "d",b.add(BigInteger.valueOf(1)));
}
String timeRegex = "(.*)(\\D)([0-9]*)";
Pattern pattern = Pattern.compile(timeRegex);
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
String sec = matcher.group(3);
StringBuilder sb = new StringBuilder();
if (sec.isEmpty()) {
sec = "0";
return str + sb+(Integer.parseInt(sec) + 1);
} else {
int length = String.valueOf(Integer.parseInt(sec) + 1).length();
if (sec.length() > length) {
for (int i = length; i < sec.length(); i++) {
sb.append("0");
}
}
return str.substring(0,str.length() - sec.length()) + String.format("%0"+sec.length() + "d",Integer.parseInt(sec)+1);
}
}
else
return "";
}
}
The issue is with Integer.parseInt(sec) when trying to parse a value too long to fix in a int (max is 2 billion)
You need to use BigInteger everywhere, also there is much useless code. You can also capture the zeros in the first group of the regex, so you don't have leading zeros to take care
public static String incrementString(String str) {
boolean isNumeric = str.chars().allMatch(Character::isDigit);
if (str.isEmpty()) {
return "1";
} else if (isNumeric) {
BigInteger b = new BigInteger(str);
return String.format("%0" + str.length() + "d", b.add(BigInteger.ONE));
}
String timeRegex = "(.*\\D0*)([1-9][0-9]*)";
Matcher matcher = Pattern.compile(timeRegex).matcher(str);
if (matcher.matches()) {
String sec = matcher.group(2);
if (sec.isEmpty()) {
return str + 1;
} else {
BigInteger new_value = new BigInteger(sec).add(BigInteger.ONE);
return matcher.group(1) + new_value;
}
}
return "";
}
How would you solve this problem by hand? I'll bet you wouldn't require a calculator.
The way I would do would be to just look at the last character in the string:
If the string is empty or the last character is not a digit, append the character 1.
If the last character is one of the digits 0 to 8, change it to the next digit.
If the last character is the digit 9:
Remove all the trailing 9s
Apply whichever of (1) or (2) above is appropriate.
Append the same number of 0s as the number of 9s you removed.
You can implement that simple algorithm in a few lines, without BigInteger and without regexes.
This seems to work, although I didn't test it thoroughly with different Unicode scripts (and I'm really not a Java programmer):
public static String incrementString(String str) {
if (str.isEmpty())
return "1";
char lastChar = str.charAt(str.length()-1);
if (!Character.isDigit(lastChar))
return str + "1";
String prefix = str.substring(0, str.length()-1);
if (Character.digit(lastChar, 10) != 9)
return prefix + (char)(lastChar + 1);
return incrementString(prefix) + (char)(lastChar - 9);
}

Java - Find the the words before and after a given word in a string

Say I have a string
String str = "This problem sucks and is hard"
and I wanted to get the words before and after "problem", so "This" and "sucks". Is regex the best way to accomplish this (keeping in mind that I'm a beginner with regex), or does Java have some kind of library (i.e. StringUtils) that can accomplish this for me?
To find the words before and after a given word, you can use this regex:
(\w+)\W+problem\W+(\w+)
The capture groups are the words you're looking for.
In Java, that would be:
Pattern p = Pattern.compile("(\\w+)\\W+problem\\W+(\\w+)");
Matcher m = p.matcher("This problem sucks and is hard");
if (m.find())
System.out.printf("'%s', '%s'", m.group(1), m.group(2));
Output
'This', 'sucks'
If you want full Unicode support, add flag UNICODE_CHARACTER_CLASS, or inline as (?U):
Pattern p = Pattern.compile("(?U)(\\w+)\\W+problema\\W+(\\w+)");
Matcher m = p.matcher("Questo problema è schifoso e dura");
if (m.find())
System.out.printf("'%s', '%s'", m.group(1), m.group(2));
Output
'Questo', 'è'
For finding multiple matches, use a while loop:
Pattern p = Pattern.compile("(?U)(\\w+)\\W+problems\\W+(\\w+)");
Matcher m = p.matcher("Big problems or small problems, they are all just problems, man!");
while (m.find())
System.out.printf("'%s', '%s'%n", m.group(1), m.group(2));
Output
'Big', 'or'
'small', 'they'
'just', 'man'
Note: The use of \W+ allows symbols to occur between words, e.g. "No(!) problem here" will still find "No" and "here".
Also note that a number is considered a word: "I found 1 problem here" returns "1" and "here".
There is a StringUtils library by apache which does have the methods to substring before and after the string. Additionally there is java's own substring which you can play with to get what you need.
Apache StringUtils library API:
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html
The methods that you might need - substringBefore() and substringBefore().
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#substringBefore(java.lang.String,%20java.lang.String)
Check this out if you want to explore java's own api's
Java: Getting a substring from a string starting after a particular character
A bit verbose but this gets the job done accurately and quickly:
import java.io.*;
import java.util.*;
public class HelloWorld{
public static void main(String []args){
String EntireString="Hello World this is a test";
String SearchWord="World";
System.out.println(getPreviousWordFromString(EntireString,SearchWord));
}
public static String getPreviousWordFromString(String EntireString, String SearchWord) {
List<Integer> IndicesOfWords = new ArrayList();
boolean isWord = false;
int indexOfSearchWord=-1;
if(EntireString.indexOf(SearchWord)!=-1) {
indexOfSearchWord = EntireString.indexOf(SearchWord)-1;
} else {
System.out.println("ERROR: SearchWord passed (2nd arg) does not exist in string EntireString. EntireString: "+EntireString+" SearchWord: "+SearchWord);
return "";
}
if(EntireString.indexOf(SearchWord)==0) {
System.out.println("ERROR: The search word passed is the first word in the search string, so there are no words before it.");
return "";
}
for (int i = 0; i < EntireString.length(); i++) {
if (Character.isLetter(EntireString.charAt(i)) && i != indexOfSearchWord) {
isWord = true;
} else if (!Character.isLetter(EntireString.charAt(i)) && isWord) {
IndicesOfWords.add(i);
isWord = false;
} else if (Character.isLetter(EntireString.charAt(i)) && i == indexOfSearchWord) {
IndicesOfWords.add(i);
}
}
if(IndicesOfWords.size()>0) {
boolean isFirstWordAWord=true;
for (int i = 0; i < IndicesOfWords.get(0); i++) {
if(!Character.isLetter(EntireString.charAt(i))) {
isFirstWordAWord=false;
}
}
if(isFirstWordAWord==true) {
String firstWord = EntireString.substring(0,IndicesOfWords.get(0));
IndicesOfWords.add(0,0);
}
} else {
return "";
}
String ResultingWord = "";
for (int i = IndicesOfWords.size()-1; i >= 0; i--) {
if (EntireString.substring(IndicesOfWords.get(i)).contains(SearchWord)) {
if (i > 0) {
ResultingWord=EntireString.substring(IndicesOfWords.get(i-1),IndicesOfWords.get(i));
break;
}
if (i==0) {
ResultingWord=EntireString.substring(IndicesOfWords.get(0),IndicesOfWords.get(1));
}
}
}
return ResultingWord;
}

Find first sequence of numbers in a string?

So first of all i would like to clear things off by saying that this is for a Minecraft plugin. So I have a method to spawn some mobs (You dont know what mobs it is), and give them custom names. The names are based on numbers. But I also have a sequence of characters in its name. So for instance if the name for the mob was "355 Blaze" it would return an int of 355, and cut the rest out. How should I do this? Currently I use substring but it doesnt work as if the number goes above 9 it will return the first number only.
If its separated by space, use substring based on the location of first space:
Integer mobId = new Integer(fullMobName.substring(0, fullMobName.indexOf(" ")));
Simply use a regex.
private final static Pattern p = Pattern.compile("\\d+");
static String firstNum(String s) {
Matcher m = p.matcher(s);
return m.find() ? m.group() : null;
}
You can use a regex expression in replace method
String s = "355 Blaze";
s.replaceAll("[A-Za-z\\s]+", "");
Then you can cast to int.
Do it without a regex (assuming the number is positive and fits in an int):
int i = 0;
// Skip past non-digits.
while (i < s.length() && !Character.isDigit(s.charAt(i))) {
++i;
}
if (i < s.length()) {
int num = 0;
// Accumulate the digits into the result.
while (i < s.length() && Character.isDigit(s.charAt(i))) {
num = 10 * num + Character.getNumericValue(s.charAt(i));
++i;
}
return num;
}
// No digits found.
throw new NoSuchElementException("No digits found!");
If it only contains digits followed by letters( with possibly an optional space), this will also work:
String ss[] = original.split("a-zA-Z ]", 2);
//ss[0] contains the numbers

How to extract a multiple quoted substrings in Java

I have a string that has multiple substring which has to be extracted. Strings which will be extracted is between ' character.
I could only extract the first or the last one when I use indexOf or regex.
How could I extract them and put them into array or list without parsing the same string only?
resultData = "Error 205: 'x' data is not crawled yet. Check 'y' and 'z' data and update dataset 't'";
I have a tried below;
protected static String errorsTPrinted(String errStr, int errCode) {
if (errCode== 202 ) {
ArrayList<String> ar = new ArrayList<String>();
Pattern p = Pattern.compile("'(.*?)'");
Matcher m = p.matcher(errStr);
String text;
for (int i = 0; i < errStr.length(); i++) {
m.find();
text = m.group(1);
ar.add(text);
}
return errStr = "Err 202: " + ar.get(0) + " ... " + ar.get(1) + " ..." + ar.get(2) + " ... " + ar.get(3);
}
Edit
I used #MinecraftShamrock 's approach.
if (errCode== 202 ) {
List<String> getQuotet = getQuotet(errStr, '\'');
return errStr = "Err 202: " + getQuotet.get(0) + " ... " + getQuotet.get(1) + " ..." + getQuotet.get(2) + " ... " + getQuotet.get(3);
}
You could use this very straightforward algorithm to do so and avoid regex (as one can't be 100% sure about its complexity):
public List<String> getQuotet(final String input, final char quote) {
final ArrayList<String> result = new ArrayList<>();
int n = -1;
for(int i = 0; i < input.length(); i++) {
if(input.charAt(i) == quote) {
if(n == -1) { //not currently inside quote -> start new quote
n = i + 1;
} else { //close current quote
result.add(input.substring(n, i));
n = -1;
}
}
}
return result;
}
This works with any desired quote-character and has a runtime complexity of O(n). If the string ends with an open quote, it will not be included. However, this can be added quite easily.
I think this is preferable over regex as you can ba absolutely sure about its complexity. Also, it works with a minimum of library classes. If you care about efficiency for big inputs, use this.
And last but not least, it does absolutely not care about what is between two quote characters so it works with any input string.
Simply use the pattern:
'([^']++)'
And a Matcher like so:
final Pattern pattern = Pattern.compile("'([^']++)'");
final Matcher matcher = pattern.matcher(resultData);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
This loops through each match in the String and prints it.
Output:
x
y
z
t
Here is a simple approach (assuming there are no escaping characters etc.):
// Compile a pattern to find the wanted strings
Pattern p = Pattern.compile("'([^']+)'");
// Create a matcher for given input
Matcher m = p.matcher(resultData);
// A list to put the found strings into
List<String> list = new ArrayList<String>();
// Loop over all occurrences
while(m.find()) {
// Retrieve the matched text
String text = m.group(1);
// Do something with the text, e.g. add it to a List
list.add(text);
}

How to Insert Commas Into a Number WITHIN a String of Other Words

I have a String like the following:
"The answer is 1000"
I want to insert commas into the number 1000 without destroying the rest of the String.
NOTE: I also want to use this for other Strings of differing lengths, so substring(int index) would not be advised for getting the number.
The best way that I can think of is to use a regex command, but I have no idea how.
Thanks in advance!
The following formats all the non-decimal numbers:
public String formatNumbers(String input) {
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(input);
NumberFormat nf = NumberFormat.getInstance();
StringBuffer sb = new StringBuffer();
while(m.find()) {
String g = m.group();
m.appendReplacement(sb, nf.format(Double.parseDouble(g)));
}
return m.appendTail(sb).toString();
}
e.g. if you call: formatNumbers("The answer is 1000 1000000")
Result is: "The answer is 1,000 1,000,000"
See: NumberFormat and Matcher.appendReplacement().
modified from Most efficient way to extract all the (natural) numbers from a string:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Example {
private static final String REGEX = "\\d+";
public static void main(String[] args) {
String input = "dog dog 1342 dog doggie 2321 dogg";
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(input); // get a matcher object
int end = 0;
String result = "";
while (m.find()) {
result = result + input.substring(end, m.start());
result = result
+ addCommas(
input.substring(
m.start(), m.end()));
end = m.end();
}
System.out.println(result);
}
private static String addCommas(String s) {
char[] c = s.toCharArray();
String result = "";
for (int i = 0; i < s.length(); i++) {
if (s.length() % 3 == i % 3)
result += ",";
result += c[i];
}
return result;
}
}
You could use the regular expression:
[0-9]+
To find contiguous sets of digits, so it would match 1000, or 7500 or 22387234, etc.. You can test this on http://regexpal.com/ This doesn't handle the case of numbers that involve decimal points, BTW.
This isn't a complete, with code answer, but the basic algorithm is as follows:
You use that pattern to find the index(es) of the match(es) within the string (the index of the characters where the various matches start)
From each of those indexes, you copy the digits into a temporary string that contains only the digits of the number(s) in the String
You write a function that starts at the end of the String, and for every 3rd digit (from the end) you insert a comma before it, unless the index of the current character is 0 (which will prevent 300 from being turned into ,300
Replace the original number in the source string with the comma'ed String, using the replace() method

Categories

Resources