In the below someString String I want to remove FAIL: and extract the last ID_ number and ignore all other ID_ number in the string. Why does the method in the first system.out doesn't work but the second one does?
Or what is the best way to achieve this?
public static void main(String[] args) {
String someString = "FAIL: some random message with ID_temptemptemp and with original ID_1234567890";
System.out.println(someString.split("FAIL: ")[1].substring(someString.lastIndexOf("ID_")));
String newString = someString.split("FAIL: ")[1];
System.out.println(newString.substring(newString.lastIndexOf("ID_") + 3));
}
Output:
4567890
1234567890
In my opinion, this sort of problem is usually best to use regular expression. While using a combination of replace substring indexOf can work but it can be difficult for the next dev to understand the real logic.
This is the regular expression solution:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class testmain {
public static void main(String[] args) {
String someString = "FAIL: some random message with ID_temptemptemp and with original ID_1234567890";
Pattern pattern3 = Pattern.compile("ID_(\\d+)");
Matcher matcher3 = pattern3.matcher(someString);
String s = null;
while (matcher3.find()) {
s = matcher3.group(1); // Keep overriding until the last set of captured value
}
System.out.println(s);
}
}
Sample output:
1234567890
The expression ID_(\\d+) means that we are looking for occurrances of the word "ID_" and if matched, capture the remaining digits.
The following while loop is just to go through all the captured patterns and keep overriding the s variable with the captures until the last one, which fits your requirement.
The original problem:
The issue with your initial solution was that after you did a .split(...) the length of the splited value in position [1] string is no longer the same as the original string value, and hence you should be doing lastIndexOf(someString.split("FAIL: ")[1]) instead to compare.
Therefore giving you the output ID_1234567890
Example:
System.out.println(someString.split("FAIL: ")[1].substring(someString.split("FAIL: ")[1].lastIndexOf("ID_")));
The remaining code works just fine.
Tips:
Tips on debugging, maybe get an IDE like IntelliJ and step through the code to see what the code is doing on each step. This would give you a better idea.
Another way would be to split on space and then use replace
String test = "FAIL: some random message with
ID_temptemptemp and with original ID_1234567890";
String arr[] = test.split (" ");
System.out.println(arr[arr.length -1].replace("ID_", ""));
Arrays.stream(str.split(" "))
.filter(x -> x.startsWith("ID_"))
.map(x -> x.substring(3))
.reduce((x, y) -> y)
.ifPresent(System.out::println);
or
String id = Arrays.stream(str.split(" "))
.filter(x -> x.startsWith("ID_"))
.map(x -> x.substring(3))
.reduce((x, y) -> y)
.orElse(null);
You first attempt does not work because once you have done this someString.split("FAIL: ")[1] the immutable string "someString" was split and two new string objects were created. So substring(someString.lastIndexOf("ID_")) goes wrong becuase you are trying to use the length from original string for a substring operation for a smaller string
The best way to solve this as I see it is someString.substring(someString.lastIndexOf("ID_") + 3)
Because I see no use of stripping out "FAIL" part
It works in the second one because you String is immutable and cannot be replaced inline.
In the first one you try to do it inline and hence it fails. But in the second one you do replace and store it in another string:
String newString = someString.split("FAIL: ")[1];
System.out.println(newString.substring(newString.lastIndexOf("ID_") + 3));
If you want to use inline then you may try StringBuffer and StringBuilder
Related
I want a dynamic code which will trim of some part of the String at the beginning and some part at last. I am able to trim the last part but not able to trim the initial part of the String to a specific point completely. Only the first character is deleted in the output.
public static String removeTextAndLastBracketFromString(String string) {
StringBuilder str = new StringBuilder(string);
int i=0;
do {
str.deleteCharAt(i);
i++;
} while(string.equals("("));
str.deleteCharAt(string.length() - 2);
return str.toString();
}
This is my code. When I pass Awaiting Research(5056) as an argument, the output given is waiting Research(5056. I want to trim the initial part of such string till ( and I want only the digits as my output. My expected output here is - 5056. Please help.
You don't need loops (in your code), you can use String.substring(int, int) in combination with String.indexOf(char):
public static void main(String[] args) {
// example input
String input = "Awaiting Research(5056)";
// find the braces and use their indexes to get the content
String output = input.substring(
input.indexOf('(') + 1, // index is exclusive, so add 1
input.indexOf(')')
);
// print the result
System.out.println(output);
}
Output:
5056
Hint:
Only use this if you are sure the input will always contain a ( and a ) with indexOf('(') < indexOf(')') or handle IndexOutOfBoundsExceptions, which will occur on most Strings not matching the braces constraint.
If your goal is just to look one numeric value of the string, try split the string with regex for the respective numeric value and then you'll have the number separated from the string
e.g:
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("somestringwithnumberlike123");
if(matcher.find()) {
System.out.println(matcher.group());
}
Using a regexp to extract what you need is a better option :
String test = "Awaiting Research(5056)";
Pattern p = Pattern.compile("([0-9]+)");
Matcher m = p.matcher(test);
if (m.find()) {
System.out.println(m.group());
}
For your case, battery use regular expression to extract your interested part.
Pattern pattern = Pattern.compile("(?<=\\().*(?=\\))");
Matcher matcher = pattern.matcher("Awaiting Research(5056)");
if(matcher.find())
{
return matcher.group();
}
It is much easier to solve the problem e.g. using the String.indexOf(..) and String.substring(from,to). But if, for some reason you want to stick to your approach, here are some hints:
Your code does what is does because:
string.equals("(") is only true if the given string is exacly "("
the do {code} while (condition)-loop executes code once if condition is not true -> think about using the while (condition) {code} loop instead
if you change the condition to check for the character at i, your code would remove the first, third, fifth and so on: After first execution i is 1 and char at i is now the third char of the original string (because the first has been removed already) -> think about always checking and removing charAt 0.
I have a List of strings like this "Taxi or bus driver". I need to convert first letter of each word to capital letter except the word "or" . Is there any easy way to achieve this using Java stream.
I have tried with Pattern.compile.splitasstream technique, I could not concat all splitted tokens back to form the original string
any help will be appreciated.If any body needs I can post my code here.
You need the right pattern to identify the location where a change has to be made, a zero-width pattern when you want to use splitAsStream. Match location which are
a word start
looking at a lower case character
not looking at the word “or”
Declare it like
static final Pattern WORD_START_BUT_NOT_OR = Pattern.compile("\\b(?=\\p{Ll})(?!or\\b)");
Then, using it to process the tokens is straight-forward with a stream and map. Getting a string back works via .collect(Collectors.joining()):
List<String> input = Arrays.asList("Taxi or bus driver", "apples or oranges");
List<String> result = input.stream()
.map(s -> WORD_START_BUT_NOT_OR.splitAsStream(s)
.map(w -> Character.toUpperCase(w.charAt(0))+w.substring(1))
.collect(Collectors.joining()))
.collect(Collectors.toList());
result.forEach(System.out::println);
Taxi or Bus Driver
Apples or Oranges
Note that when splitting, there will always be a first token, regardless of whether it matched the criteria. Since the word “or” usually never appears at the beginning of a phrase and the transformation is transparent to non-lowercase letter characters, this should not a problem here. Otherwise, treating the first element specially with a stream would make the code too complicated. If that’s an issue, a loop would be preferable.
A loop based solution could look like
private static final Pattern FIRST_WORD_CHAR_BUT_NOT_OR
= Pattern.compile("\\b(?!or\\b)\\p{Ll}");
(now using a pattern that matches the character rather than looking at it)
public static String capitalizeWords(String phrase) {
Matcher m = FIRST_WORD_CHAR_BUT_NOT_OR.matcher(phrase);
if(!m.find()) return phrase;
StringBuffer sb = new StringBuffer();
do m.appendReplacement(sb, m.group().toUpperCase()); while(m.find());
return m.appendTail(sb).toString();
}
which, as a bonus, is also capable of handling characters which span multiple char units. Starting with Java 9, the StringBuffer can be replaced with StringBuilder to increase the efficiency. This method can be used like
List<String> result = input.stream()
.map(s -> capitalizeWords(s))
.collect(Collectors.toList());
Replacing the lambda expression s -> capitalizeWords(s) with a method reference of the form ContainingClass::capitalizeWords is also possible.
Here is my code:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ConvertToCapitalUsingStreams {
// collection holds all the words that are not to be capitalized
private static final List<String> EXCLUSION_LIST = Arrays.asList(new String[]{"or"});
public String convertToInitCase(final String data) {
String[] words = data.split("\\s+");
List<String> initUpperWords = Arrays.stream(words).map(word -> {
//first make it lowercase
return word.toLowerCase();
}).map(word -> {
//if word present in EXCLUSION_LIST return the words as is
if (EXCLUSION_LIST.contains(word)) {
return word;
}
//if the word not present in EXCLUSION_LIST, Change the case of
//first letter of the word and return
return Character.toUpperCase(word.charAt(0)) + word.substring(1);
}).collect(Collectors.toList());
// convert back the list of words into a single string
String finalWord = String.join(" ", initUpperWords);
return finalWord;
}
public static void main(String[] a) {
System.out.println(new ConvertToCapitalUsingStreams().convertToInitCase("Taxi or bus driver"));
}
}
Note:
You may also want to look at this SO post about using apache commons-text library to do this job.
Split your string as words then convert first character to uppercase, then joining it to form original String:
String input = "Taxi or bus driver";
String output = Stream.of(input.split(" "))
.map(w -> {
if (w.equals("or") || w.length() == 0) {
return w;
}
return w.substring(1) + Character.toUpperCase(w.charAt(0));
})
.collect(Collectors.joining(" "));
How can I delete everything after first empty space in a string which user selects? I was reading this how to remove some words from a string in java. Can this help me in my case?
You can use replaceAll with a regex \s.* which match every thing after space:
String str = "Hello java word!";
str = str.replaceAll("\\s.*", "");
output
Hello
regex demo
Like #Coffeehouse Coder mention in comment, This solution will replace every thing if the input start with space, so if you want to avoid this case, you can trim your input using string.trim() so it can remove the spaces in start and in end.
Assuming that there is no space in the beginning of the string.
Follow these steps-
Split the string at space. It will create an array.
Get the first element of that array.
Hope this helps.
str = "Example string"
String[] _arr = str.split("\\s");
String word = _arr[0];
You need to consider multiple white spaces and space in the beginning before considering the above code.
I am not native to JAVA Programming but have an idea that it has split function for string.
And the reference you cited in the question is bit complex, while you can achieve the desired thing very easily.
P.S. In future if you make a mind to get two words or three, splitting method is better (assuming you have already dealt with multiple white-spaces) else substring is better.
A simple way to do it can be:
System.out.println("Hello world!".split(" ")[0]);
// Taking 'str' as your string
// To remove the first space(s) of the string,
str = str.trim();
int index = str.indexOf(" ");
String word = str.substring(0, index);
This is just one method of many.
str = str.replaceAll("\\s+", " "); // This replaces one or more spaces with one space
String[] words = str.split("\\s");
String first = words[0];
The simplest solution in my opinion would be to just locate the index which the user wants it to be cut off at and then call the substring() method from 0 to the index they wanted. Set that = to a new string and you have the string they want.
If you want to replace the string then just set the original string = to the result of the substring() method.
Link to substring() method: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring(int,%20int)
There are already 5 perfectly good answers, so let me add a sixth one. Variety is the spice of life!
private static final Pattern FIRST_WORD = Pattern.compile("\\S+");
public static String firstWord(CharSequence text) {
Matcher m = FIRST_WORD.matcher(text);
return m.find() ? m.group() : "";
}
Advantages over the .split(...)[0]-type answers:
It directly does exactly what is being asked, i.e. "Find the first sequence of non-space characters." So the self-documentation is more explicit.
It is more efficient when called on multiple strings (e.g. for batch processing a large list of strings) because the regular expression is compiled only once.
It is more space-efficient because it avoids unnecessarily creating a whole array with references to each word when we only need the first.
It works without having to trim the string.
(I know this is probably too late to be of any use to the OP but I'm leaving it here as an alternative solution for future readers.)
This would be more efficient
String str = "Hello world!";
int spaceInd = str.indexOf(' ');
if(spaceInd != -1) {
str = str.substring(0, spaceInd);
}
System.out.println(String.format("[%s]", str));
I have few lines of code, which I'm trying to convert to functional paradigm. The code is:
private String test(List<String> strings, String input) {
for (String s : strings) {
input = input.replace(s, ", ");
}
return input;
}
I need to make this one instruction chain. It must replace all strings from given list with coma IN given String input. I tried to do it with map method, but with no success. I'm aware I can do it if I appended input string into list at beginning and call map then, but the list is immutable, so I cannot do that.
I believe you can do this with a simple reduce:
strings.stream().reduce(input, (in, s) -> in.replace(s, ", "));
It takes the input, and replaces each occurence of the first string with ", ". Then it takes that result, and uses it as the input along with the next string, and repeats for every item in the list.
As Louis Wasserman points out, this approach cannot be used with parallelStream, so it won't work if you want parallelization.
The only think I can think of -- which is pretty awkward -- is
strings.stream()
.map(s -> (Function<String, String>) (x -> x.replace(s, ", ")))
.reduce(Function.identity(), Function::andThen)
.apply(input)
The following does pretty much the same thing.
private String test(List<String> strings, String input) {
return input.replaceAll(
strings
.stream()
.map(Pattern::quote)
.collect(Collectors.joining("|"))
, ", "
);
}
The main difference is that it first combines all the search strings into a single regex, and applies them all at once. Depending on size of your input strings, this may perform even better than your original use case.
If the list of strings is fixed, or changes only rarely, you can get some more speed from precompiling the joined pattern.
As per my project I need to devide a string into two parts.
below is the example:
String searchFilter = "(first=sam*)(last=joy*)";
Where searchFilter is a string.
I want to split above string to two parts
first=sam* and last=joy*
so that i can again split this variables into first,sam*,last and joy* as per my requirement.
I dont have much hands on experience in java. Can anyone help me to achieve this one. It will be very helpfull.
Thanks in advance
The most flexible way is probably to do it with regular expressions:
import java.util.regex.*;
public class Test {
public static void main(String[] args) {
// Create a regular expression pattern
Pattern spec = Pattern.compile("\\((.*?)=(.*?)\\)");
// Get a matcher for the searchFilter
String searchFilter = "(first=sam*)(last=joy*)";
Matcher m = spec.matcher(searchFilter);
// While a "abc=xyz" pattern can be found...
while (m.find())
// ...print "abc" equals "xyz"
System.out.println("\""+m.group(1)+"\" equals \""+m.group(2)+"\"");
}
}
Output:
"first" equals "sam*"
"last" equals "joy*"
Take a look at String.split(..) and String.substring(..), using them you should be able to achieve what you are looking for.
you can do this using split or substring or using StringTokenizer.
I have a small code that will solve ur problem
StringTokenizer st = new StringTokenizer(searchFilter, "(||)||=");
while(st.hasMoreTokens()){
System.out.println(st.nextToken());
}
It will give the result you want.
I think you can do it in a lot of different ways, it depends on you.
Using regexp or what else look at https://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html.
Anyway I suggest:
int separatorIndex = searchFilter.indexOf(")(");
String filterFirst = searchFilter.substring(1,separatorIndex);
String filterLast = searchFilter.substring(separatorIndex+1,searchFilter.length-1);
This (untested snippet) could do it:
String[] properties = searchFilter.replaceAll("(", "").split("\)");
for (String property:properties) {
if (!property.equals("")) {
String[] parts = property.split("=");
// some method to store the filter properties
storeKeyValue(parts[0], parts[1]);
}
}
The idea behind: First we get rid of the brackets, replacing the opening brackets and using the closing brackets as a split point for the filter properties. The resulting array includes the String {"first=sam*","last=joy*",""} (the empty String is a guess - can't test it here). Then for each property we split again on "=" to get the key/value pairs.