Java String split operation - java

When I split a string in java as shown in code below, it gives length as 3.
String data = "DK4..||VSDK4|";
String[] tokens = data.split("\\|");
System.out.println(tokens.length);
However it should be 4, what could be the reason behind this?

From the split method documentation:
Trailing empty strings are therefore not included in the resulting array.
This is because split with a single argument calls split with second argument as 0, which, according to that method's documentation
If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.

See the doc of split(String regex):
Splits this string around matches of the given regular expression.
This method works as if by invoking the two-argument split method with
the given expression and a limit argument of zero. Trailing empty
strings are therefore not included in the resulting array.
You can use split(String regex, int limit) with a negative limit to get all:
String[] tokens = data.split("\\|", -1);
If n is non-positive then the pattern will be applied as many times as
possible and the array can have any length. If n is zero then the
pattern will be applied as many times as possible, the array can have
any length, and trailing empty strings will be discarded.

Related

Weird behavior of Java's String.split() [duplicate]

I am trying to split the Value using a separator.
But I am finding the surprising results
String data = "5|6|7||8|9||";
String[] split = data.split("\\|");
System.out.println(split.length);
I am expecting to get 8 values. [5,6,7,EMPTY,8,9,EMPTY,EMPTY]
But I am getting only 6 values.
Any idea and how to fix. No matter EMPTY value comes at anyplace, it should be in array.
split(delimiter) by default removes trailing empty strings from result array. To turn this mechanism off we need to use overloaded version of split(delimiter, limit) with limit set to negative value like
String[] split = data.split("\\|", -1);
Little more details:
split(regex) internally returns result of split(regex, 0) and in documentation of this method you can find (emphasis mine)
The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array.
If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter.
If n is non-positive then the pattern will be applied as many times as possible and the array can have any length.
If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
Exception:
It is worth mentioning that removing trailing empty string makes sense only if such empty strings were created by the split mechanism. So for "".split(anything) since we can't split "" farther we will get as result [""] array.
It happens because split didn't happen here, so "" despite being empty and trailing represents original string, not empty string which was created by splitting process.
From the documentation of String.split(String regex):
This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array.
So you will have to use the two argument version String.split(String regex, int limit) with a negative value:
String[] split = data.split("\\|",-1);
Doc:
If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
This will not leave out any empty elements, including the trailing ones.
String[] split = data.split("\\|",-1);
This is not the actual requirement in all the time. The Drawback of above is show below:
Scenerio 1:
When all data are present:
String data = "5|6|7||8|9|10|";
String[] split = data.split("\\|");
String[] splt = data.split("\\|",-1);
System.out.println(split.length); //output: 7
System.out.println(splt.length); //output: 8
When data is missing:
Scenerio 2: Data Missing
String data = "5|6|7||8|||";
String[] split = data.split("\\|");
String[] splt = data.split("\\|",-1);
System.out.println(split.length); //output: 5
System.out.println(splt.length); //output: 8
Real requirement is length should be 7 although there is data missing. Because there are cases such as when I need to insert in database or something else. We can achieve this by using below approach.
String data = "5|6|7||8|||";
String[] split = data.split("\\|");
String[] splt = data.replaceAll("\\|$","").split("\\|",-1);
System.out.println(split.length); //output: 5
System.out.println(splt.length); //output:7
What I've done here is, I'm removing "|" pipe at the end and then splitting the String. If you have "," as a seperator then you need to add ",$" inside replaceAll.
From String.split() API Doc:
Splits this string around matches of the given regular expression.
This method works as if by invoking the two-argument split method with
the given expression and a limit argument of zero. Trailing empty
strings are therefore not included in the resulting array.
Overloaded String.split(regex, int) is more appropriate for your case.
you may have multiple separators, including whitespace characters, commas, semicolons, etc. take those in repeatable group with []+, like:
String[] tokens = "a , b, ,c; ;d, ".split( "[,; \t\n\r]+" );
you'll have 4 tokens -- a, b, c, d
leading separators in the source string need to be removed before applying this split.
as answer to question asked:
String data = "5|6|7||8|9||";
String[] split = data.split("[\\| \t\n\r]+");
whitespaces added just in case if you'll have those as separators along with |

Why aren't my last split patterns respected in this code

First thing first, here is my code:
String line = "Events|1005435529|7021370073||PAGELOAD|2017-06-19T12:04:40||JI||ServerHostName|ServerIPAddress|9P2_D2jB9Toct7PDTJ7zwLUmWfEYz6Y4akyOKn2g4CepveMH4wr3!46548593!1497854077121|||||||||||";
int offset = line.indexOf("Events");
String zeroIn = line.substring(offset);
String[] jsonElements = zeroIn.split("\\|");
System.out.println(Arrays.asList(jsonElements));
Output:
[Events, 1005435529, 7021370073, , PAGELOAD, 2017-06-19T12:04:40, , JI, , ServerHostName, ServerIPAddress, 9P2_D2jB9Toct7PDTJ7zwLUmWfEYz6Y4akyOKn2g4CepveMH4wr3!46548593!1497854077121]`
I also notice spaces added to each array element at the beginning.
My question is that I have almost 10 empty pipeline symbols at the end of the String line while as the first second and third occurance of empty pipeline symbols is respected, the last ones are missed and don't add up in the array. What do I miss here?
split(java.lang.String regex) calls split(java.lang.String regex ,int limit) with an argument of 0.
If n is zero then the pattern will be applied as many times as
possible, the array can have any length, and trailing empty strings
will be discarded.
You may call this method by yourself with a positive value (and large enough to be sure to include all tokens) to prevent empty tokens from being discarded :
String[] jsonElements = zeroIn.split("\\|", zeroIn.length());
Note : from the comments below, using a negative value is indeed a better way to do this :
String[] jsonElements = zeroIn.split("\\|", -1);
If n is non-positive then the pattern will be applied as many times as
possible and the array can have any length.
From String class and split method doc:
Trailing empty strings are therefore not included in the resulting array.
So, after last occurrence of not empty string, rest will be not included in array.
The accepted answer explains the limitations you oberved splitting on a single character delimeter. I thought I would offer this answer if you need the ability to retain empty tokens in your output. If you split using a lookaround, e.g. a lookbehind, then you would end up with distinct entries even when two pipes have nothing in between them:
String line = "Events|1005435529|7021370073||PAGELOAD|2017-06-19T12:04:40||JI||ServerHostName|ServerIPAddress|9P2_D2jB9Toct7PDTJ7zwLUmWfEYz6Y4akyOKn2g4CepveMH4wr3!46548593!1497854077121|||||||||||";
String[] parts = line.split("(?<=\\|)");
for (String part : parts) {
System.out.println(part);
}
Demo here:
Rextester

Confused with using split with multiple delimiters

I'm practicing reading input and then tokenizing it.
For example, if I have [882,337] I want to just get the numbers 882 and 337. I tried using the following code:
String test = "[882,337]";
String[] tokens = test.split("\\[|\\]|,");
System.out.println(tokens[0]);
System.out.println(tokens[1]);
System.out.println(tokens[2]);
It kind of works, the output is:
(blank line)
882
337
What I don't understand is why token[0] is empty? I would expect there to only be two tokens where token[0] = 882 and token[1] = 337.
I checked out some links but didn't find the answer.
Thanks for the help!
Split splits the given String. If you split "[882,337]" on "[" or "," or "]" then you actually have:
nothing
882
337
nothing
But, as you have called String.split(delimiter), this calls String.split(delimiter, limit) with a limit of zero.
From the documentation:
The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
(emphasis mine)
So in this configuration the final, empty, strings are discarded. You are therefore left with exactly what you have.
Usually, to tokenize something like this, one would go for a combination of replaceAll and split:
final String[] tokens = input.replaceAll("^\\[|\\]$").split(",");
This will first strip off the start (^[) and end (]$) brackets and then split on ,. This way you don't have to have somewhat obtuse program logic where you start looping from an arbitrary index.
As an alternative, for more complex tokenizations, one can use Pattern - might be overkill here, but worth bearing in mind before you get into writing multiple replaceAll chains.
First we need to define, in Regex, the tokens we want (rather than those we're splitting on) - in this case it's simple, it's just digits so \d.
So, in order to extract all digit only (no thousands/decimal separators) values from an arbitrary String on would do the following:
final List<Integer> tokens = new ArrayList<>(); <-- to hold the tokens
final Pattern pattern = Pattern.compile("\\d++"); <-- the compiled regex
final Matcher matcher = pattern.matcher(input); <-- the matcher on input
while(matcher.find()) { <-- for each matched token
tokens.add(Integer.parseInt(matcher.group())); <-- parse and `int` and store
}
N.B: I have used a possessive regex pattern for efficiency
So, you see, the above code is somewhat more complex than the simple replaceAll().split(), but it is much more extensible. You can use arbitrary complex regex to token almost any input.
The symbols where the string is split are here:
String test = "[882,337]";
^ ^ ^
Because The first char matches your delimiter, everything left from it will be the first result. Well, left from the first letter is nothing, so the result is the empty string.
One could expect the same behaviour for the end, since the last symbol also matches the delimiter. But:
Trailing empty strings are therefore not included in the resulting array.
See Javadoc.
Splitting creates two (or more) things from one thing. For instance if you split a,b by , you will get a and b.
But in case of ",b" you will get "" and "b". You can think of it this way:
"" exists at start, end and even in-between all characters of string:
""+","+"b" -> ",b" so if we split on this "," we are getting left and right part: "" and "b"
Similar things happens in case of "a," and at first result array is ["a",""] but here split method removes trailing empty strings and returns only ["a"] (you can turn off this clearing mechanism by using split(",", -1)).
So in case of
String test = "[882,337]";
String[] tokens = test.split("\\[|\\]|,");
you are splitting:
""+"["+"882"+","+"337"+"]"+""
here: ^ ^ ^
which at first creates array ["", "882", "337", ""] but then trailing empty string is removed and finally you are receiving:
["", "882", "337"]
Only case where empty string is removed from start of result array is when
you are using Java 8 (or newer) and splitting on regex which is zero-length like split("") or lets say before each x with split("(?=x)") (more info at: Why in Java 8 split sometimes removes empty strings at start of result array?)
and when this empty string was result of split method. For instance "".split("") will not remove "", more info here: https://stackoverflow.com/a/25058091/1393766
That's because each delimiter has a "before" and "after" result, even if it is empty. Consider
882,337
You expect that to produce two results.
Similarly, you expect
882,337,
to produce three, with the last one being empty (assuming your limit is big enough, or assuming you're using almost any other language / implementation of split()). Extending that logically,
,882,337,
must produce four, with the first and last results being empty. This is exactly the case you have, except you have multiple delimiters.

How to split a comma-delimited string into an array of empty strings [duplicate]

This question already has answers here:
Java String split removed empty values
(5 answers)
Closed 1 year ago.
I want to split ",,," to a array of 4 "" using the String.split()
Here is my code:
String str = ",,,";
String[] tokens = str.split(",");
However, the result tokens were an an empty array: [], rather than an array of 4 "" (["","","",""]) as I wanted.
I have tested to change the str a little bit:
String str = ",,,1";
String[] tokens = str.split(",");
This time the result tokens were ["","","","1"]. This is close to what I want, but I really do not want to add this "1" before doing the split.
The problem is basically, the String.split() will return an empty array if it contains only empty elements "".
Can you help solve the problem?
You need to use the overloaded String#split(regex, limit) method which takes in the limit parameter.
String[] tokens = str.split(",", -1);
From the docs(emphasis mine):
The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
Explanation: When you do not provide the limit argument or provide "zero" as the limit, the split() discards trailing empty fields. When you provide a positive limit argument, it limits the number of fields to that particular limit. But when you provide a negative limit, the split() method allows any number of fields and also not discarding the trailing empty fields. To be more clear, have a look at the source code of the Pattern#split(regex, limit) which has this snippet at the end(comments have been added by me and were not present in the actual source code).
if (limit == 0) // When zero or no arg is given
while (resultSize > 0 && matchList.get(resultSize-1).equals("")) // if trailing entries are blank
resultSize--; // remove them out
Note: If you do not provide any limit argument, the split() method without limit argument calls the overloaded split() method like this.
public String[] split(String regex) {
return split(regex, 0);
}
And also note that, String#split(regex, limit) internally calls the Pattern#split(regex, limit).

Java : split a string that containing special characters

I have a string like ||81|||01|| and I want to split the string with | symbol.
I had done this way,
String str = "||81|||01||";
System.out.println(str .split("\\|").length); //printing 6 . But I am expecting 8
what is wrong with this code? | How can I split this string with that character so that I will get expected length (8)?;
Using split("\\|") is the same as split("\\|", 0), where the limit parameter 0 tells the function "omit trailing empty strings". So you are missing the last two empty strings. Use the two-argument version and supply a negative number to obtain all parts (even trailing empty ones):
str.split("\\|", -1)
Print:
System.out.println(Arrays.toString(str.split("\\|")));
And you'll understand why it's printing 6.
You can try doing what you want using public String[] split(String regex, int limit):
The limit parameter controls the number of times the pattern is
applied and therefore affects the length of the resulting array.
So you should do:
System.out.println(str.split("\\|", -1).length);
Now, printing the array will print:
[, , 81, , , 01, , ] as you expected.
You can also use string.split(Pattern.quote("|"),-1) for spliting a string on a special character.
You need to use:
str.split("\\|", -1)
The second parameter is limit. From the javadoc:
The limit parameter controls the number of times the pattern is
applied and therefore affects the length of the resulting array. If
the limit n is greater than zero then the pattern will be applied at
most n - 1 times, the array's length will be no greater than n, and
the array's last entry will contain all input beyond the last matched
delimiter. If n is non-positive then the pattern will be applied as
many times as possible and the array can have any length. If n is zero
then the pattern will be applied as many times as possible, the array
can have any length, and trailing empty strings will be discarded.
str.split("\\|", -1) will do the necessary.
Possible duplicate : Here
String str = "||81|||01||";
System.out.println(str.split("\\|", 8).length);
The second argument to split specifies maximum number of matches. Single argument split is like invoking split(str, 0) which leaves out trailing strings. See javadoc of both for more explaination.

Categories

Resources