Android String.split("") returning extra element - java

I am trying to split a word into its individual letters.
I tried both String.split("") and String.split("|") however when I split a word it is creating a extra empty element.
Example:
word = "word";
int n = word.length();
Log.i("20",Integer.toString(n));
String[] letters = word.split("|");
Log.i("25",Integer.toString(letters.length));
The output in the Android Monitor is:
07-21 15:50:23.084 5711-5711/com.strizhevskiy.movetester I/20: 4
07-21 15:50:23.085 5711-5711/com.strizhevskiy.movetester I/25: 5
I put the individual letters into TextView blocks and I can actually see an extra empty TextView.
When I test these methods in my regular Java it outputs the expected answer: 4.
I am almost tempted to think this is an actual bug in Android's implementation of the method.

I am thinking you want to do this:
public Character[] toCharacterArray( String s ) {
if ( s == null ) {
return null;
}
int len = s.length();
Character[] array = new Character[len];
for (int i = 0; i < len ; i++) {
array[i] = new Character(s.charAt(i));
}
return array;
}
Instead of splitting a word without delimiters?
I hope this helps!

It's hard to say if it's bug or expected behavior, because what are you doing doesn't make sense. You are trying to split string with logical OR (split is waiting for Regular expression, not just a string), so as result it could be different result in Android comparing with normal java, and I don't see there any issue.
Anyway, there is many ways to achieve what you want in a normal way, e.g. just iterating over word by each char in a cycle or just use toCharArray String's method.

Thank you for the suggestions. My current work-around is to use a mock array and copying over into a fresh array using System.arraycopy().
String[] mockLetters = word.split("");
int n = word.length();
String[] letters = new String[n];
System.arraycopy(mockLetters,1,letters,0,n);
I appreciate the suggestions to use toCharArray(). However, these letters then get put into TextViews and TextView doesnt seem to accept char. I could, of coarse, make it work but I've decided to stick with what I currently have.
Tom, in a comment to my question, answered my underlying issue:
Why String.split() worked differently in Android than it does in Java?
Apparently the rules for String.split() changed with Java 8.

Try passing a 0 as the limit per the documentation below so that the trailing spaces are discarded.
String[] split (String regex,
int limit)
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

How to divide a string into equal groups of n characters padded with blank spaces in Java?

How to create a method that will take imput of a String and an integer n and output the String divided into parts consisting of n characters and separated by a blank space? For example, imput String: "THISISFUN", integer:3, result: "THI SIS FUN".
When you answer, can you please really try to explain what each part of the code does? I really want to understand it.
I tried using StringBuilder and the split() method but the problem is that I don't understand how all of that works. Therefore, I ended up kind of thoughtlessly pasting parts of codes from different online articles which doesn't work the best if you want to actually learn something, especially if you simply cannot find any posts about a specific issue. I could only find things like: "how to divide the String into n parts" and "how to ad a space after a specific char" which are sort of similar issues but not the same.
Here is one way to do it:
public static void splitString(String str, int groupSize){
char[] arr = str.toCharArray(); // Split the string into character array ①
// Iterate over array and print the characters
for(int i=0; i<arr.length; i++){
// If 'i' is a multiple of 'groupSize' ②
if(i > 0 && i % groupSize == 0){ ③
System.out.print(" ");
}
System.out.print(arr[i]);
}
}
① Split the string into a character array (so that you can access the characters individually). You can also do it using the charAt() method without splitting the string into an array. Read the Javadoc for more details.
② Check if the loop counter i is a multiple of groupSize
③ Note the use of System.out.print() as we do not want to print a newline. Here you can use a StringBuilder too and print the contents at the end instead of printing the characters inside the loop.

Swapping portions of text in a String in Java

I currently have a String and I am looking to swap every 4 characters with another set of four characters. EG
Input: 1001 1101 0001 1001
Output:1101 1001 1001 0001
I really have no idea how to actually swap the characters. Would I do character by character, or is there some way that I could swap multiple ones at a time. Thanks very much! :)
String.replace() method would be appropriate I guess.
String in Java are immutable, meaning you can't change them. If you want to do modifications like this, use StringBuilder instead. It has methods to get and replace substrings (in your case a substring of 4 characters).
API: http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html
I would split the string on spaces which would result in an array of Strings.
From there you could loop through each string and replace it to your desired result. After that is done, you can build it back into a string using StringBuilder
String input = "1001 1101 0001 1001";
//make array of strings in order to swap them, space being the common trait
String[] array = input.split("\\s");
//then swap array elements
for(int i = 0;i<array.length-1;i+=2){
String tmp = array[i];
array[i]= array[i+1];
array[i+1] = tmp;
}
//build the output
String output = "";
for(int i = 0;i<array.length;i++){
if(i<array.length-1)
output+= array[i] + " ";
else
output+= array[i];
}
StringBuilder.replace() would be more appropriate than String.replace() since it does not copy the entire string.
Even better for performance a char[] may work well if you know the size of your string will be constant. The replace() calls all shift the chars unnecessarily if you are always replacing a fix count of characters.
Finally Apache Commons has StringUtils.overlay() and some other helpful String utils if you'd like to consider a third party library ( in case they'd help with other requirements )

Determining if a given string of words has words greater than 5 letters long

So, I'm in need of help on my homework assignment. Here's the question:
Write a static method, getBigWords, that gets a String parameter and returns an array whose elements are the words in the parameter that contain more than 5 letters. (A word is defined as a contiguous sequence of letters.) So, given a String like "There are 87,000,000 people in Canada", getBigWords would return an array of two elements, "people" and "Canada".
What I have so far:
public static getBigWords(String sentence)
{
String[] a = new String;
String[] split = sentence.split("\\s");
for(int i = 0; i < split.length; i++)
{
if(split[i].length => 5)
{
a.add(split[i]);
}
}
return a;
}
I don't want an answer, just a means to guide me in the right direction. I'm a novice at programming, so it's difficult for me to figure out what exactly I'm doing wrong.
EDIT:
I've now modified my method to:
public static String[] getBigWords(String sentence)
{
ArrayList<String> result = new ArrayList<String>();
String[] split = sentence.split("\\s+");
for(int i = 0; i < split.length; i++)
{
if(split[i].length() > 5)
{
if(split[i].matches("[a-zA-Z]+"))
{
result.add(split[i]);
}
}
}
return result.toArray(new String[0]);
}
It prints out the results I want, but the online software I use to turn in the assignment, still says I'm doing something wrong. More specifically, it states:
Edith de Stance states:
⇒     You might want to use: +=
⇒     You might want to use: ==
⇒     You might want to use: +
not really sure what that means....
The main problem is that you can't have an array that makes itself bigger as you add elements.
You have 2 options:
ArrayList (basically a variable-length array).
Make an array guaranteed to be bigger.
Also, some notes:
The definition of an array needs to look like:
int size = ...; // V- note the square brackets here
String[] a = new String[size];
Arrays don't have an add method, you need to keep track of the index yourself.
You're currently only splitting on spaces, so 87,000,000 will also match. You could validate the string manually to ensure it consists of only letters.
It's >=, not =>.
I believe the function needs to return an array:
public static String[] getBigWords(String sentence)
It actually needs to return something:
return result.toArray(new String[0]);
rather than
return null;
The "You might want to use" suggestions points to that you might have to process the array character by character.
First, try and print out all the elements in your split array. Remember, you do only want you look at words. So, examine if this is the case by printing out each element of the split array inside your for loop. (I'm suspecting you will get a false positive at the moment)
Also, you need to revisit your books on arrays in Java. You can not dynamically add elements to an array. So, you will need a different data structure to be able to use an add() method. An ArrayList of Strings would help you here.
split your string on bases of white space, it will return an array. You can check the length of each word by iterating on that array.
you can split string though this way myString.split("\\s+");
Try this...
public static String[] getBigWords(String sentence)
{
java.util.ArrayList<String> result = new java.util.ArrayList<String>();
String[] split = sentence.split("\\s+");
for(int i = 0; i < split.length; i++)
{
if(split[i].length() > 5)
{
if(split[i].matches("[a-zA-Z]+"))
{
result.add(split[i]);
}
if (split[i].matches("[a-zA-Z]+,"))
{
String temp = "";
for(int j = 0; j < split[i].length(); j++)
{
if((split[i].charAt(j))!=((char)','))
{
temp += split[i].charAt(j);
//System.out.print(split[i].charAt(j) + "|");
}
}
result.add(temp);
}
}
}
return result.toArray(new String[0]);
}
Whet you have done is correct but you can't you add method in array. You should set like a[position]= spilt[i]; if you want to ignore number then check by Float.isNumber() method.
Your logic is valid, but you have some syntax issues. If you are not using an IDE like Eclipse that shows you syntax errors, try commenting out lines to pinpoint which ones are syntactically incorrect. I want to also tell you that once an array is created its length cannot change. Hopefully that sets you off in the right directions.
Apart from syntax errors at String array declaration should be like new String[n]
and add method will not be there in Array hence you should use like
a[i] = split[i];
You need to add another condition along with length condition to check that the given word have all letters this can be done in 2 ways
first way is to use Character.isLetter() method and second way is create regular expression
to check string have only letter. google it for regular expression and use matcher to match like the below
Pattern pattern=Pattern.compile();
Matcher matcher=pattern.matcher();
Final point is use another counter (let say j=0) to store output values and increment this counter as and when you store string in the array.
a[j++] = split[i];
I would use a string tokenizer (string tokenizer class in java)
Iterate through each entry and if the string length is more than 4 (or whatever you need) add to the array you are returning.
You said no code, so... (This is like 5 lines of code)

which code is more efficient?

which of the following is an efficient way to reverse words in a string ?
public String Reverse(StringTokenizer st){
String[] words = new String[st.countTokens()];
int i = 0;
while(st.hasMoreTokens()){
words[i] = st.nextToken();i++}
for(int j = words.length-1;j--)
output = words[j]+" ";}
OR
public String Reverse(StringTokenizer st, String output){
if(!st.hasMoreTokens()) return output;
output = st.nextToken()+" "+output;
return Reverse(st, output);}
public String ReverseMain(StringTokenizer st){
return Reverse(st, "");}
while the first way seems more readable and straight forward, there are two loops in it. In the 2nd method, I've tried doing it in tail-recursive way. But I am not sure whether java does optimize tail-recursive code.
you could do this in just one loop
public String Reverse(StringTokenizer st){
int length = st.countTokens();
String[] words = new String[length];
int i = length - 1;
while(i >= 0){
words[i] = st.nextToken();i--}
}
But I am not sure whether java does optimize tail-recursive code.
It doesn't. Or at least the Sun/Oracle Java implementations don't, up to and including Java 7.
References:
"Tail calls in the VM" by John Rose # Oracle.
Bug 4726340 - RFE: Tail Call Optimization
I don't know whether this makes one solution faster than the other. (Test it yourself ... taking care to avoid the standard micro-benchmarking traps.)
However, the fact that Java doesn't implement tail-call optimization means that the 2nd solution is liable to run out of stack space if you give it a string with a large (enough) number of words.
Finally, if you are looking for a more space efficient way to implement this, there is clever way that uses just a StringBuilder.
Create a StringBuilder from your input String
Reverse the characters in the StringBuilder using reverse().
Step through the StringBuilder, identifying the start and end offset of each word. For each start/end offset pair, reverse the characters between the offsets. (You have to do this using a loop.)
Turn the StringBuilder back into a String.
You can test results by timing both of them on a large amount of results
eg. You reverse 100000000 strings and see how many seconds it takes. You could also compare start and end system timestamps to get the exact difference between the two functions.
StringTokenizer is not deprecated but if you read the current JavaDoc...
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
String[] strArray = str.split(" ");
StringBuilder sb = new StringBuilder();
for (int i = strArray.length() - 1; i >= 0; i--)
sb.append(strArray[i]).append(" ");
String reversedWords = sb.substring(0, sb.length -1) // strip trailing space

Splitting string N into N/X strings

I would like some guidance on how to split a string into N number of separate strings based on a arithmetical operation; for example string.length()/300.
I am aware of ways to do it with delimiters such as
testString.split(",");
but how does one uses greedy/reluctant/possessive quantifiers with the split method?
Update: As per request a similar example of what am looking to achieve;
String X = "32028783836295C75546F7272656E745C756E742E657865000032002E002E005C0"
Resulting in X/3 (more or less... done by hand)
X[0] = 32028783836295C75546F
X[1] = 6E745C756E742E6578650
x[2] = 65000032002E002E005C0
Dont worry about explaining how to put it into the array, I have no problem with that, only on how to split without using a delimiter, but an arithmetic operation
You could do that by splitting on (?<=\G.{5}) whereby the string aaaaabbbbbccccceeeeefff would be split into the following parts:
aaaaa
bbbbb
ccccc
eeeee
fff
The \G matches the (zero-width) position where the previous match occurred. Initially, \G starts at the beginning of the string. Note that by default the . meta char does not match line breaks, so if you want it to match every character, enable DOT-ALL: (?s)(?<=\G.{5}).
A demo:
class Main {
public static void main(String[] args) {
int N = 5;
String text = "aaaaabbbbbccccceeeeefff";
String[] tokens = text.split("(?<=\\G.{" + N + "})");
for(String t : tokens) {
System.out.println(t);
}
}
}
which can be tested online here: http://ideone.com/q6dVB
EDIT
Since you asked for documentation on regex, here are the specific tutorials for the topics the suggested regex contains:
\G, see: http://www.regular-expressions.info/continue.html
(?<=...), see: http://www.regular-expressions.info/lookaround.html
{...}, see: http://www.regular-expressions.info/repeat.html
If there's a fixed length that you want each String to be, you can use Guava's Splitter:
int length = string.length() / 300;
Iterable<String> splitStrings = Splitter.fixedLength(length).split(string);
Each String in splitStrings with the possible exception of the last will have a length of length. The last may have a length between 1 and length.
Note that unlike String.split, which first builds an ArrayList<String> and then uses toArray() on that to produce the final String[] result, Guava's Splitter is lazy and doesn't do anything with the input string when split is called. The actual splitting and returning of strings is done as you iterate through the resulting Iterable. This allows you to just iterate over the results without allocating a data structure and storing them all or to copy them into any kind of Collection you want without going through the intermediate ArrayList and String[]. Depending on what you want to do with the results, this can be considerably more efficient. It's also much more clear what you're doing than with a regex.
How about plain old String.substring? It's memory friendly (as it reuses the original char array).
well, I think this is probably as efficient a way to do this as any other.
int N=300;
int sublen = testString.length()/N;
String[] subs = new String[N];
for(int i=0; i<testString.length(); i+=sublen){
subs[i] = testString.substring(i,i+sublen);
}
You can do it faster if you need the items as a char[] array rather as individual Strings - depending on how you need to use the results - e.g. using testString.toCharArray()
Dunno, you'll probably need a method that takes string and int times and returns a list of strings. Pseudo code (haven't checked if it works or not):
public String[] splintInto(String splitString, int parts)
{
int dlength = splitString.length/parts
ArrayList<String> retVal = new ArrayList<String>()
for(i=0; i<splitString.length;i+=dlength)
{
retVal.add(splitString.substring(i,i+dlength)
}
return retVal.toArray()
}

Categories