just a beginner in java doing a simple reading file processing some data and writing to a file, however whenever I print to a file I get this inconsistent spacing such as shown below. Especially the zeros are throwing me off. Right now I am padding the strings with empty spaces but I am sure there are better suggestions out there to have consistent spacing between strings in a file. Thanks for the help. I have attached a picture of the inconsistent printing, especially the zeros.
In Apache Commons StringUtils library there are convenient methods to set the proper pad - e.g. rightPad seems to be useful in your case - you could make something like
String row = StringUtils.rightPad(firstValue, lengthOfTheLongestValueInColumn1 + definedColumnMargin) + StringUtils.rightPad(secondValue, lengthOfTheLongestValueInColumn2 + definedColumnMargin) // + ... etc
If these lengthOfTheLongestValueInColumn variables would be calculated dynamically then it would work perfectly but you could also just hardcode some reasonable value (if you know that no value will be longer than, let say, 20 it could have value of 20)
I think best option will be to use String format
return String.format("%1$" + length + "s", inputString)
where length is max size of your digit
you can read more here
Related
A simple line of code:
String thing = "Something";
thing += " something else" + " and more.";
IntelliJ IDEA offers to change this line into 4 other ways to accomplish the same result:
String.format()
StringBuilder.append()
java.text.MessageFormat.format()
Replace += with =
Why? What is so wrong with +=? Can anyone explain this please? Thanks.
In general case, the result is not the same. + operator allocates intermediate string, which requires additional memory.
String thing = "Something";
thing += " something else" + " and more."; // two allocations: to compute string inside expression ```" something else" + " and more."```` and to execute ```+=```
By using StringBuilder you don't allocate intermediate result, e.g. less memory is needed.
In your case with short lines and without loops no actual performance boost is expected. However with loops you receive O(N^2) complexity. Please check this answer with explained example.
I am assuming you are referring to this:
This is not actually a fix "problem" with your code, as indicated by the pencil icon. Fixes to problems with your code are identified with a lightbulb, such as not using the value of thing:
The pencil just means "here's a shortcut to change your code, so you don't have to change it manually". Changing a a += b to a = a + b usually isn't that much work, but other things, like changing a for-each loop to a regular for loop, is.
This could be useful if you suddenly remembered that you need the index of the array for something.
I have the following problem: I have a String that I read from a MySQL Database (with the JDBC driver) and have to compare it with another String that I receive over TCP with a BufferedReader. When I use String.equals, false is returned even if the Strings are exactly equal, I even printed both Strings to the console to make sure there aren't any typos or null objects. String.compareTo returns a negative number around -100.
I am really confused here and have no concrete idea how to fix that. Maybe it's related to the database's encoding (UTF-8)?
As requested, here is my code snippet:
public TeleportSign getTeleportSign(String target) {
// I used a HashMap, but I switched to an ArrayList in order to be able
// to compare the Strings directly.
//return signs.get(target);
for(TeleportSign s : signsList) {
// I am printing the Strings here. I even put stars to the left
// and the right of the String to make sure there are no
// spaces or new lines. s.getTarget() returns the String from the DB,
// target is the String sent over TCP.
System.out.println("*" + s.getTarget() + "* " +
String.valueOf(s.getTarget().compareTo(target))
+ " *" + target + "*");
if(s.getTarget().compareTo(target) == 0)
return s;
}
return null;
}
And the console output is:
*TDM1* -84 *TDM1*
Thanks in advance!
Captain
So I rebooted the entire system and retried. Everything works now as expected. I can't explain this to myself because I restarted the JVM multiple times and nothing happened, and a system reboot shouldn't affect a Java program like this.
I am sorry for everyone's time I wasted, but I really appreciate your quick help anyways.
EDIT: I use the trim method from String now. This method cuts off any leading null characters to prevent issues like this one. I hope this will be helpful for someone who has the same problem!
Okay so i am working on a game based on a Trading card game in java. I Scraped all of the game peices' "information" into a csv file where each row is a game peice and each column is a type of attribute for that peice. I have spent hours upon hours writing code with Buffered reader and etc. trying to extract the information from my csv file into a 2d Array but to no avail. My csv file is linked Here: http://dl.dropbox.com/u/3625527/MonstersFinal.csv I have one year of computer science under my belt but I still cannot figure out how to do this.
So my main question is how do i place this into a 2D array that way i can keep the rows and columns?
Well, as mentioned before, some of your strings contain commas, so initially you're starting from a bad place, but I do have a solution and it's this:
--------- If possible, rescrape the site, but perform a simple encoding operation when you do. You'll want to do something like what you'll notice tends to be done in autogenerated XML files which contain HTML; reserve a 'control character' (a printable character works best, here, for reasons of debugging and... well... sanity) that, once encoded, is never meant to be read directly as an instance of itself. Ampersand is what I like to use because it's uncommon enough but still printable, but really what character you want to use is up to you. What I would do is write the program so that, at every instance of ",", that comma would be replaced by "&c" before being written to the CSV, and at every instance of an actual ampersand on the site, that "&" would be replaced by "&a". That way, you would never have the issue of accidentally separating a single value into two in the CSV, and you could simply decode each value after you've separated them by the method I'm about to outline in...
-------- Assuming you know how many columns will be in each row, you can use the StringTokenizer class (look it up- it's awesome and built into Java. A good place to look for information is, as always, the Java Tutorials) to automatically give you the values you need in the form of an array.
It works by your passing in a string and a delimiter (in this case, the delimiter would be ','), and it spitting out all the substrings which were separated by those commas. If you know how many pieces there are in total from the get-go, you can instantiate a 2D array at the beginning and just plug in each row the StringTokenizer gives them to you. If you don't, it's still okay, because you can use an ArrayList. An ArrayList is nice because it's a higher-level abstraction of an array that automatically asks for more memory such that you can continue adding to it and know that retrieval time will always be constant. However, if you plan on dynamically adding pieces, and doing that more often than retrieving them, you might want to use a LinkedList instead, because it has a linear retrieval time, but a much better relation than an ArrayList for add-remove time. Or, if you're awesome, you could use a SkipList instead. I don't know if they're implemented by default in Java, but they're awesome. Fair warning, though; the cost of speed on retrieval, removal, and placement comes with increased overhead in terms of memory. Skip lists maintain a lot of pointers.
If you know there should be the same number of values in each row, and you want them to be positionally organized, but for whatever reason your scraper doesn't handle the lack of a value for a row, and just doesn't put that value, you've some bad news... it would be easier to rewrite the part of the scraper code that deals with the lack of values than it would be to write a method that interprets varying length arrays and instantiates a Piece object for each array. My suggestion for this would again be to use the control character and fill empty columns with &n (for 'null') to be interpreted later, but then specifics are of course what will individuate your code and coding style so it's not for me to say.
edit: I think the main thing you should focus on is learning the different standard library datatypes available in Java, and maybe learn to implement some of them yourself for practice. I remember implementing a binary search tree- not an AVL tree, but alright. It's fun enough, good coding practice, and, more importantly, necessary if you want to be able to do things quickly and efficiently. I don't know exactly how Java implements arrays, because the definition is "a contiguous section of memory", yet you can allocate memory for them in Java at runtime using variables... but regardless of the specific Java implementation, arrays often aren't the best solution. Also, knowing regular expressions makes everything much easier. For practice, I'd recommend working them into your Java programs, or, if you don't want to have to compile and jar things every time, your bash scripts (if your using *nix) and/or batch scripts (if you're using Windows).
I think the way you've scraped the data makes this problem more difficult than it needs to be. Your scrape seems inconsistent and difficult to work with given that most values are surrounded by quotes inconsistently, some data already has commas in it, and not each card is on its own line.
Try re-scraping the data in a much more consistent format, such as:
R1C1|R1C2|R1C3|R1C4|R1C5|R1C6|R1C7|R1C8
R2C1|R2C2|R2C3|R2C4|R2C5|R2C6|R2C7|R3C8
R3C1|R3C2|R3C3|R3C4|R3C5|R3C6|R3C7|R3C8
R4C1|R4C2|R4C3|R4C4|R4C5|R4C6|R4C7|R4C8
A/D Changer|DREV-EN005|Effect Monster|Light|Warrior|100|100|You can remove from play this card in your Graveyard to select 1 monster on the field. Change its battle position.
Where each line is definitely its own card (As opposed to the example CSV you posted with new lines in odd places) and the delimiter is never used in a data field as something other than a delimiter.
Once you've gotten the input into a consistently readable state, it becomes very simple to parse through it:
BufferedReader br = new BufferedReader(new FileReader(new File("MonstersFinal.csv")));
String line = "";
ArrayList<String[]> cardList = new ArrayList<String[]>(); // Use an arraylist because we might not know how many cards we need to parse.
while((line = br.readLine()) != null) { // Read a single line from the file until there are no more lines to read
StringTokenizer st = new StringTokenizer(line, "|"); // "|" is the delimiter of our input file.
String[] card = new String[8]; // Each card has 8 fields, so we need room for the 8 tokens.
for(int i = 0; i < 8; i++) { // For each token in the line that we've read:
String value = st.nextToken(); // Read the token
card[i] = value; // Place the token into the ith "column"
}
cardList.add(card); // Add the card's info to the list of cards.
}
for(int i = 0; i < cardList.size(); i++) {
for(int x = 0; x < cardList.get(i).length; x++) {
System.out.printf("card[%d][%d]: ", i, x);
System.out.println(cardList.get(i)[x]);
}
}
Which would produce the following output for my given example input:
card[0][0]: R1C1
card[0][1]: R1C2
card[0][2]: R1C3
card[0][3]: R1C4
card[0][4]: R1C5
card[0][5]: R1C6
card[0][6]: R1C7
card[0][7]: R1C8
card[1][0]: R2C1
card[1][1]: R2C2
card[1][2]: R2C3
card[1][3]: R2C4
card[1][4]: R2C5
card[1][5]: R2C6
card[1][6]: R2C7
card[1][7]: R3C8
card[2][0]: R3C1
card[2][1]: R3C2
card[2][2]: R3C3
card[2][3]: R3C4
card[2][4]: R3C5
card[2][5]: R3C6
card[2][6]: R3C7
card[2][7]: R4C8
card[3][0]: R4C1
card[3][1]: R4C2
card[3][2]: R4C3
card[3][3]: R4C4
card[3][4]: R4C5
card[3][5]: R4C6
card[3][6]: R4C7
card[3][7]: R4C8
card[4][0]: A/D Changer
card[4][1]: DREV-EN005
card[4][2]: Effect Monster
card[4][3]: Light
card[4][4]: Warrior
card[4][5]: 100
card[4][6]: 100
card[4][7]: You can remove from play this card in your Graveyard to select 1 monster on the field. Change its battle position.
I hope re-scraping the information is an option here and I hope I haven't misunderstood anything; Good luck!
On a final note, don't forget to take advantage of OOP once you've gotten things worked out. a Card class could make working with the data even simpler.
I'm working on a similar problem for use in machine learning, so let me share what I've been able to do on the topic.
1) If you know before you start parsing the row - whether it's hard-coded into your program or whether you've got some header in your file that gives you this information (highly recommended) - how many attributes per row there will be, you can reasonably split it by comma, for example the first attribute will be RowString.substring(0, RowString.indexOf(',')), the second attribute will be the substring from the first comma to the next comma (writing a function to find the nth instance of a comma, or simply chopping off bits of the string as you go through it, should be fairly trivial), and the last attribute will be RowString.substring(RowString.lastIndexOf(','), RowString.length()). The String class's methods are your friends here.
2) If you are having trouble distinguishing between commas which are meant to separate values, and commas which are part of a string-formatted attribute, then (if the file is small enough to reformat by hand) do what Java does - represent characters with special meaning that are inside of strings with '\,' rather than just ','. That way you can search for the index of ',' and not '\,' so that you will have some way of distinguishing your characters.
3) As an alternative to 2), CSVs (in my opinion) aren't great for strings, which often include commas. There is no real common format to CSVs, so why not make them colon-separated-values, or dash-separated-values, or even triple-ampersand-separated-values? The point of separating values with commas is to make it easy to tell them apart, and if commas don't do the job there's no reason to keep them. Again, this applies only if your file is small enough to edit by hand.
4) Looking at your file for more than just the format, it becomes apparent that you can't do it by hand. Additionally, it would appear that some strings are surrounded by triple double quotes ("""string""") and some are surrounded by single double quotes ("string"). If I had to guess, I would say that anything included in a quotes is a single attribute - there are, for example, no pairs of quotes that start in one attribute and end in another. So I would say that you could:
Make a class with a method to break a string into each comma-separated fields.
Write that method such that it ignores commas preceded by an odd number of double quotes (this way, if the quote-pair hasn't been closed, it knows that it's inside a string and that the comma is not a value separator). This strategy, however, fails if the creator of your file did something like enclose some strings in double double quotes (""string""), so you may need a more comprehensive approach.
For various reasons I am trying to set a string to 2000 spaces. Currently I am using:
String s = String.format("%1$-2000s"," ");
This is great for Java 5, however, some of the developers in our department are using 1.4 and this does not work.
I was wondering, are any other ways of achieving the same result? I know I can do things like a for loop adding a space at a time, but I am looking for something simple like the format option.
For those that may be interested in why I need this, it is because we have an XML type on a dataobject that on insert into the DB is null. It then gets updated with the XML string, usually around 2000 characters in size. In Oracle pre-reserving this space can prevent row migration, therefore, increasing performance.
Thanks!
char[] spacesArray = new char[2000];
Arrays.fill(spacesArray, ' ');
String spaces = new String(spacesArray);
the simplest answer: (scroll to see all the codes)
String s = " "; // 2000 spaces
You can use lpad(' ',2000,' ') in the insert statement directly to tell Oracle to create the value you want.
In fact, you can set the field in question to have this as the default, which could prevent you from needing to change it in multiple places (if your code is explicitly sending null as the value for the field, that will override the default).
A StringBuffer and then add a space 2000 times in a loop, and toString() afterwards. I don't think there are any "simpler" ways to do it which doesn't end up doing this anyway under the covers.
If you do this a lot, it would make a good library function.
A random function I found in my personal library:
public static String whiteSpace2(int l) {
if (l==0) return "";
String half=whiteSpace2(l/2);
if ((l&1)!=0) {
return half+" "+half;
} else {
return half+half;
}
}
Not claiming it is the fastest possible way to generate whitespace, but it works :-)
StringUtils.repeat(" ", 2000) (from commons-lang)
However, I'm not sure whether such micro-optimizations should be made with the cost of code that would require a 5 line comment to explain why is this needed. If you do it - be sure to add an extensive comment, otherwise imagine the reaction of those reading your code.
If nothing else works:
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 2000; ++i)
sb.append(" ");
String str = new String(sb);
See this other question.
Can I multiply strings in Java to repeat sequences?
Both Apache Commons StringUtils and Google Guava libraries have commands to multiply (repeat) strings.
Sorry if my question sounds dumb. But some time small things create big problem for you and take your whole time to solve it. But thanks to stackoverflow where i can get GURU advices. :)
So here is my problem. i search for a word in a string and put 0 where that word occur.
For example : search word is DOG and i have string "never ever let dog bite you" so the string
would be 000100 . Now when I try to convert this string into INT it produce result 100 :( which is bad. I also can not use int array i can only use string as i am concatinating it, also using somewhere else too in program.
Now i am sure you are wondering why i want to convert it into INT. So here my answer. I am using 3 words from each string to make this kind of binary string. So lets say i used three search queries like ( dog, dog, ever ) so all three strings would be
000100
000100
010000
Then I want to SUM them it should produce result like this "010200" while it produce result "10200" which is wrong. :(
Thanks in advance
Of course the int representation won't retain leading zeros. But you can easily convert back to a String after summing and pad the zeros on the left yourself - just store the maximum length of any string (assuming they can have different lengths). Or if you wanted to get even fancier you could use NumberFormat, but you might find this to be overkill for your needs.
Also, be careful - you will get some unexpected results with this code if any word appears in 10 or more strings.
Looks like you might want to investigate java.util.BitSet.
You could prefix your value with a '1', that would preserve your leading 0's. You can then take that prefix into account you do your sum in the end.
That all is assuming you work through your 10 overflow issue that was mentioned in another comment.
Could you store it as a character array instead? Your using an int, which is fine, but your really not wanting an int - you want each position in the int to represent words in a string, and you turn them on or off (1 or 0). Seems like storing them in a character array would make more sense.