0

I'm given a task to read data from a text file and save it to a Set. Text file represents an imaginary bill containing certain item description and it's price, quantity and total sum. I only need item's name and price. Text file looks like this:

Item_name   Item_price(float value with comma as format symbol)  Quantity(int)  Total(float)
Item_name   Item_price(float value with comma as format symbol)  Quantity(int)  Total(float)

(Text file contains multiple items). Also, items sometimes have numbers in their name, eg. LG 4k TV 1000U).

I tried to solve it like this:

private void readAndSave(Path file) {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(
             new BufferedInputStream(new FileInputStream(file.toString()))))) {


        Set<Item> items = new TreeSet<>();
        String line;
        while ((line = br.readLine()) != null) {


            float price = 0, numb;
            boolean priceFound = false;
            String name = "";
            String[] lineElements;
            lineElements = line.split(" ");

            for(String temp: lineElements) {
                if((numb = getNumberRepresentation(temp)) != -1) {
                    if(!priceFound) {
                        price = numb;
                        priceFound = true;
                    }
                    break;
                }

                name += temp + " ";
            }
            items.add(new Item(name, price));

        }
    } catch (FileNotFoundException fe) {
        System.out.println("File not found!");
    } catch (IOException e) {
        System.out.println("Error while opening/writing files!");
    }

}

Class Item contains two variables(String, float) representing name and price of an item and extends Comparable.

And here is getNumberRepresentation method

private float getNumberRepresentation(String temp) {
    try {

        DecimalFormatSymbols symbols = new DecimalFormatSymbols();
        symbols.setDecimalSeparator(',');
        DecimalFormat format = new DecimalFormat("0.##");
        format.setDecimalFormatSymbols(symbols);
        return format.parse(temp).floatValue();

    } catch(Exception e) {
        return -1;
    }
}

I've tried to use the logic that, if a price is found, then the name must also be already found and all other Strings from the line can be skipped. Problem here is that sometimes I get a number from an item's name as price(1000U, from previous example). Is there a better and more efficient solution to this problem?

Edit: File sample

Escape from Paradise City 70,00 1135 79450,00 Sony ITC60, TV cabel 111,26 111 12349,86

kolsdj
  • 3
  • 3
  • One suggestion to your existing code... dont use 'try, catch' to parse you temp valiable... you should use TryParse() e.g. bool result = Int32.TryParse(value, out number); if (result) { Console.WriteLine("Converted '{0}' to {1}.", value, number); } else { // if (value == null) value = ""; Console.WriteLine("Attempted conversion of '{0}' failed.", value == null ? "" : value); } – Gwasshoppa Dec 21 '16 at 00:52
  • Do you have control over what the text file looks like. i.e. Can you make the file TAB delimited, then you are splitting on a TAB not a " " (space. – Gwasshoppa Dec 21 '16 at 00:57
  • Thanks for the suggestion. Unfortunately i don't have any control over the text file. – kolsdj Dec 21 '16 at 01:07
  • LOL sorry I just realised you are working in Java not c# :) – Gwasshoppa Dec 21 '16 at 01:16
  • Please add to the question a sample of the file lines if possible. – yaitloutou Dec 21 '16 at 14:50
  • Edit completed. – kolsdj Dec 21 '16 at 16:55

1 Answers1

0

You need to be using java.util.regex.Pattern and get everything before the match of a Regex for the cost and the match of the regex for the cost. I assume there won't be anything in the name that looks like ###,## where # are numerals. (Represented by \d in regex).

The tutorial can be found here.

It would look something like this:

Before reading the lines:

Pattern p = Pattern.compile("(.*?) (\\d*,\\d*)");

For each line:

Matcher m = p.matcher(line);
if (m.matches() && m.groupCount() == 2) {
    name = m.group(1);
    price = getNumberRepresentation(m.group(2));
} else {
    // line doesn't match the pattern, handle the exception!
}
Jimi Kimble
  • 424
  • 4
  • 9
  • I've tried to use your approach(assuming that I understood it correctly), but for name it gets everything before the sum and for the price it gets the sum. Here is the code: ` lineElements = line.split(" "); Matcher m = p.matcher(line); if (m.matches() && m.groupCount() == 2) { name = m.group(0); price = getNumberRepresentation(m.group(1)); } else { System.out.println("Line error."); } ` – kolsdj Dec 21 '16 at 11:52
  • I realize now that my explanation is written poorly.. instead of saying before splitting the lines, I should have said before reading and for each line.. I'll fix the answer to reflect this. Also.. make sure your pattern is non-greedy. ".*?" instead of ".*". The first version of this answer was greedy which would give you the behavior you are talking about. – Jimi Kimble Dec 21 '16 at 17:52