I have a string which has the below content
String msg = "The variables &CHAG_EF and &CHAG_DNE_DTE can be embedded"
String test1 = "22/10/2010 00:10:12"
String test2 = "25/10/2010 00:01:12"
I need to search the string variable msg for the string "&CHAG_EF" and if it exists replace with the value of test1 and also search the string variable msg for the string "&CHAG_DNE_DTE" and if it exists replace with the value of test2.
How can i replace them?
So simple!
String msg2 = msg.replace("&CHAG_EF", test1).replace("&CHAG_DNE_DTE", test2);
Firstly, Strings can't be modified in Java so you'll need to create new versions with the correct modified values. There are two ways to approach this problem:
Dynamically hard-code all the replacements like other posters have suggested. This isn't scalable with large strings or a large number of replacements; or
You loop through the String looking for potential variables. If they're in your replacement Map then replace them. This is very similar to How to create dynamic Template String.
The code for (2) looks something like this:
public static String replaceAll(String text, Map<String, String> params) {
Pattern p = Pattern.compile("&(\\w+)");
Matcher m = p.matcher(text);
boolean result = m.find();
if (result) {
StringBuffer sb = new StringBuffer();
do {
String replacement = params.get(m.group(1));
if (replacement == null) {
replacement = m.group();
}
m.appendReplacement(sb, replacement);
result = m.find();
} while (result);
m.appendTail(sb);
return sb.toString();
}
return text;
}
Strings in Java are immutable, so any of the "manipulation" methods return a new string rather than modifying the existing one. One nice thing about this is that you can chain operations in many cases, like this:
String result = msg.replace("&CHAG_EF", test1)
.replace("&CHAG_DNE_DTE", test2);
msg = msg.replace("&CHAG_EF", test1).replace("&CHAG_DNE_DTE", test2);
Related
I have a string as a#1-b#2-c#3-d#4-e#5-f#6-g#7-h#8-i#9-j#0-k#10-l#11.
I want to create a program such that if I give value as a then it should return a#1, If I give b then it should return b#2 from given string. I am very new to java regular expressions.
Yes, a simple regex should do the trick. Just prepend your input to a regex matching # followed by some numbers (assuming that's the pattern):
String str = "a#1-b#2-c#3-d#4-e#5-f#6-g#7-h#8-i#9-j#0-k#10-l#11";
String input = "a";
Matcher m = Pattern.compile(input + "#\\d+").matcher(str);
if (m.find()) {
System.out.println(m.group());
}
Probably using RegExpo for such simple task is overhead. Just string search:
public static String get(char ch) {
final String str = "a#1-b#2-c#3-d#4-e#5-f#6-g#7-h#8-i#9-j#0-k#10-l#11";
int pos = str.indexOf(ch);
if (pos < 0)
return null;
int end = str.indexOf('-', pos);
return end < 0 ? str.substring(pos) : str.substring(pos, end);
}
Not better than #shmosel's answer, but if you need to repeatedly extract values, you can build a Map once, then each retrieval will be faster (but initial Map construction will be slow):-
Map<String, String> map = Arrays.stream(str.split("-"))
.collect(Collectors.toMap(o -> o.substring(0, o.indexOf('#')).trim(), Function.identity()));
Here's the full code:-
String str = "a#1-b#2-c#3-d#4-e#5-f#6-g#7-h#8-i#9-j#0-k#10-l#11";
Map<String, String> map = Arrays.stream(str.split("-"))
.collect(Collectors.toMap(o -> o.substring(0, o.indexOf('#')).trim(), Function.identity()));
System.out.println(map.get("a"));
Output: a#1
I have a small problem, but it's hard for me to solve it.
I have built a String that is a collection of some object's attributes, constructed and delimited by ||. But whenever I have some null attribute, it keeps on printing null, I want to replace null with empty string.
For example, for the input
ADS||abc||null||null
I want it to become
ADS||abc||||
I tried these two, but they didn't work:
string.replace(null,"")
string.replace("null","")
Can someone please help?
Since Strings are immutable, you should assign your String variable to the result of the replace method.
String str = "ADS||abc||null||null to become ADS||abc||||";
str = str.replace("null", "");
System.out.println(str);
Output:
ADS||abc|||| to become ADS||abc||||
Do you mean below code?
String[] names = new String("ADS||abc||null||null to become ADS||abc||||").split("\\|\\|");
List<String> list = new ArrayList<>();
for (String name : names) {
list.add(name.replace("null", ""));
}
This works fine.
public static void main(String[] args) {
String s = "ADS||abc||null||null";
s = s.replace("null", "");
System.out.println(s);
}
Output
ADS||abc||||
you forgot that string is immutable, add this to your code:
String string = string.replace("null","");
I am trying to concat String array values in a String, The below code does not work
private void newString() {
String str = "Split me";
String[] tokens = str.split("[ ]+");
String newStr = new String();
for(int i=0; i<tokens.length; i++){
newStr.concat(tokens[i]);
}
System.out.println("NEW STRING IS : " + newStr);
}
public static void main(String[] args){
Main m = new Main();
m.newString();
}
When you call newStr.concat(tokens[i]); this doesn't modify newStr, it returns a new String that is the result of the concatenation. You aren't doing anything with the result.
You need to do something like: newStr = newStr.concat(tokens[i]);
String is an immutable type in java, so it's methods work like this, returning a new String object. Consider using a (mutable) StringBuilder instead. StringBuilder maintains an internal buffer that can grow, and so avoids the unnecessary String copies that come with using concatenation and immutable Strings.
String is immutable. Naturally, String.concat returns a brand new String.
... a new String object is created, representing a character sequence that is the concatenation of the character sequence represented by this String object and the character sequence represented by the argument string.
The way you're trying to do it, the code should look like...
String glued = "";
for (final String token : tokens) {
glued = glued.concat(token);
}
Now, the problem I have with this approach is that you're doing a lot of copies of the String data. Each concat copies all of the data in glued as well as the data in token. Now, think about the implications of that... I'm not a fan of premature optimization, but I believe the logical way to achieve this is to instead use a StringBuilder as follows...
final StringBuffer buf = new StringBuffer();
for (final String token : tokens) {
buf.append(token);
}
final String glued = buf.toString();
I try to fix it with StringBuilder,here is the new codes.
private void newString() {
String str = "Split me";
String[] tokens = str.split("[ ]+");
StringBuilder newStr = new StringBuilder();
for(int i=0; i<tokens.length; i++){
newStr.append(tokens[i]);
}
System.out.println("NEW STRING IS : " + newStr);
}
I'ms looking for a way to replace my variables in a string by their value. Here is my string lookalike:
"cp $myfile1 $myfile2"
In fact, I looked the javadoc and it seems that I could use split() method from String class which is good but I have also seen an article on which it seems that it is possible to replace all my variables with regex and replaceAll() method. Unfortunately I didnt find any example on the last solution.
Is it possible to use replaceAll in my case (with an example)?
No, you can't use String.replaceAll in this case. (You could replace all $... substrings, but each replacement would depend on the actual variable being replaced.)
Here's an example that does a simultaneous replacement which depends on the substring being replaced:
import java.util.*;
import java.util.regex.*;
class Test {
public static void main(String[] args) {
Map<String, String> variables = new HashMap<String, String>() {{
put("myfile1", "/path/to/file1");
put("myfile2", "/path/to/file2");
}};
String input = "cp $myfile1 $myfile2";
// Create a matcher for pattern $\S+
Matcher m = Pattern.compile("\\$(\\S+)").matcher(input);
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, variables.get(m.group(1)));
m.appendTail(sb);
System.out.println(sb.toString());
}
}
Output:
cp /path/to/file1 /path/to/file2
(adapted from over here: Replace multiple substrings at once)
I would stick to java and use
public void replace(String s, String placeholder, String value) {
return s.replace(placeholder, value);
}
You could even do multiple replacements with this approach:
public String replace(String s, Map<String, String> placeholderValueMap) {
Iterator<String> iter = placeholderValueMap.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
String value = placeholderValueMap.get(key);
s = s.replace(key, value);
}
return s;
}
You could use it like this:
String yourString = "cp $myfile1 $myfile2";
Map<String, String> placeholderValueMap = new HashMap<String, String>();
placeholderValueMap.put("$myfile1", "fileOne");
placeholderValueMap.put("$myfile2", "fileTwo");
someClass.replace(yourString, placeholderValueMap);
Assuming there are no restrictions in the characters that can be used in the individual Strings, and the Strings may be empty.
Edit:
Seems like the proper way to do this is to use a separator, and to escape occurances of that separator that already exist in any of the individual strings. Below is my attempt to this, which seems to work. Did miss any cases that will break it?:
public static void main(String args[])
{
Vector<String> strings = new Vector<String>();
strings.add("abab;jmma");
strings.add("defgh;,;");
strings.add("d;;efgh;,;");
strings.add("");
strings.add("");
strings.add(";;");
strings.add(";,;");
String string = combine(strings);
strings= separate(string);
System.out.println();
}
static String combine(Vector<String> strings)
{
StringBuilder builder = new StringBuilder();
for(String string : strings)
{
//don't prepend a SEPARATOR to the first string
if(!builder.toString().equals(""))
{
builder.append(";");
}
string = string.replaceAll(";", ",;");
builder.append(string);
}
return builder.toString();
}
static Vector<String> separate(String string)
{
Vector<String> strings = new Vector<String>();
separate(string, strings, 0);
return strings;
}
static void separate(String string, Vector<String> strings, int currIndex)
{
int nextIndex = -1;
int checkIndex = currIndex;
while(nextIndex == -1 && checkIndex < string.length())
{
nextIndex = string.indexOf(';', checkIndex);
//look back to determine if this occurance is escaped
if(string.charAt(nextIndex - 1) == ',')
{
//this ones is escaped, doesn't count
checkIndex = nextIndex + 1;
nextIndex = -1;
}
}
if(nextIndex == -1)
{
//no more remain
String toAdd = string.substring(currIndex, string.length());
toAdd = toAdd.replaceAll(",;", ";");
strings.add(toAdd);
return;
}
else if(currIndex + 1 == nextIndex)
{
//empty string
strings.add("");
separate(string, strings, nextIndex);
}
else
{
//there could be more
String toAdd = string.substring(currIndex, nextIndex);
toAdd = toAdd.replaceAll(",;", ";");
strings.add(toAdd);
separate(string, strings, nextIndex + 1);
}
}
}
Take your Vector of Strings and convert it to a JSON object and store the JSON object.
( http://www.json.org/ and http://www.json.org/java/ )
With your code, you can recover empty strings using the two-argument version of split:
String[] separate(String string)
{
return string.split(SEPARATOR, -1);
}
If you can truly make no assumptions about the string contents, the only way to do this properly is by escaping the separator sequence (which can then be a single character) wherever it occurs in the source string(s). Obviously, if you escape the separator sequence, you need to unescape the result after splitting. (The escape mechanism will likely require additional at least one additional escape/unescape.)
EDIT
Here's an example (XML-inspired) of escaping and unescaping. It assumes that the separator sequence is "\u0000" (a single NULL character).
/** Returns a String guaranteed to have no NULL character. */
String escape(String source) {
return source.replace("&", "&").replace("\u0000", "&null;");
}
/** Reverses the above escaping and returns the result. */
String unescape(String escaped) {
return source.replace("&null;", "\u0000").replace("&", "&");
}
Many other variations are possible. (It is important that the replacements when unescaping are in reverse order from those used for escaping.) Note that you can still use String.split() to separate the components.
You can build a class that stores the individual strings internally and then outputs a concatenated version of the strings when you call toString. Getting the original strings back is trivial as you already have them stored individually.
You can have the same comportement in two lines of code using Google Guava library (Splitter and Joiner classes).
public String combine(Collection<String> strings) {
return Joiner.on("yourUniqueSeparator").join(strings);
}
public Iterable<String> separate(String toSeparate) {
return Splitter.on("yourUniqueSeparator").split(toSeparate);
}
Take a look at opencsv if you want to use delimited text. The api is rather easy to use, and it takes care of dealing with escaping quotes and the like. However, it treats null values as empty strings, so you might get a,,c if your input was { "a", null, "c" }. If that's not acceptable, you could use a recognizable string and convert it back later.
char tokenSeparator = ',';
char quoteChar = '"';
String inputData[] = {"a","b","c"};
StringWriter stringWriter = new StringWriter();
CSVWriter csvWriter = new CSVWriter(stringWriter, tokenSeparator, quoteChar);
csvWriter.writeNext(inputData);
csvWriter.close();
StringReader stringReader = new StringReader(stringWriter.toString());
CSVReader csvReader = new CSVReader(stringReader, tokenSeparator, quoteChar);
String outputData[] = csvReader.readNext();