Buffered Reader: Reset won't reset - java

I'm currently learing about the mark() and reset() methods of the BufferedReader and want to do the following:
I parse a CSV, set up like this (spaces as delimiter):
555 value1
555 value2
600 foobar
700 whatever
Each line, one object (adress) is created with the first number as its ID. When the ID is used multiple times, I want to compare the values in the second column and proceed afterwards.
With the data above, my code does compare the two values with ID 555, but fails to create an object with the third line (ID 600).
Mistake found: splitted the first line after parsing the new one. Simple mix up of variables.
My setup is similar to this:
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
br.mark(1000); //save current line
List<String> list = new ArrayList<String>(Arrays.asList(line.split(delimiter)));
Adress a = new Adress(Long.parseLong(list.get(0)); //create object
while (((checkLine = br.readLine()) != null) && exit == false){
List<String> nextLine = new ArrayList<String>(Arrays.asList(line.split(delimiter)));
long nextId = Long.parseLong(nextLine.get(0));
if( nextId == a.getId() ){
System.out.println(nextId + " vs. " + a.getId());
br.mark(1000); //mark the next line if it has the same ID
//[...] do more stuff
} else{
exit = true;
}
}
br.reset(); //reset to the last line with the ID
}
Sysout:
555 vs. 555
555 vs. 555
555 vs. 555

I see a couple of issues in the code:
Inside the second while() loop you are still splitting the string "line", but the while loop assigns the input to "checkLine".
You don't reset "exit" to false - this should probably happen after the br.reset().

if your addresses are separated by spaces , and the different elements of your address are also separated by spaces , then this line does not give you addresses , it gives you elements .
List < String > list = new ArrayList < String > ( Arrays . asList ( line . split ( delimiter ) ) ) ;

The mistake was the following variable-mixup (solely my stupidity was the mistake!):
while (((checkLine = br.readLine()) != null) && exit == false){
List<String> nextLine = new ArrayList<String>(Arrays.asList(line.split(delimiter)));
[...]
The List nextLine has to be changed from line.split to checkline.split:
List<String> nextLine = new ArrayList<String>(Arrays.asList(checkLine.split(delimiter)));
Thanks to everybody helping!

Related

Data evaluation from text file

I need some help. I dont know how to solve my problem.
I have text file in this format:
personx 25
personz 2
persony 5
persony 7
personi 55
personx 25
I need to count the numbers for every person. The output should be "personx = 50" etc.
I can not use my old system where I knew there is 10 people. So I had 10 variables and I just went through the file with scanner and checked if line starts with "personx" then count the number to variable personx etc. I dont want to use these variables now. I dont want to change code after every new person.
How to solve this? I want to have this output sorted from highest to lowest:
personi = 55
personx = 50
persony = 12
personz = 2
Is that possible without using variables personi, personx, persony, personz ? My idea was to go through the file and scan the names. Save the name into an array and add another name into an array if that name is not in the array yet. So I will have the names.
Next I will scan the file again and check for the name and number. Check name + number and then save the number into another array on the same possition as the name in the first array. So I will have
Names[0] = "personi";
Count[0] = 55;
Names[1] = "personx";
Count[1] = 50;
And then I will just print these two arrays with for cycle.
I dont think that it is the best solution. How would you do it? Is there something better/faster/easier ? And how to solve that Sorting?
Thank you for your time.
You can us Map<String,Integer>
In this case i used TreeMap which will sort everything for you. If you dont need sorting then just use HashMap instead of TreeMap.
Map<String, Integer> map = new TreeMap();
try {
BufferedReader reader = new BufferedReader(new FileReader(new File("C:/iPhone/persons.txt")));
String line = "";
String [] person = new String[2];
while ((line = reader.readLine()) != null) {
person = line.split(" ");
String name = person[0];
int number = Integer.parseInt(person[1]);
map.put(name,map.getOrDefault(name,0)+number);
}
reader.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
map.forEach((k,v)->System.out.println(k + " = " + v));
}
persons.txt:
personx 25
personz 2
persony 5
persony 7
personi 55
personx 25
Output:
personi = 55
personx = 50
persony = 12
personz = 2
1) Can I use this on file where line is not in my format but it has for example.. this format ? "personx bla bla 25" ? Is it possible to convert it too? how?
Yes you can create method which will do it for you. You can use either string splits or some regex.
2) Why is there String [] person = new String[2]; ?
Mistake, it should be String[1]. Corrected now
3) what is String line = ""; ?
It is just new String where i'm storing every line that i read from file. As you can see, im assigning reder.readLine() in while loop. After that im just splitting it.
EDIT:
Changed code so person can have multiple params but will take only first as name and last as number.
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap();
try {
BufferedReader reader = new BufferedReader(new FileReader(new File("C:/iPhone/persons.txt")));
String line = "";
String [] person;
while ((line = reader.readLine()) != null) {
person = line.split(" ");
String name = person[0];
int number = Integer.parseInt(person[person.length-1]);
map.put(name,map.getOrDefault(name,0)+number);
}
reader.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
map.forEach((k,v)->System.out.println(k + " = " + v));
}
persons.txt:
personx asdasdas dasd asd a 25
personz 2
persony asd asd asd a 5
persony 7
personi 55
personx 25
output:
personi = 55
personx = 50
persony = 12
personz = 2

line.startsWith does not interprete the string

I am trying to not print lines start with string like 2 2 but with the current state just line starts with notice are being delteted. I debugged it and wrote the Output in the code lines. How can I fix it?
I appreciate any help.
Code:
int number = Character.getNumericValue(newName.charAt(2));
//here start_zero is `2 2`
String start_zero = new StringBuilder().append(number)
.append(" ").append(number).toString();
try (PrintWriter writer = new PrintWriter(path + File.separator
+ newName);
Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
//here is the first line `2 2`
String line = scanner.nextLine();
//here is start_zero `2 2` too.
if (!line.startsWith("notice") || !line.startsWith(start_zero) ) {
writer.println(line);
writer.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (!line.startsWith("notice") || !line.startsWith(start_zero) ) {
writer.println(line);
writer.flush();
}
your problem is in your if statement. You used OR, but you should have used AND
if (!line.startsWith("notice") && !line.startsWith(start_zero) ) {
writer.println(line);
writer.flush();
}
if the first returns true ... which is your case, the second doesn't matter anymore in your code.
Just change your if statement operator from OR to AND like this
if (!line.startsWith("notice") && !line.startsWith(start_zero) )
{rest of code here}
This condition:
if (!line.startsWith("notice") || !line.startsWith(start_zero) )
Means: "Do the following if the line doesn't start with "notice" or if the line doesn't start with "2 2".
It means that if the line doesn't start with "notice", the whole condition becomes true. Because it's correct to say that the first or the second conditions were met when just one of them is met.
If you want to print the line only if it neither starts with "notice" nor with "2 2", you have to use one of these conditions:
! ( line.startsWith("notice") || line.startsWith(start_zero) )
(Note: the parentheses are important.) Or the equivalent (by DeMorgan's law):
! line.startsWith("notice") && ! line.startsWith(start_zero)
The first can be interpreted as 'Do the following if it's not true that the line starts with either "notice" or "2 2"', and the second as 'Do the following if the line both doesn't start with "notice" and doesn't start with "2 2"'.

How to make a local variable accessible outside the loop in java

I have a txt file in while one line is like this :
"Execution Status: Pass"
I want to take the value out : pass from here.
I am using below code :
String patternString1 = "(Execution) (Status:) (.*)";
Pattern patt1 = Pattern.compile( patternString1 );
BufferedReader r = new BufferedReader(new FileReader( "c:\\abc.txt" ));
String line;
while ( (line = r.readLine()) != null ) {
String g11 = null;
Matcher m1 = patt1.matcher( line );
while ( m1.find() ) {
g11=m1.group(3);
System.out.println(g11+"HI1"); //Line1
}
System.out.println(g11+"HI1"); //Line2
}
While Line 1 is giving the desired output as "pass" I am not getting this expected output from Line 2.
Could any one of you please help me in accessing the local variable out of the loop?
Declare String g11 as a local variable at the start of your method
String g11=""; -- declare g11 as a local variable
String patternString1 = "(Execution) (Status:) (.*)";
Pattern patt1 = Pattern.compile(patternString1);
Add the rest of your code here.........
Could you try changing following line:
while (m1.find())
to
if(m1.find())
It should give the result you want
How about the easy way:
String result = line.replaceAll(".*: ", "");
This line says "replace everything up to and including colon space with nothing" (ie delete it).
If there is only one instance of this match in single line then use if instead of while (m1.find()) loop or break the loop once match is found.
Sample code:
while ( (line = r.readLine()) != null ) {
String g11 = null;
Matcher m1 = patt1.matcher( line );
if( m1.find() ) {
g11=m1.group(3);
}
if(g11 != null){
System.out.println(g11+"HI1"); //Line2
}
}

How do sort my pattern match results as complete match, half a match and so on [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Regular expression not matching subwords in phrase
My program displays the matching results, but I want to sort the results as complete match (100%), half a match and so on.
My text file contains the following line:
Red car
Red
Car
So If I search for: “red car”. I get the following results
Red car
Red
Car
So what I want to do is to sort the found results as follows:
"red car" 100% match
"red" 40% match
"car" 40% match
Any help is appreciated.
Any help is appreciated. My code is as follows:
public static void main(String[] args) {
// TODO code application logic here
String strLine;
try{
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream("C:\\textfile.txt"");
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
Scanner input = new Scanner (System.in);
System.out.print("Enter Your Search: "); // String key="red or yellow";
String key = input.nextLine();
while ((strLine = br.readLine()) != null) {
Pattern p = Pattern.compile(key); // regex pattern to search for
Matcher m = p.matcher(strLine); // src of text to search
boolean b = false;
while(b = m.find()) {
System.out.println( " " + m.group()); // returns index and match
// Print the content on the console
}
}
//Close the input stream
in.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
Assuming you are searching for "Red" or "Yellow", and or is the only logical operator you need (no 'and' or 'xor') and you don't want to use any wildcards or regular-expressions in what you search for, then I would simply loop through, trying to match each String in turn against the line. In pseudo-code, something like:
foreach (thisLine: allLinesInTheFile) {
numOfCharsMatching = 0
foreach (thisString: allSearchStrings) {
if (thisLine.contains(thisString) {
numOfCharsMatching = numOfCharsMatching + thisString.length
}
}
score = ( numOfCharsMatching / thisLine.length ) * 100
}
If you don't want spaces to count in your score, then you'd need to remove them from the thisString.length (and not allow them in your search terms)
One other problem is the numOfCharsMatching will be incorrect if matches can overlap (i.e. if searching for 'row' or 'brown' in 'brown row' it will say that there are 11 characters matching, longer than the length of the string. You could use a BitSet to track which characters have been involved in a match, something like:
foreach (thisLine: allLinesInTheFile) {
whichCharsMatch = new BitSet()
foreach (thisString: allSearchStrings) {
if (thisLine.contains(thisString) {
whichCharsMatch.set(startPositionOfMatch, endPositionOfMatch, true)
}
}
score = ( numOfCharsMatching / thisLine.length ) * 100
}
Have a look at the BitSet javadoc, particularly the set and cardinality methods

using tokenizer to read a line

public void GrabData() throws IOException
{
try {
BufferedReader br = new BufferedReader(new FileReader("data/500.txt"));
String line = "";
int lineCounter = 0;
int TokenCounter = 1;
arrayList = new ArrayList < String > ();
while ((line = br.readLine()) != null) {
//lineCounter++;
StringTokenizer tk = new StringTokenizer(line, ",");
System.out.println(line);
while (tk.hasMoreTokens()) {
arrayList.add(tk.nextToken());
System.out.println("check");
TokenCounter++;
if (TokenCounter > 12) {
er = new DataRecord(arrayList);
DR.add(er);
arrayList.clear();
System.out.println("check2");
TokenCounter = 1;
}
}
}
} catch (FileNotFoundException ex) {
Logger.getLogger(Driver.class.getName()).log(Level.SEVERE, null, ex);
}
}
Hello , I am using a tokenizer to read the contents of a line and store it into an araylist. Here the GrabData class does that job.
The only problem is that the company name ( which is the third column in every line ) is in quotes and has a comma in it. I have included one line for your example. The tokenizer depends on the comma to separate the line into different tokens. But the company name throws it off i guess. If it weren't for the comma in the company column , everything goes as normal.
Example:-
Essie,Vaill,"Litronic , Industries",14225 Hancock Dr,Anchorage,Anchorage,AK,99515,907-345-0962,907-345-1215,essie#vaill.com,http://www.essievaill.com
Any ideas?
First of all StringTokenizer is considered to be legacy code. From Java doc:
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.
Using the split() method you get an array of strings. While iterating through the array you can check if the current string starts with a quote and if that's the case check if the next one ends with a quote. If you meet these 2 conditions then you know you didn't split where you wanted and you can merge these 2 together, process it like you want and continue iterating through the array normally after that. In that pass you will probably do i+=2 instead of your regular i++ and it should go unnoticed.
You can accomplish this using Regular Expressions. The following code:
String s = "asd,asdasd,asd\"asdasdasd,asdasdasd\", asdasd, asd";
System.out.println(s);
s = s.replaceAll("(?<=\")([^\"]+?),([^\"]+?)(?=\")", "$1 $2");
s = s.replaceAll("\"", "");
System.out.println(s);
yields
asd,asdasd,asd, "asdasdasd,asdasdasd", asdasd, asd
asd,asdasd,asd, asdasdasd asdasdasd, asdasd, asd
which, from my understanding, is the preprocessing you require for your tokenizer-code to work. Hope this helps.
While StringTokenizer might not natively handle this for you, a couple lines of code will do it... probably not the most efficient, but should get the idea across...
while(tk.hasMoreTokens()) {
String token = tk.nextToken();
/* If the item is encapsulated in quotes, loop through all tokens to
* find closing quote
*/
if( token.startsWIth("\"") ){
while( tk.hasMoreTokens() && ! tk.endsWith("\"") ) {
// append our token with the next one. Don't forget to retain commas!
token += "," + tk.nextToken();
}
if( !token.endsWith("\"") ) {
// open quote found but no close quote. Error out.
throw new BadFormatException("Incomplete string:" + token);
}
// remove leading and trailing quotes
token = token.subString(1, token.length()-1);
}
}
As you can see, in the class description, the use of StringTokenizer is discouraged by Oracle.
Instead of using tokenizer I would use the String split() method
which you can use a regular expression as argument and significantly reduce your code.
String str = "Essie,Vaill,\"Litronic , Industries\",14225 Hancock Dr,Anchorage,Anchorage,AK,99515,907-345-0962,907-345-1215,essie#vaill.com,http://www.essievaill.com";
String[] strs = str.split("(?<! ),(?! )");
List<String> list = new ArrayList<String>(strs.length);
for(int i = 0; i < strs.length; i++) list.add(strs[i]);
Just pay attention to your regex, using this one you're assuming that the comma will be always between spaces.

Categories