{"id":"reading-files-searching","slug":"searching-a-file","title":"Searching a file","text":"Many questions about a file are answered by going through its lines once and checking each one. How many lines mention something? Is a certain line there at all? This program counts and prints the lines of a log that contain the word `ERROR`:\n\n```file log.txt\n08:00 start\n08:15 ERROR disk almost full\n09:30 backup done\n10:05 ERROR connection lost\n10:06 connection back\n```\n\n```java\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        int errors = 0;\n        try (Scanner scanner = new Scanner(Paths.get(\"log.txt\"))) {\n            while (scanner.hasNextLine()) {\n                String line = scanner.nextLine();\n                if (line.contains(\"ERROR\")) {\n                    System.out.println(line);\n                    errors++;\n                }\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Errors: \" + errors);\n    }\n}\n```\n\n```output\n08:15 ERROR disk almost full\n10:05 ERROR connection lost\nErrors: 2\n```\n\nAny String method can do the checking: `contains` for a part of the line, `startsWith` for its beginning, `equals` for the whole line, `equalsIgnoreCase` when capitals shouldn't matter.\n\n### Is a line there?\n\nTo find out whether something is in the file at all, keep a `boolean` that starts as `false` and becomes `true` when a line matches. The answer is known only after the loop, once every line has been checked. Here the user types a discount code, and the program looks for it in the file of valid codes:\n\n```file codes.txt\nWELCOME5\nSPRING10\nFRIEND20\n```\n\n```java\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String code = scanner.nextLine();\n        boolean found = false;\n        try (Scanner fileScanner = new Scanner(Paths.get(\"codes.txt\"))) {\n            while (fileScanner.hasNextLine()) {\n                if (fileScanner.nextLine().equals(code)) {\n                    found = true;\n                }\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        if (found) {\n            System.out.println(\"Code accepted\");\n        } else {\n            System.out.println(\"Unknown code\");\n        }\n    }\n}\n```\n\n```input\nSPRING10\n```\n\n```output\nCode accepted\n```\n\n- `equals` compares whole lines. With `contains`, the code `RING1` would be accepted too, since it's inside `SPRING10`.\n- The answer is printed after the loop. Printed inside it, there would be an answer for every line of the file.\n","task":"The file `reviews.txt` holds a restaurant's reviews, one per line. The program reads a word and counts the reviews that mention it. Fill in the blanks. For the input `pizza` and the file shown below, it prints:\n\n```\nReviews that mention pizza: 3\n```\n","kind":"fill","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String word = scanner.nextLine();\n        int count = 0;\n        try (Scanner fileScanner = new Scanner(Paths.get(\"reviews.txt\"))) {\n            while (fileScanner.hasNextLine()) {\n                String line = fileScanner.nextLine();\n                if (line.[[contains]](word)) {\n                    [[count++‖count += 1‖count = count + 1‖++count]];\n                }\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Reviews that mention \" + word + \": \" + count);\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String word = scanner.nextLine();\n        int count = 0;\n        try (Scanner fileScanner = new Scanner(Paths.get(\"reviews.txt\"))) {\n            while (fileScanner.hasNextLine()) {\n                String line = fileScanner.nextLine();\n                if (line.contains(word)) {\n                    count++;\n                }\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Reviews that mention \" + word + \": \" + count);\n    }\n}\n","hints":["A review mentions the word when the word is somewhere inside the line: `contains`.","The second blank adds one to the counter: `count++`."],"tests":[{"name":"Test 1","stdin":"pizza\n","files":{"reviews.txt":"The pizza was great\nSlow service\nBest pizza in town\nNice staff, cold pizza\nLovely desserts\n"},"expect":"Reviews that mention pizza: 3","hidden":false},{"name":"Test 2","stdin":"service\n","files":{"reviews.txt":"The pizza was great\nSlow service\nBest pizza in town\nNice staff, cold pizza\nLovely desserts\n"},"expect":"Reviews that mention service: 1","hidden":true},{"name":"Test 3","stdin":"sushi\n","files":{"reviews.txt":"The pizza was great\nSlow service\n"},"expect":"Reviews that mention sushi: 0","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Read a word, and print the number of the first line of `diary.txt` that contains it, as `First on line ` and the number. If no line contains it, print `Not in the file`. For the input `apple` and the file shown below, the program prints:\n\n```\nFirst on line 2\n```\n","kind":"code","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String word = scanner.nextLine();\n\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String word = scanner.nextLine();\n        int lineNumber = 0;\n        int first = 0;\n        try (Scanner fileScanner = new Scanner(Paths.get(\"diary.txt\"))) {\n            while (fileScanner.hasNextLine()) {\n                String line = fileScanner.nextLine();\n                lineNumber++;\n                if (first == 0 && line.contains(word)) {\n                    first = lineNumber;\n                }\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        if (first == 0) {\n            System.out.println(\"Not in the file\");\n        } else {\n            System.out.println(\"First on line \" + first);\n        }\n    }\n}\n","hints":["Count the lines as you read them. Keep the number of the first match in a variable that starts at 0, which means nothing found yet.","Set it only while it's still 0: `if (first == 0 && line.contains(word))`. Later matches then don't change it."],"tests":[{"name":"Test 1","stdin":"apple\n","files":{"diary.txt":"Went to the market\nBought apples and pears\nRain all afternoon\nBaked an apple pie\n"},"expect":"First on line 2","hidden":false},{"name":"Test 2","stdin":"Rain\n","files":{"diary.txt":"Went to the market\nBought apples and pears\nRain all afternoon\nBaked an apple pie\n"},"expect":"First on line 3","hidden":true},{"name":"Test 3","stdin":"snow\n","files":{"diary.txt":"Went to the market\nBought apples and pears\n"},"expect":"Not in the file","hidden":true},{"name":"Test 4","stdin":"pie\n","files":{"diary.txt":"Went to the market\nBought apples and pears\nRain all afternoon\nBaked an apple pie\n"},"expect":"First on line 4","hidden":true},{"name":"Test 5","stdin":"Went\n","files":{"diary.txt":"Went to the market\nWent home\n"},"expect":"First on line 1","hidden":true}],"require":[],"forbid":[]},{"task":"What does this program print? Compare `equals` and `contains` on every line.\n","kind":"predict","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(\"green tea\\ntea\\nTea cake\\nsteam\");\n        int same = 0;\n        int inside = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            if (line.equals(\"tea\")) {\n                same++;\n            }\n            if (line.contains(\"tea\")) {\n                inside++;\n            }\n        }\n        System.out.println(\"equals: \" + same);\n        System.out.println(\"contains: \" + inside);\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(\"green tea\\ntea\\nTea cake\\nsteam\");\n        int same = 0;\n        int inside = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            if (line.equals(\"tea\")) {\n                same++;\n            }\n            if (line.contains(\"tea\")) {\n                inside++;\n            }\n        }\n        System.out.println(\"equals: \" + same);\n        System.out.println(\"contains: \" + inside);\n    }\n}\n","hints":["Only one line is exactly `tea`. `Tea cake` starts with a capital T, so neither check matches it.","Look inside `steam`: s, t, e, a, m."],"tests":[{"name":"Output","stdin":"","expect":"equals: 1\ncontains: 3","hidden":false}],"require":[],"forbid":[],"lines":["equals: 1","contains: 3"]}]}