{"id":"reading-files-keyboard","slug":"reading-until-end","title":"Reading until the input ends","text":"This module is about reading data from files. A program reads a file one line at a time, much as it reads what a user types, so it starts at the keyboard.\n\nModule 19 read input in a `while (true)` loop that stops at a signal, such as an empty line: read a line, `break` if it's the signal, and only then use it. This step adds two more ways to know when to stop.\n\n### Until the input ends\n\nA Scanner's `hasNextLine()` tells whether there's another line to read. It's `true` while there is one, and `false` once the input has ended, so a loop can read every line without waiting for a signal:\n\n```java\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int count = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            count++;\n            System.out.println(count + \": \" + line);\n        }\n        System.out.println(\"Lines: \" + count);\n    }\n}\n```\n\n```input\nred\ngreen\nblue\n```\n\n```output\n1: red\n2: green\n3: blue\nLines: 3\n```\n\n- `hasNextLine()` only looks. `nextLine()` then reads the line, so the next round sees the line after it.\n- An empty line is a line too: `hasNextLine()` is `true` for it, and `nextLine()` gives `\"\"`.\n- In the checks on this site, the input ends after its last line. A person at a keyboard has no natural end, which is why keyboard programs usually wait for a stop signal instead. (In a terminal, Ctrl+D ends the input, or Ctrl+Z and then Enter on Windows.)\n\nA file does have an end, and this loop is exactly how the next steps read one.\n\n### A stop word in any capitals\n\nA stop word typed by a person may come as `end`, `End` or `END`. `equalsIgnoreCase` from module 16 accepts all of them:\n\n```java\nString line = scanner.nextLine();\nif (line.equalsIgnoreCase(\"end\")) {\n    break;\n}\n```\n","task":"The program reads a letter until its input ends, and prints how many lines it has and how many of them are empty (the gaps between paragraphs). Fill in the blanks. For the input shown below, it prints:\n\n```\nLines: 5\nEmpty lines: 2\n```\n","kind":"fill","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int lines = 0;\n        int empty = 0;\n        while (scanner.[[hasNextLine]]()) {\n            String line = scanner.nextLine();\n            lines++;\n            if ([[line.isEmpty()‖line.equals(\"\")]]) {\n                empty++;\n            }\n        }\n        System.out.println(\"Lines: \" + lines);\n        System.out.println(\"Empty lines: \" + empty);\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int lines = 0;\n        int empty = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            lines++;\n            if (line.isEmpty()) {\n                empty++;\n            }\n        }\n        System.out.println(\"Lines: \" + lines);\n        System.out.println(\"Empty lines: \" + empty);\n    }\n}\n","hints":["The loop runs while there's another line to read: `hasNextLine`.","The second blank checks whether the line is empty: `line.isEmpty()`."],"tests":[{"name":"Test 1","stdin":"Dear Mia,\n\nthe garden is in bloom.\n\nLeo\n","expect":"Lines: 5\nEmpty lines: 2","hidden":false},{"name":"Test 2","stdin":"Hello\n","expect":"Lines: 1\nEmpty lines: 0","hidden":true},{"name":"Test 3","stdin":"One\n\n\nTwo\nThree\n\n","expect":"Lines: 6\nEmpty lines: 3","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Read words until the stop word `end`, which may be typed in any capitals, such as `End` or `END`. Print each word in capital letters with `!` after it, and at the end the number of words, not counting the stop word. For the input `hello`, `world`, `End`, the program prints:\n\n```\nHELLO!\nWORLD!\nWords: 2\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int words = 0;\n        while (true) {\n            String word = scanner.nextLine();\n            if (word.equalsIgnoreCase(\"end\")) {\n                break;\n            }\n            words++;\n            System.out.println(word.toUpperCase() + \"!\");\n        }\n        System.out.println(\"Words: \" + words);\n    }\n}\n","hints":["`word.equalsIgnoreCase(\"end\")` is true for `end`, `End`, `END` and every other mix of capitals.","`word.toUpperCase()` gives the word in capitals. Check for the stop word before you print or count."],"tests":[{"name":"Test 1","stdin":"hello\nworld\nEnd\n","expect":"HELLO!\nWORLD!\nWords: 2","hidden":false},{"name":"Test 2","stdin":"quiet\nEND\n","expect":"QUIET!\nWords: 1","hidden":true},{"name":"Test 3","stdin":"a\nbee\nsea\nend\nextra\n","expect":"A!\nBEE!\nSEA!\nWords: 3","hidden":true},{"name":"Test 4","stdin":"eNd\n","expect":"Words: 0","hidden":true}],"require":[],"forbid":[]},{"task":"A traffic counter types a line for each vehicle that passes: `car`, `bike` or `bus`. Read the lines until the input ends, with `hasNextLine()`, and print how many vehicles of each kind passed. For the input shown below, the program prints:\n\n```\nCars: 3\nBikes: 2\nBuses: 1\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int cars = 0;\n        int bikes = 0;\n        int buses = 0;\n        while (scanner.hasNextLine()) {\n            String vehicle = scanner.nextLine();\n            if (vehicle.equals(\"car\")) {\n                cars++;\n            } else if (vehicle.equals(\"bike\")) {\n                bikes++;\n            } else if (vehicle.equals(\"bus\")) {\n                buses++;\n            }\n        }\n        System.out.println(\"Cars: \" + cars);\n        System.out.println(\"Bikes: \" + bikes);\n        System.out.println(\"Buses: \" + buses);\n    }\n}\n","hints":["One counter for each kind, all made before the loop and starting at 0.","In the loop, read the line and compare it with `equals`: `if (vehicle.equals(\"car\")) { cars++; } else if ...`."],"tests":[{"name":"Test 1","stdin":"car\nbike\ncar\nbus\nbike\ncar\n","expect":"Cars: 3\nBikes: 2\nBuses: 1","hidden":false},{"name":"Test 2","stdin":"bus\n","expect":"Cars: 0\nBikes: 0\nBuses: 1","hidden":true},{"name":"Test 3","stdin":"bike\nbike\nbike\ncar\n","expect":"Cars: 1\nBikes: 3\nBuses: 0","hidden":true}],"require":[{"pattern":"\\.hasNextLine\\s*\\(","message":"Read until the input ends with `hasNextLine()`."}],"forbid":[]}]}