Related
I am replacing a character in a string. There has to be a better way to do this, right?
public static String eqEq(String stringIn) {
char[] stringArray;
stringArray = stringIn.toCharArray();
for (int i = 0; i < stringIn.length(); i++){
if(stringArray[i] == '='){
stringArray[i] = '?';
}
}
String sReturn = new String(stringArray);
return sReturn;
}
Something wrong with replace()?
public static String eqEq(String stringIn) {
return stringIn.replace('=', '?');
}
Note that replace() replaces all occurrences, but uses plain text search/replacements, unlike replaceAll() which is the regex version of replace().
Also note the replace() has two versions: One version that has char parameters (used here), and another that has String parameters in case you want to search/replace more than one character.
You could try String#replace, for example
stringIn = stringIn.replace('=', '?');
You could even use String#repalceAll if you want to use a regular expression instead.
You could even use a StringBuilder
StringBuilder sb = new StringBuilder(value);
int index = -1;
while ((index = sb.indexOf("=")) != -1) {
sb.replace(index, index + 1, "?");
}
The choice is yours
You can use the replace or replaceAll methods on the String class, as follows:
public static String eqEq(String stringIn) {
stringIn.replace("=", "?");
}
OR
public static String eqEq(String stringIn) {
stringIn.replaceAll("=", "?");
}
See a live example of this code running (using replaceAll) on a sample string.
If I have a string such as one of the following:
AlphaSuffix
BravoSuffix
CharlieSuffix
DeltaSuffix
What is the most concise Java syntax to transform AlphaSuffix into Alpha into BravoSuffix into Bravo?
Use a simple regexp to delete the suffix:
String myString = "AlphaSuffix";
String newString = myString.replaceFirst("Suffix$", "");
Chop it off.
String given = "AlphaSuffix"
String result = given.substring(0, given.length()-"Suffix".length());
To make it even more concise, create a utility method.
public static String chop(String value, String suffix){
if(value.endsWith(suffix)){
return value.substring(0, value.length() - suffix.length());
}
return value;
}
In the utility method, I've added a check to see if the suffix is actually at the end of the value.
Test:
String[] sufs = new String[] {
"AlphaSuffix",
"BravoSuffix",
"CharlieSuffix",
"DeltaSuffix"
};
for (int i = 0; i < sufs.length; i++) {
String s = chop(sufs[i], "Suffix");
System.out.println(s);
}
Gives:
Alpha
Bravo
Charlie
Delta
if suffixes are all different/unkown you can use
myString.replaceFirst("^(Alpha|Bravo|Charlie|Delta|...).*", "$1");
I wan to remove the last set of data from string using java.
For example I have a string like A,B,C, and I want to remove ,C, and want to get the out put value like A,B . How is it possible in java? Please help.
String start = "A,B,C,";
String result = start.subString(0, start.lastIndexOf(',', start.lastIndexOf(',') - 1));
Here is a fairly "robust" reg-exp solution:
Pattern p = Pattern.compile("((\\w,?)+),\\w+,?");
for (String test : new String[] {"A,B,C", "A,B", "A,B,C,",
"ABC,DEF,GHI,JKL"}) {
Matcher m = p.matcher(test);
if (m.matches())
System.out.println(m.group(1));
}
Output:
A,B
A
A,B
ABC,DEF,GHI
Since there may be a trailing comma, something like this (using org.apache.commons.lang.StringUtils):
ArrayList<String> list = new ArrayList(Arrays.asList(myString.split()));
list.remove(list.length-1);
myString = StringUtils.join(list, ",");
You can use String#lastIndexOf to find the index of the second-to-last comma, and then String#substring to extract just the part before it. Since your sample data ends with a ",", you'll need to use the version of String#lastIndexOf that accepts a starting point and have it skip the last character (e.g., feed in the string's length minus 1).
I wasn't going to post actual code on the theory better to teach a man to fish, but as everyone else is:
String data = "A,B,C,";
String shortened = data.substring(0, data.lastIndexOf(',', data.length() - 2));
You can use regex to do this
String start = "A,B,C,";
String result = start.replaceAll(",[^,]*,$", "");
System.out.println(result);
prints
A,B
This simply erases the the 'second last comma followed by data followed by last comma'
If full String.split() is not possible, the how about just scanning the string for comma and stop after reaching 2nd, without including it in final answer?
String start = "A,B";
StringBuilder result = new StringBuilder();
int count = 0;
for(char ch:start.toCharArray()) {
if(ch == ',') {
count++;
if(count==2) {
break;
}
}
result.append(ch);
}
System.out.println("Result = "+result.toString());
Simple trick, but should be efficient.
In case you want last set of data removed, irrespective of how much you want to read, then
start.substring(0, start.lastIndexOf(',', start.lastIndexOf(',')-1))
Another way to do this is using a StringTokenizer:
String input = "A,B,C,";
StringTokenizer tokenizer = new StringTokenizer(input, ",");
String output = new String();
int tokenCount = tokenizer.countTokens();
for (int i = 0; i < tokenCount - 1; i++) {
output += tokenizer.nextToken();
if (i < tokenCount - 1) {
output += ",";
}
}
public string RemoveLastSepratorFromString(string input)
{
string result = input;
if (result.Length > 1)
{
result = input.Remove(input.Length - 1, 1);
}
return result;
}
// use from above method
string test = "1,2,3,"
string strResult = RemoveLastSepratorFromString(test);
//output --> 1,2,3
The fact that the replace method returns a string object rather than replacing the contents of a given string is a little obtuse (but understandable when you know that strings are immutable in Java). I am taking a major performance hit by using a deeply nested replace in some code. Is there something I can replace it with that would make it faster?
This is what StringBuilder is meant for. If you're going to be doing a lot of manipulation, do it on a StringBuilder, then turn that into a String whenever you need to.
StringBuilder is described thus:
"A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization".
It has replace (and append, insert, delete, et al) and you can use toString to morph it into a real String.
The previous posts are right, StringBuilder/StringBuffer are a solution.
But, you also have to question if it is a good idea to do the replace on big Strings in memory.
I often have String manipulations that are implemented as a stream, so instead of replacing it in the string and then sending it to an OutputStream, I do the replace at the moment that I send the String to the outputstream. That works much faster than any replace.
This works much faster if you want this replace to implement a template mechanism. Streaming is always faster since you consume less memory and if the clients is slow, you only need to generate at a slow pace - so it scales much better.
The follow code is approx. 30 times faster if there is no match and 5 times faster if there is a match.
static String fastReplace( String str, String target, String replacement ) {
int targetLength = target.length();
if( targetLength == 0 ) {
return str;
}
int idx2 = str.indexOf( target );
if( idx2 < 0 ) {
return str;
}
StringBuilder buffer = new StringBuilder( targetLength > replacement.length() ? str.length() : str.length() * 2 );
int idx1 = 0;
do {
buffer.append( str, idx1, idx2 );
buffer.append( replacement );
idx1 = idx2 + targetLength;
idx2 = str.indexOf( target, idx1 );
} while( idx2 > 0 );
buffer.append( str, idx1, str.length() );
return buffer.toString();
}
Adding to the #paxdiablo answer, here's a sample implementation of a replaceAll using StringBuffers that is a ~3.7 times faster than String.replaceAll():
Code:
public static String replaceAll(final String str, final String searchChars, String replaceChars)
{
if ("".equals(str) || "".equals(searchChars) || searchChars.equals(replaceChars))
{
return str;
}
if (replaceChars == null)
{
replaceChars = "";
}
final int strLength = str.length();
final int searchCharsLength = searchChars.length();
StringBuilder buf = new StringBuilder(str);
boolean modified = false;
for (int i = 0; i < strLength; i++)
{
int start = buf.indexOf(searchChars, i);
if (start == -1)
{
if (i == 0)
{
return str;
}
return buf.toString();
}
buf = buf.replace(start, start + searchCharsLength, replaceChars);
modified = true;
}
if (!modified)
{
return str;
}
else
{
return buf.toString();
}
}
Test Case -- the output is the following (Delta1 = 1917009502; Delta2 =7241000026):
#Test
public void testReplaceAll()
{
String origStr = "1234567890-1234567890-";
String replacement1 = StringReplacer.replaceAll(origStr, "0", "a");
String expectedRep1 = "123456789a-123456789a-";
String replacement2 = StringReplacer.replaceAll(origStr, "0", "ab");
String expectedRep2 = "123456789ab-123456789ab-";
String replacement3 = StringReplacer.replaceAll(origStr, "0", "");
String expectedRep3 = "123456789-123456789-";
String replacement4 = StringReplacer.replaceAll(origStr, "012", "a");
String expectedRep4 = "1234567890-1234567890-";
String replacement5 = StringReplacer.replaceAll(origStr, "123", "ab");
String expectedRep5 = "ab4567890-ab4567890-";
String replacement6 = StringReplacer.replaceAll(origStr, "123", "abc");
String expectedRep6 = "abc4567890-abc4567890-";
String replacement7 = StringReplacer.replaceAll(origStr, "123", "abcdd");
String expectedRep7 = "abcdd4567890-abcdd4567890-";
String replacement8 = StringReplacer.replaceAll(origStr, "123", "");
String expectedRep8 = "4567890-4567890-";
String replacement9 = StringReplacer.replaceAll(origStr, "123", "");
String expectedRep9 = "4567890-4567890-";
assertEquals(replacement1, expectedRep1);
assertEquals(replacement2, expectedRep2);
assertEquals(replacement3, expectedRep3);
assertEquals(replacement4, expectedRep4);
assertEquals(replacement5, expectedRep5);
assertEquals(replacement6, expectedRep6);
assertEquals(replacement7, expectedRep7);
assertEquals(replacement8, expectedRep8);
assertEquals(replacement9, expectedRep9);
long start1 = System.nanoTime();
for (long i = 0; i < 10000000L; i++)
{
String rep = StringReplacer.replaceAll(origStr, "123", "abcdd");
}
long delta1 = System.nanoTime() -start1;
long start2= System.nanoTime();
for (long i = 0; i < 10000000L; i++)
{
String rep = origStr.replaceAll( "123", "abcdd");
}
long delta2 = System.nanoTime() -start1;
assertTrue(delta1 < delta2);
System.out.printf("Delta1 = %d; Delta2 =%d", delta1, delta2);
}
If you have a number of strings to replace (such as XML escape sequences), especially where the replacements are different length from the pattern, FSM lexer type algorithm seems like it might be most efficient, similar to the suggestion of processing in a stream fashion, where the output is incrementally built.
Perhaps a Matcher object could be used to do that efficiently.
Just get the char[] of the String and iterate through it. Use a temporary StringBuilder.
Look for the pattern you want to replace while iterating if you don't find the pattern, write the stuff you scanned to the StringBuilder, else write the replacement text to the StringBuilder.
All string manipulation in general are very slow. Consider to use StringBuffer, it's not exactly like the String class, but have a lot in common and it's mutable as well.
When you're replacing single characters, consider iterating over your character array but replace characters by using a (pre-created) HashMap<Character, Character>().
I use this strategy to convert an integer exponent string by unicode superscript characters.
It's about twice as fast compared to String.replace(char, char). Note that the time associated to creating the hash map isn't included in this comparison.
Because String.replace(CharSequence target, CharSequence replacement) has Pattern.compile, matcher, replaceAll inside, one can slightly optimize it by for using precompiled target pattern constant, like this:
private static final Pattern COMMA_REGEX = Pattern.compile(",");
...
COMMA_REGEX.matcher(value).replaceAll(replacement);
Apache commons stuff, based on StringBuilder
StringUtils.replace(String text, String searchString, String replacement)
This question already has answers here:
Simple way to repeat a string
(32 answers)
Closed 4 years ago.
I did check the other questions; this question has its focus on solving this particular question the most efficient way.
Sometimes you want to create a new string with a specified length, and with a default character filling the entire string.
ie, it would be cool if you could do new String(10, '*') and create a new String from there, with a length of 10 characters all having a *.
Because such a constructor does not exist, and you cannot extend from String, you have either to create a wrapper class or a method to do this for you.
At this moment I am using this:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
char[] array = new char[length];
int pos = 0;
while (pos < length) {
array[pos] = charToFill;
pos++;
}
return new String(array);
}
It still lacks any checking (ie, when length is 0 it will not work). I am constructing the array first because I believe it is faster than using string concatination or using a StringBuffer to do so.
Anyone else has a better sollution?
Apache Commons Lang (probably useful enough to be on the classpath of any non-trivial project) has StringUtils.repeat():
String filled = StringUtils.repeat("*", 10);
Easy!
Simply use the StringUtils class from apache commons lang project. You have a leftPad method:
StringUtils.leftPad("foobar", 10, '*'); // Returns "****foobar"
No need to do the loop, and using just standard Java library classes:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
if (length > 0) {
char[] array = new char[length];
Arrays.fill(array, charToFill);
return new String(array);
}
return "";
}
As you can see, I also added suitable code for the length == 0 case.
Some possible solutions.
This creates a String with length-times '0' filled and replaces then the '0' with the charToFill (old school).
String s = String.format("%0" + length + "d", 0).replace('0', charToFill);
This creates a List containing length-times Strings with charToFill and then joining the List into a String.
String s = String.join("", Collections.nCopies(length, String.valueOf(charToFill)));
This creates a unlimited java8 Stream with Strings with charToFill, limits the output to length and collects the results with a String joiner (new school).
String s = Stream.generate(() -> String.valueOf(charToFill)).limit(length).collect(Collectors.joining());
In Java 11, you have repeat:
String s = " ";
s = s.repeat(1);
(Although at the time of writing still subject to change)
char[] chars = new char[10];
Arrays.fill(chars, '*');
String text = new String(chars);
To improve performance you could have a single predefined sting if you know the max length like:
String template = "####################################";
And then simply perform a substring once you know the length.
Solution using Google Guava
String filled = Strings.repeat("*", 10);
public static String fillString(int count,char c) {
StringBuilder sb = new StringBuilder( count );
for( int i=0; i<count; i++ ) {
sb.append( c );
}
return sb.toString();
}
What is wrong?
using Dollar is simple:
String filled = $("=").repeat(10).toString(); // produces "=========="
Solution using Google Guava, since I prefer it to Apache Commons-Lang:
/**
* Returns a String with exactly the given length composed entirely of
* the given character.
* #param length the length of the returned string
* #param c the character to fill the String with
*/
public static String stringOfLength(final int length, final char c)
{
return Strings.padEnd("", length, c);
}
The above is fine. Do you mind if I ask you a question - Is this causing you a problem? It seams to me you are optimizing before you know if you need to.
Now for my over engineered solution. In many (thou not all) cases you can use CharSequence instead of a String.
public class OneCharSequence implements CharSequence {
private final char value;
private final int length;
public OneCharSequence(final char value, final int length) {
this.value = value;
this.length = length;
}
public char charAt(int index) {
if(index < length) return value;
throw new IndexOutOfBoundsException();
}
public int length() {
return length;
}
public CharSequence subSequence(int start, int end) {
return new OneCharSequence(value, (end-start));
}
public String toString() {
char[] array = new char[length];
Arrays.fill(array, value);
return new String(array);
}
}
One extra note: it seems that all public ways of creating a new String instance involves necessarily the copy of whatever buffer you are working with, be it a char[], a StringBuffer or a StringBuilder. From the String javadoc (and is repeated in the respective toString methods from the other classes):
The contents of the character array are copied; subsequent modification of
the character array does not affect
the newly created string.
So you'll end up having a possibly big memory copy operation after the "fast filling" of the array. The only solution that may avoid this issue is the one from #mlk, if you can manage working directly with the proposed CharSequence implementation (what may be the case).
PS: I would post this as a comment but I don't have enough reputation to do that yet.
Try this Using the substring(int start, int end); method
String myLongString = "abcdefghij";
if (myLongString .length() >= 10)
String shortStr = myLongString.substring(0, 5)+ "...";
this will return abcde.
Mi solution :
pw = "1321";
if (pw.length() < 16){
for(int x = pw.length() ; x < 16 ; x++){
pw += "*";
}
}
The output :
1321************
Try this jobber
String stringy =null;
byte[] buffer = new byte[100000];
for (int i = 0; i < buffer.length; i++) {
buffer[i] =0;
}
stringy =StringUtils.toAsciiString(buffer);