replacing characters of a string - java

So I'm trying to iterate over a string and replace ever occurrence of a given substring with a new value. I can't seem to figure out what the problem with my code is because it doesn't seem to make any changes to the strings i run through it.
i create a new string nS that starts out as just “”, and am iterating through the template viewing each character as a substring s. In in every case that something needs to be replaced with a value i append said value on to the nS, else it just appends the current substring as is.
#Override
public String format(String template) {
String nS = "";
for (int i = 0, n = template.length(); i < n; i++) {
String s = template.substring(i, i + 1);
switch (s) {
case "%%":
nS = nS.concat("%");
break;
case "%t":
nS = nS.concat(String.valueOf(inSeconds()));
break;
}
}
return nS;
}
the actual code has many more cases but i left them out so that its not as overwhelming.

The ending index in the 2-arg substring method is exclusive.
The substring begins at the specified beginIndex and extends to the character at index endIndex - 1.
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive.
You are getting a substring of exactly one character, not 2. Try i + 2, after the appropriate bounds-checking:
String s = template.substring(i, i + 2);

Assuming performance is not a big issue I would do
public String format(String template) {
return template.replaceAll ("%%", "\uffff")
.replaceAll("%t", ""+inSeconds())
.replaceAll("\uffff", "%");
}

What you're describing attempting to do sounds like you're trying to rewrite String.replace()
Given String s = "My Name Is Bob"
and you would like to replace "Bob" with "Susan" all you need to do is:
String s = "My Name is Bob";
String n = s.replace("Bob", "Susan");
System.out.println(n); //My Name is Susan
System.out.println(s); //My Name is Bob
Another option, is to break the string into a character array and iterate over it.
String s = "My Name is Bob";
char[] bits = s.toCharArray();
for(char c : bits) {
// logic
}
Compare two characters at once:
String s = "My Name is Bob";
char[] bits = s.toCharArray();
for(int i = 0; i < bits.length; i++) {
if(i + 1 <= bits.length) {
String searchFor = "" + bits[i] + bits[i + 1];
// logic
}
}

Related

Java: Split string by number of characters but with guarantee that string will be split only after whitespace

I want to achieve something like this.
String str = "This is just a sample string";
List<String> strChunks = splitString(str,8);
and strChunks should should be like:
"This is ","just a ","sample ","string."
Please note that string like "sample " have only 7 characters as with 8 characters it will be "sample s" which will break down my next word "string".
Also we can go with the assumption that a word will never be larger than second argument of method (which is 8 in example) because in my use case second argument is always static with value 32000.
The obvious approach that I can think of is looping thru the given string, breaking the string after 8 chars and than searching the next white space from the end. And then repeating same thing again for remaining string.
Is there any more elegant way to achieve the same. Is there any utility method already available in some standard third libraries like Guava, Apache Commons.
Splitting on "(?<=\\G.{7,}\\s)" produces the result that you need (demo).
\\G means the end of previous match; .{7,} means seven or more of any characters; \\s means a space character.
Not a standard method, but this might suit your needs
See it on http://ideone.com/2RFIZd
public static List<String> splitString(String str, int chunksize) {
char[] chars = str.toCharArray();
ArrayList<String> list = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
int count = 0;
for(char character : chars) {
if(count < chunksize - 1) {
builder.append(character);
count++;
}
else {
if(character == ' ') {
builder.append(character);
list.add(builder.toString());
count = 0;
builder.setLength(0);
}
else {
builder.append(character);
count++;
}
}
}
list.add(builder.toString());
builder.setLength(0);
return list;
}
Please note, I used the human notation for string length, because that's what your sample reflects( 8 = postion 7 in string). that's why the chunksize - 1 is there.
This method takes 3 milliseconds on a text the size of http://catdir.loc.gov/catdir/enhancements/fy0711/2006051179-s.html
Splitting String using method 1.
String text="This is just a sample string";
List<String> strings = new ArrayList<String>();
int index = 0;
while (index < text.length()) {
strings.add(text.substring(index, Math.min(index + 8,text.length())));
index += 8;
}
for(String s : strings){
System.out.println("["+s+"]");
}
Splitting String using Method 2
String[] s=text.split("(?<=\\G.{"+8+"})");
for (int i = 0; i < s.length; i++) {
System.out.println("["+s[i]+"]");
}
This uses a hacked reduction to get it done without much code:
String str = "This is just a sample string";
List<String> parts = new ArrayList<>();
parts.add(Arrays.stream(str.split("(?<= )"))
.reduce((a, b) -> {
if (a.length() + b.length() <= 8)
return a + b;
parts.add(a);
return b;
}).get());
See demo using edge case input (that breaks some other answers!)
This splits after each space, then either joins up parts or adds to the list depending on the length of the pair.

How to retain matched sub string and replace unmatched sub strings in Java String

Hello I try to print in an array of Strings
In the following way:
Input: big = "12xy34", small = "xy" output: "** xy **"
Input: big = "" 12xt34 "", small = "xy" output: "******"
Input: big = "12xy34", small = "1" output: "1 *****"
Input: big = "12xy34xyabcxy", small = "xy" output: "** xy ** xy *** xy"
Input: big = "78abcd78cd", small = "78" output: "78 **** 78 **"
What I need to write a condition to receive as up?
public static String stars(String big, String small) {
//throw new RuntimeException("not implemented yet ");
char[] arr = big.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (big.contains(small) ) {
arr[i] = '*';
}
}
String a = Arrays.toString(arr);
return big+""+a;
}
Algorithm:
Convert big and small String's to char[] array's bigC and smallC respectively
Iterate over each character of big String
At every index during iteration, identify whether there is a sub-string possible beginning current character
If there is a sub-string possibility, advance the index in big String iteration by length of small String
Otherwise, replace the character by *
Code:
public class StringRetainer {
public static void main(String args[]) {
String big[] = {"12xy34", "12xt34", "12xy34", "12xy34xyabcxy", "78abcd78cd"};
String small[] = {"xy", "xy", "1", "xy", "78"};
for(int i = 0; i < big.length & i < small.length; i++) {
System.out.println("Input: big = \"" + big[i] + "\", small = \"" + small[i] + "\" output : \"" + stars(big[i], small[i]) + "\"");
}
}
public static String stars(String big, String small) {
//String to char[] array conversions
char[] bigC = big.toCharArray();
char[] smallC = small.toCharArray();
//iterate through every character of big String and selectively replace
for(int i = 0; i < bigC.length; i++) {
//flag to determine whether small String occurs in big String
boolean possibleSubString = true;
int j = 0;
//iterate through every character of small String to determine
//the possibility of character replacement
for(; j < smallC.length && (i+j) < bigC.length; j++) {
//if there is a mismatch of at least one character in big String
if(bigC[i+j] != smallC[j]) {
//set the flag indicating sub string is not possible and break
possibleSubString = false;
break;
}
}
//if small String is part of big String,
//advance the loop index with length of small String
//replace with '*' otherwise
if(possibleSubString)
i = i+j-1;
else
bigC[i] = '*';
}
big = String.copyValueOf(bigC);
return big;
}
}
Note:
This is one possible solution (legacy way of doing)
Looks like there is no straight forward way of making this happen using built-in String/StringBuffer/StringBuilder methods

How to specify the number of alphabets (and not blank spaces) to include in a substring?

I am trying to print a substring using index value. I need to exclude the blank space while counting but it should print the output along with blank space. I want to display, say, n alphabets from the main string. The blank spaces will be as they are but the number of alphabets from the lower bound to upper bound index should be n. My code is
public class Test {
public static void main(String args[])
{
String Str=new String("Welcome to the class");
System.out.println("\nReturn value is:");
System.out.println(Str.substring(2,9));
}
}
Output:
lcome t
In the above mentioned code, it counts the space between the "Welcome" and "to". i need not want to count the space between them. My expected output is lcome to
You could use simple mathematics. Just substring it, remove all whitespaces and compare the original length to the String without whitespaces. Afterwards add the difference in size to your end index for the substring.
public static void main(String args[]) {
String Str = "Welcome to the class";
System.out.println("\nReturn value is:");
String sub = Str.substring(2, 9);
String wsRemoved = sub.replaceAll(" ", "");
String wsBegginingRemoved = sub.replaceAll("^ *", "");
String outputSub = Str.substring(2+(sub.length()-wsBegginingRemoved.length()), 9+(sub.length()-wsRemoved.length()+(sub.length() - wsBegginingRemoved.length())));
System.out.println(outputSub);
}
Edit: not ignoring leading whitespaces anymore
O/P
lcome to
O/P "My name is Earl"
name is E
One way would be to extract it to using a regex ^.{2}([^ ] *){7}.
Another option is to use a simple for loop to traverse the string and calculate the end point to use for substring.
int non_whitespace = 0; int i;
for(i = 2; non_whitespace < 7; ++non_whitespace, ++i) {
while (str.charAt(i) == ' ') ++i;
}
return str.substring(2, i);
It is up to you which method do you consider more readable, and assess which one leads to better performance if speed is a concern.
What you want to do is display n number of characters from the string including the spaces but n doesn't include the no. of blank spaces. For that, you could simply be using a loop instead of a library function.
The Logic: Keep displaying characters of the String str from index = 2 to index = 9-1 in a while loop. If the current character is a blank space, then increase the value of n, which is the upper bound of the string index for the sub string, by 1, i.e., the program will now display an extra character beyond the upper bound for each blank space encountered.
Consider the code below.
String str = "Welcome to the class";
int index = 2, n = 9;
while(index < n){
char c = str.charAt(index);
System.out.print(c);
if(c==' ')
n++;
index++;
}
Output: lcome to
Hope you can understand this code.
EDIT
As #Finbarr O'B said, a check to prevent StringIndexOutOfBoundsException would be necessary for the program for which, the loop will have to be defined as:
while(index < n && index < str.length()){
...
}
If you don't want to use regex, you can implement your own version of substring. The straightforward solution:
private static String substring(int begin, int end, String str) {
StringBuilder res = new StringBuilder();
while (begin < end) {
if (str.charAt(begin) == ' ') {
end++;
}
res.append(str.charAt(begin));
begin++;
}
return res.toString();
}
The trick here is to ignore the "count" of a space, by incrementing end when it's encountered, forcing the loop to make one extra iteration.
The code complexity is O(n).
System.out.println(substring(2, 9, "Welcome to the class"));
>> lcome to
You could use replaceFirst for this:
String Str = "Welcome to the class"; // remove new String()
Str = Str.replaceFirst("^ *", "");
System.out.println("\nReturn value is:");
System.out.println(Str.substring(2, 10)); // increment end index by 1
Output:
lcome to

java replace substring in string specific index

How would I replace a string 10100 with 10010 using the algorithm "replace the last substring 10 with 01."
I tried
s=s.replace(s.substring(a,a+2), "01");
but this returns 01010, replacing both the first and the second substring of "10".
"a" represents s.lastindexOf("10");
Here's a simple and extensible function you can use. First its use/output and then its code.
String original = "10100";
String toFind = "10";
String toReplace = "01";
int ocurrence = 2;
String replaced = replaceNthOcurrence(original, toFind, toReplace, ocurrence);
System.out.println(replaced); // Output: "10010"
original = "This and This and This";
toFind = "This";
toReplace = "That";
ocurrence = 3;
replaced = replaceNthOcurrence(original, toFind, toReplace, ocurrence);
System.out.println(replaced); // Output: "This and This and That"
Function code:
public static String replaceNthOcurrence(String str, String toFind, String toReplace, int ocurrence) {
Pattern p = Pattern.compile(Pattern.quote(toFind));
Matcher m = p.matcher(str);
StringBuffer sb = new StringBuffer(str);
int i = 0;
while (m.find()) {
if (++i == ocurrence) { sb.replace(m.start(), m.end(), toReplace); break; }
}
return sb.toString();
}
If you want to access the last two indices of a string, then you can use: -
str.substring(str.length() - 2);
This gives you string from index str.length() - 2 to the last character, which is exactly the last two character.
Now, you can replace the last two indices with whatever string you want.
UPDATE: -
Of you want to access the last occurrence of a character or substring, you can use String#lastIndexOf method: -
str.lastIndexOf("10");
Ok, you can try this code: -
String str = "10100";
int fromIndex = str.lastIndexOf("10");
str = str.substring(0, fromIndex) + "01" + str.substring(fromIndex + 2);
System.out.println(str);
10100 with 10010
String result = "10100".substring(0, 2) + "10010".substring(2, 4) + "10100".substring(4, 5);
You can get the last index of a character or substring using string's lastIndexOf method. See the documentation link below for how to use it.
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#lastIndexOf(java.lang.String)
Once you know the index of your substring, you can get the substring of all characters before that index, and the substring of all characters after the last character in your search string, and concatenate.
This is a little drawn out, and I didn't actually run it (so I might have a syntax error), but it gives you the point of what I'm trying to convey at least. You could do this all in one line if you want, but it wouldn't illustrate the point as well.
string s = "10100";
string searchString = "10";
string replacementString = "01";
string charsBeforeSearchString = s.substring(0, s.lastIndexOf(searchString) - 1);
string charsAfterSearchString = s.substring(s.lastIndexIf(searchString) + 2);
s = charsBeforeSearchString + replacementString + charsAfterSearchString;
The easiest way:
String input = "10100";
String result = Pattern.compile("(10)(?!.*10.*)").matcher(input).replaceAll("01");
System.out.println(result);

Algorithm for duplicated but overlapping strings

I need to write a method where I'm given a string s and I need to return the shortest string which contains s as a contiguous substring twice.
However two occurrences of s may overlap. For example,
aba returns ababa
xxxxx returns xxxxxx
abracadabra returns abracadabracadabra
My code so far is this:
import java.util.Scanner;
public class TwiceString {
public static String getShortest(String s) {
int index = -1, i, j = s.length() - 1;
char[] arr = s.toCharArray();
String res = s;
for (i = 0; i < j; i++, j--) {
if (arr[i] == arr[j]) {
index = i;
} else {
break;
}
}
if (index != -1) {
for (i = index + 1; i <= j; i++) {
String tmp = new String(arr, i, i);
res = res + tmp;
}
} else {
res = res + res;
}
return res;
}
public static void main(String args[]) {
Scanner inp = new Scanner(System.in);
System.out.println("Enter the string: ");
String word = inp.next();
System.out.println("The requires shortest string is " + getShortest(word));
}
}
I know I'm probably wrong at the algorithmic level rather than at the coding level. What should be my algorithm?
Use a suffix tree. In particular, after you've constructed the tree for s, go to the leaf representing the whole string and walk up until you see another end-of-string marker. This will be the leaf of the longest suffix that is also a prefix of s.
As #phs already said, part of the problem can be translated to "find the longest prefix of s that is also a suffix of s" and a solution without a tree may be this:
public static String getShortest(String s) {
int i = s.length();
while(i > 0 && !s.endsWith(s.substring(0, --i)))
;
return s + s.substring(i);
}
Once you've found your index, and even if it's -1, you just need to append to the original string the substring going from index + 1 (since index is the last matching character index) to the end of the string. There's a method in String to get this substring.
i think you should have a look at the Knuth-Morris-Pratt algorithm, the partial match table it uses is pretty much what you need (and by the way it's a very nice algorithm ;)
If your input string s is, say, "abcde" you can easily build a regex like the following (notice that the last character "e" is missing!):
a(b(c(d)?)?)?$
and run it on the string s. This will return the starting position of the trailing repeated substring. You would then just append the missing part (i.e. the last N-M characters of s, where N is the length of s and M is the length of the match), e.g.
aba
^ match "a"; append the missing "ba"
xxxxxx
^ match "xxxxx"; append the missing "x"
abracadabra
^ match "abra"; append the missing "cadabra"
nooverlap
--> no match; append "nooverlap"
From my understanding you want to do this:
input: dog
output: dogdog
--------------
input: racecar
output: racecaracecar
So this is how i would do that:
public String change(String input)
{
StringBuilder outputBuilder = new StringBuilder(input);
int patternLocation = input.length();
for(int x = 1;x < input.length();x++)
{
StringBuilder check = new StringBuilder(input);
for(int y = 0; y < x;y++)
check.deleteCharAt(check.length() - 1);
if(input.endsWith(check.toString()))
{
patternLocation = x;
break;
}
}
outputBuilder.delete(0, input.length() - patternLocation);
return outputBuilder.toString();
}
Hope this helped!

Categories

Resources