In some place of a class I have declared a temporal String variable:
String name;
Which I will use to store data from a text. The text have many fields with these two types of format:
Type: text/html
name=foo
For this case, I am particularly interested in the fields of the type name=foo
So, I breaked previously the lines of the text using split
String lines[] = text.split("\n");
And, again, I will use split to identify the fields of the type mentioned. In the code below, the while cycle stops where it detects a name=foo field, and prints the value of that field in the console.
int i = 0; // Counter for the while cycle
while (!(lines[i].split("=")[0].equals("name"))) {
i++;
if (lines[i].split("=")[0].equals("name")) // If the field is name...
System.out.println(lines[i].split("=")[1]); // Prints the value of the field
name = lines[i].split("=")[1]; // <-- My problem is here
}
My problem starts when I want to copy the value of the field to the String variable mentioned early, giving me an java.lang.ArrayIndexOutOfBoundsException.
I need that String to do something with it later. Any idea to safely copy the value of that field to a String variable?
Adding paranthesis to your if saves you from two problems:
if a line contains no = the whole String is in [0] and accessing [1] will result in said Exception
you are changing (overwriting) the variable name regardless of the condition
To please the compiler you may also want to intialize name to something like null.
int i = 0; // Counter for the while cycle
while (!(lines[i].split("=")[0].equals("name"))) {
i++;
if (lines[i].split("=")[0].equals("name")){ // If the field is name...
System.out.println(lines[i].split("=")[1]); // Prints the value of the field
name = lines[i].split("=")[1]; // <-- My problem is here
}
}
In your code:
String name;
name = lines[i].split("=")[1];
Here name will overwrite every time.
I think you are looking for something like this:
String names[];
String lines[] = text.split("\n");
names[] = new String[lines.length];
And inside you while loop do it like:
names[i] = lines[i].split("=")[1];
There are quite a few things to note about your code:
you probably miss {} after the if-statement and therefore update name every run of the while-loop
you access [1] without checking how many elements the split("=") yielded
you literally call split("=") 4 times on almost every line. Save CPU-time by introducing a temporary variable!
you can replace your while-loop by a for-loop which also finds name=value in the first line and does not "throw up" if name=value is not inside any of the lines (you don't check whether i is less than lines.length)
I left your comments inside my answer; feel free to remove them.
Variant a (using an index):
for (int i = 0; i < lines.length; i++) {
// Only split once and keep X=Y together in name=X=Y by specifying , 2
final String[] split = lines[i].split("=", 2);
if (split.length == 2 && split[0].equals("name")){ // If the field is name...
System.out.println(split[1]); // Prints the value of the field
name = split[1]; // <-- My problem is here
break; // no need to look any further
}
}
Variant b (using "for-each"):
for (String line : lines) {
// Only split once and keep X=Y together in name=X=Y by specifying , 2
final String[] split = line.split("=", 2);
if (split.length == 2 && split[0].equals("name")) { // If the field is name...
System.out.println(split[1]); // Prints the value of the field
name = split[1]; // <-- My problem is here
break; // no need to look any further
}
}
I suppose your problem is when you reach the last line or a line which doesn't contains a "=" sign. You are checking
!(lines[i].split("=")[0].equals("name"))
but then you add 1 to i, so maybe this condition now is false
if (lines[i].split("=")[0].equals("name"))
and you will get java.lang.ArrayIndexOutOfBoundsException here
name = lines[i].split("=")[1];
if the line doesn't contains a "=".
Try
if (lines[i].split("=")[0].equals("name")) { // If the field is name...
System.out.println(lines[i].split("=")[1]); // Prints the value of the field
name = lines[i].split("=")[1];
}
Related
I'm making a minecraft-forge mod and I'm having problems putting an String into Block#getBlockFromName(String name). the String:
String oreName = "minecraft:iron_ore -replace:minecraft:stone.minecraft:netherrack.minecraft:end_stone;";
And like you see after -replace: I have an block name (minecraft:stone) and a dot and than again block name and a dot. I want to split each block name into a separate String and read it one by one so I can insert it into Block#getBlockFromName and get 1 block out of each String. I tried using String#split(".") to split it into an array, but when I print out the array when I switched it back to String by using Arrays#toString it was empty. I want to split it by dots because I have an config file so those blocks can be changed to anything, I can't just pull out minecraft:stone out of the String because the ones who are using my mod will be able to configure that minecraft:stone to something else and add another block name by using a dot after the first block name.
This is what I've done so far:
String oreName = "minecraft:iron_ore -replace:minecraft:stone.minecraft:netherrack.minecraft:end_stone;";
String block1 = oreName.substring(oreName.indexOf("-replace:"));
String block2 = block1.replace("-replace:", "");
String block3 = block2.contains(" -") ? block2.substring(0, block2.indexOf(" ")) : block2.replace(";", "");
System.out.println("The Block Names Are: " + block3); // It prints it just without "minecraft:iron_ore -replace:" and ";" at the end
String[] block4 = block3.split(".");
System.out.println("The array: " + Arrays.toString(block4)); // only prints out "The array: []"
Problem is that String.split() takes regular expression as argument.
For your case you need to escape . symbol with:
String[] block4 = block3.split("\\.");
Which prints
The array: [minecraft:stone, minecraft:netherrack, minecraft:end_stone]
I am trying to read users id and their link type from a txt file. The data is given in following format.
SRC:aa
TGT:bb
VOT:1
SRC:cc
TGT:bb
VOT:-1
where 'SRC' and 'TGT' indicators of the users id. In data, some users ids are blank, i.e. users disagree to reveal their identities as following:
SRC:
TGT:cc
VOT:-1
SRC:ff
TGT:bb
VOT:1
In this case, I want to give them a special id, "anonymous". So, I wrote the following code:
//Reading source
dataline = s.nextLine();
String[] line1parts = new String[2];
.
.
//split the line at ":"
line1parts = dataline.split(":");
//if the line has source
if (line1parts[0].trim().equals("SRC")){
//if the soruce name is empty
if (line1parts[1].isEmpty()) {
src = "anonymous";
System.out.print("src: " + src);
}
//if the source already integer id
else {
src = line1parts[1].trim();
System.out.print("src: " + src);
}
}
The program shows java.lang.ArrayIndexOutOfBoundsException error. I have also tried if (line1parts[1].equals("") and if (line1parts[1].equals(null). Probably for the case SRC: (when empty) the string array is not creating any object (sorry if I am wrong. I am very new in java). How can I assign an user ID when it is empty? Thanks in advance.
If a line only contains SRC: the line1parts array will have only one item, thus line1parts[1] raises an ArrayIndexOutOfBoundsException .
Replace if (line1parts[1].isEmpty()) by if (line1parts.length < 2 )
Has StephaneM made me remember, the split method trim the empty cell during the splitting. This removed every empty cells at the end. This mean the empty cell if there is no SRC value in your case
To prevent this, you can call
java.lang.String.split(String, int)
This integer specify the length of the array you want, at minimum.
line1parts = dataline.split(":", 2);
You are sure to receive an array with length of 2 or more. So this could still remove some cells, but with a length constraint.
A good think to know is that if you send -1, the split will return EVERY cells. No trimming is done.
You are trying to get the index which is not present.
split() helps to divide value from regex you provided.
you are split the string
1."TGT:cc" in this case split method split String value from ":" and it is returning an array of size 2 i.e. [TGT,cc] (it has 0 and 1 index).
2.When you split the String "SRC:" in this case split method create an array of size 1 i.e [SRC] (it has only 0 index) because in this String after ":" nothing and so that it does not create extra index for null value.
When you call "line1parts[1].isEmpty()" it throw ArrayIndexOutOfBoundsException because it does not have the index 1.
Here you have to check "line1parts.length" before call "line1parts[1].isEmpty()".
line1parts = dataline.split(":");
// if the line has source
if (line1parts[0].trim().equals("SRC")) {
if (line1parts.length > 1) {
// if the soruce name is empty
if (line1parts[1].isEmpty()) {
src = "anonymous";
System.out.print("src: " + src);
}
// if the source already integer id
else {
src = line1parts[1].trim();
System.out.print("src: " + src);
}
}
}
Or-----------------
You have to do ::
line1parts = dataline.split(":",2);
I have taken the following code snippet from the 5th snippet on this developer guide on Content Providers.
The confusion is that in the first statement String[] mSelectionArgs = {""};, mSelectionArgs[0] IS set to "".
Then later if the mSearchString is empty (TextUtils.isEmpty(mSearchString)), then again mSelectionArgs[0] is assigned "".
So the question is that why are they setting it to an empty string when it is already initialized to an empty string?
/*
* This defines a one-element String array to contain the selection argument.
*/
String[] mSelectionArgs = {""};
// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();
// Remember to insert code here to check for invalid or malicious input.
// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
// Setting the selection clause to null will return all words
mSelectionClause = null;
mSelectionArgs[0] = "";
} else {
// Constructs a selection clause that matches the word that the user entered.
mSelectionClause = UserDictionary.Words.WORD + " = ?";
// Moves the user's input string to the selection arguments.
mSelectionArgs[0] = mSearchString;
}
...
I like it, because it's symmetric
if something
var = x
else
var = y
It's clear what var is under each condition, without needing to go back and visit its initial value.
Except for additional clarity and code readability, as noted in another answer, this coding style makes for a less error prone code which is easier to maintain.
This way, if the initial value of mSelectionArgs is changed, or new code added which overrides this value before the execution of the if-else block, the code of this block will still execute correctly. Without this "rudimentary" assignment, a change as described above could lead to a bug which would be very difficult to trace.
As a side note:
This specific code snippet is not that good (yes, I know it is from Android Developers site...) - if you pass null as selection argument to query(), then it is better to also pass null as selectionArgs argument. I'd modify this sample to something like this (setting both selection and selectionArgs to null):
// Gets a word from the UI
mSearchString = mSearchWord.getText().toString();
// Remember to insert code here to check for invalid or malicious input.
String[] mSelectionArgs = null;
// If the word is the empty string, gets everything
if (TextUtils.isEmpty(mSearchString)) {
// Setting the selection clause to null will return all words
mSelectionClause = null;
mSelectionArgs = null;
} else {
// Constructs a selection clause that matches the word that the user entered.
mSelectionClause = UserDictionary.Words.WORD + " = ?";
// Moves the user's input string to the selection arguments.
mSelectionArgs = new String[] {mSearchString};
}
Edit: why the above code snippet is better than the original one?
It is not an error to pass null as selection and non-null as selectionArgs. This array will be passed to the specific ContentProvider you're addressing, and shouldn't be used at all since selection does not contain any ? placeholders. Any ContentProvider violating this assumption is buggy. Although not an error, it just looks weird - why do you pass an object that should be ignored anyway? This also has performance cost (which is higher if ContentProvider runs in different process), which is proportional to the size of the object being passed.
Edit 2: why the above code snippet is MUCH better than the original one?
Turns out that what I said above might be misleading. I found it out the hard way:
Caused by: java.lang.IllegalArgumentException: Cannot bind argument at index 3 because the index is out of range. The statement has 1 parameters.
at android.database.sqlite.SQLiteProgram.bind(SQLiteProgram.java:212)
at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:166)
at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:200)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1161)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1032)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1200)
The above exception was thrown because I tried to pass selectionArgs which contained more elements than the number of ? placeholders in selection.
These two methods from SQLiteProgram.java are to "blame" for this exception:
public void bindAllArgsAsStrings(String[] bindArgs) {
if (bindArgs != null) {
for (int i = bindArgs.length; i != 0; i--) {
bindString(i, bindArgs[i - 1]);
}
}
}
private void bind(int index, Object value) {
if (index < 1 || index > mNumParameters) {
throw new IllegalArgumentException("Cannot bind argument at index "
+ index + " because the index is out of range. "
+ "The statement has " + mNumParameters + " parameters.");
}
mBindArgs[index - 1] = value;
}
Now, when I found out about this behavior, I think that the code example from Android Developers site is not just inefficient, but is a total crap!
Bottom line: if you pass null as selection, pass null as selectionArgs as well. If selection is not null and contains ? placeholders - make sure that the length of selectionArgs array equals the number of ? placeholders in selection.
Very new to Java: Trying to learn it.
I created an Array and would like to access individual components of the array.
The first issue I am having is how to I print the array as a batch or the whole array as indicated below? For example: on the last value MyValue4 I added a line break so that when the values are printed, the output will look like this: There has to be a better way to do this?
MyValue1
MyValue2
MyValue3
MyValue4
MyValue1
MyValue2
MyValue3
MyValue4
The next thing I need to do is, manipulate or replace a value with something else, example: MyValue with MyValx, when the repeat variable is at a certain number or value.
So when the repeat variable reaches 3 change my value to something else and then change back when it reaches 6.
I am familiar with the Replace method, I am just not sure how to put this all together.
I am having trouble with changing just parts of the array with the while and for loop in the mix.
My Code:
public static String[] MyArray() {
String MyValues[] = { "MyValue1", "MyValue2", "MyValue3", "MyValue4\n" };
return MyValues;
}
public static void main(String[] args) {
int repeat = 0;
while (repeat < 7) {
for (String lines : MyArray()) {
System.out.println(lines);
}
repeat = repeat + 1;
if (repeat == 7) {
break;
}
}
}
Maybe to use for cycle to be shorter:
for (int i = 0; i < 7; i++) {
for (String lines : MyArray()) {
// Changes depended by values.
if (i > 3) {
lines = MyValx;
}
System.out.println(lines); // to have `\n` effect
}
System.out.println();
}
And BTW variables will start in lower case and not end withenter (\n). So use:
String myValues[] = {"MyValue1", "MyValue2", "MyValue3", "MyValue4"};
instead of:
String MyValues[] = { "MyValue1", "MyValue2", "MyValue3", "MyValue4\n" };
and add System.out.println(); after eache inside cycle instead of this:
MyValues[n] = "value";
where n is the position in the array.
You may consider using System.out.println() without any argument for printing an empty line instead of inserting new-line characters in your data.
You already know the for-each loop, but consider a count-controlled loop, such as
for (int i = 0; i < lines.length; i++) {
...
}
There you can use i for accessing your array as well as for deciding for further actions.
Replacing array items based on a number in a string might be a bit trickier. A regular expression will definitely do the job, if you are familiar with that. If not, I can recommend learning this, because it will sure be useful in future situations.
A simpler approach might be using
int a = Integer.parseInt("123"); // returns 123 as integer
but that only works on strings, which contain pure numbers (positive and negative). It won't work with abc123. This will throw an exception.
These are some ideas, you might try out and experiment with. Also use the documentation excessively. ;-)
I need pass a string parameter that contains many params. When receive the parameter, I use String.split() to split it to get all the params.
But one promblem accured. How to design my string decollator so that any ASCII CODE on keyboard can be passed correctly.
Hope for any advice.
Maybe you could have a look at variadic arguments instead of splitting a string. For example:
public void method(String... strings) {
// strings is actually an array
String firstParam = strings[0];
String secondParam = strings[1];
// ...
}
Calling:
method("string1");
method("string1", "string2", "string3");
// as many string args as you want
If I understood correctly - you need to encode set of parameters to one string. You can use some sequence of characters for this purpose, E.g.
final String delimiter = "###"
String value = "param1###param2###param3";
String[] parameters = value.split(delimiter);
Choose a character which is easy to enter and unlikely to appear in the input. Let's assume that character is #.
Normal input would like like Item 1#Item 2#Item 3. Actually, you can .trim() every item and let the user enter Item 1 # Item 2 # Item 3 if s/he prefers.
However, like you describe, say the user would like to enter Item #1, Item #2, etc.. There are a few ways to let him/her do this, but the easier is to let them escape the delimiter. For example, instead of Item #1 # Item #2 # Item #3, which would result in 6 different items being found normally, let the user enter, for example Item ##1 # Item ##2 # Item ##3. Then in your parsing, make sure to handle the case when two or more #'s have been entered in a row. split likely won't be good enough, you'll have to go through the string yourself.
Here's a sketch of a method which would split the input string for you:
private static List<String> parseArguments(String input) {
ArrayList<String> arguments = new ArrayList<String>();
String[] prelArguments = input.split("#");
for (int i = 0; i < prelArguments.length; i++) {
String argument = prelArguments[i];
if (argument.equals("")) {
// We will enter here if there were two or more #'s in a row
StringBuilder combinedArgument = new StringBuilder(arguments.remove(arguments.size() - 1));
int inARow = 0;
while (prelArguments[i+inARow].equals("")) {
inARow++;
combinedArgument.append('#');
}
i += inARow;
combinedArgument.append(prelArguments[i]);
arguments.add(combinedArgument.toString());
} else {
arguments.add(argument);
}
}
return arguments;
}
Error handling, edge-case handling and some performance improvement is missing from the above, but I think the idea comes through.
I would eliminate the problem, which is the misuse of String as an argument container. If you need to pass more parameters, pass more parameters. If this gets out of hand, consider passing a map, or a custom object that can contain all the parameters.