0

I have a formatted text file that I need to extract information from and put into corresponding member variables in a class Item (1 line of text = 1 Item). I am using Scanner and delimiter, but it can only recognize the ; separating information and not new lines.

I've tried a few different regex expressions and my latest one is down below where I specify only the delimiter I know is coming up. I've also tried the regex [;\\n] . My only conclusion is that scanner treats new line characters different than other (which kind of makes sense, I know it has functions based on new lines).

Here is the text file format

1000;Knock Bits;88;12.67;8015
1001;Widgets;10;35.50;8004
1002;Grommets;20;23.45;8001

and here is what my code looks like

while (scan.hasNext())
{           
Item item = new Item();
scan.useDelimiter("[;]");

item.setID(scan.nextInt());
item.setName(scan.next());
item.setQuantity(scan.nextInt());
item.setPriceInCents((int) scan.nextFloat()*100);

scan.useDelimiter("\\n");
item.setSupplierID(scan.nextInt()); 
}

All the above code works except the last line getting supplierID with nextInt(). I know I could just replace that line with

item.setSupplierID(Integer.parseInt(scan.nextLine()));

But that's kind of ugly and there should be a way to do it using regex without having to customize a line specifically for the last word. Preferably using only one delimiter for the whole loop.

Jedediah
  • 133
  • 1
  • 11

2 Answers2

2

Use scanner.useDelimiter("[;\n]"); or scanner.useDelimiter("[;\r\n]"); to work in both Windows and Linux systems.

Call it outside the while loop:

    scanner.useDelimiter("[;\r\n]");

    while (scanner.hasNext()) {
        Item item = new Item();
        item.setID(scanner.nextInt());
        item.setName(scanner.next());
        item.setQuantity(scanner.nextInt());
        item.setPriceInCents((int) scanner.nextFloat()*100);
        item.setSupplierID(scanner.nextInt());
    }

If using \R as suggested by mypetlion: scanner.useDelimiter(";|\\R");

  • 1
    To be fully agnostic, you can replace the `\r\n` with `\R`. Introduced to Java's pattern syntax in Java 8. – mypetlion Feb 06 '19 at 22:48
  • Using delimiter `[;\r\n]` for data like `1;2\r\n3;4` would fail since character class `[...]` describes potential set for *single* character it can match. In other words *each* `\r` and `\n` is treated as **separate** delimiter, meaning that scanner will think that there is one element (empty string) at `\r\n` (between `\r` and `\n`). Using `\R` instead solves this problem (but it must be used outside of character class since it doesn't represent single character but also `\r\n` *sequence*). – Pshemo Feb 06 '19 at 23:21
  • This solved the problem. I suppose the new line character was \r. To be fully agnostic without too much trouble, I suppose you could come up with a regex to include all numbers, spaces, tabs, and leave any other characters (punctuation, \n, \r etc) to be delimiters. This would allow for commas and other seperators to work. – Jedediah Feb 07 '19 at 01:14
  • Slightly unrelated question, \n\r and \\n\\r both work and do the same thing. How is that possible? Unless they coincidentally do the same thing in this scenario? – Jedediah Feb 07 '19 at 01:16
  • @Jedediah related [Understanding regex in Java: split(“\t”) vs split(“\\t”) - when do they both work, and when should they be used](https://stackoverflow.com/q/3762347) – Pshemo Feb 07 '19 at 08:19
0

read the whole line then use string.split(";") to get the elements

List<Map<String,Object>> items = new ArrayList<>();
    try {
        Scanner scanner = new Scanner(new File(ClassLoader.getSystemResource("stats.txt").getFile()));
        while (scanner.hasNext()){
            String[] itemString = scanner.nextLine().split(";");
            Map<String,Object> item = new HashMap<>();
            item.put("id",Integer.parseInt(itemString[0]));
            item.put("name",itemString[1]);
            item.put("quant",Integer.parseInt(itemString[2]));
            item.put("price",Float.parseFloat(itemString[3]));
            item.put("suplierId",Integer.parseInt(itemString[4]));
            items.add(item);

        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    items.forEach(i->{
        i.forEach((key, value) -> System.out.println(key + " : " + value));
        System.out.println();
    });

Instead of Map you can just populate the object parsed values

mavriksc
  • 1,130
  • 1
  • 7
  • 10