{"id":"recap-text","slug":"text","title":"Taking text apart","text":"Input often packs several values into one line of text. A program cuts the line into parts, turns the parts that are numbers into numbers, and asks questions about the parts that are words.\n\n### The tools\n\n| Tool | What it does | Taught in |\n| --- | --- | --- |\n| `line.split(\",\")` | cuts a line at every comma, into an array of parts | module 16, Working with strings |\n| `parts.length`, `parts[0]` | how many parts there are, and one part | module 15, Arrays |\n| `Integer.valueOf(parts[1])` | a part that holds a whole number, as an int | module 3, Variables and types, and module 16 |\n| `text.equals(other)` | the same text? Never compare text with `==` | module 6, Conditions and logic |\n| `contains`, `startsWith`, `endsWith` | yes-or-no questions about text | module 16, Working with strings |\n| `text.trim()` | the text without spaces at either end | module 16, Working with strings |\n\n### Words on a line\n\nChess players write down their games move by move. Each move is a short code, such as `Nf3` (a knight moves to the square f3). An `x` in a move means it captures a piece, and a `+` at the end means it puts the other king in check. Here are the first moves of a game, one code for each player's move, separated by spaces:\n\n```java\nString moves = \"e4 e5 Nf3 Nc6 Bb5 a6 Bxc6 dxc6\";\nString[] parts = moves.split(\" \");\nint captures = 0;\nfor (String move : parts) {\n    if (move.contains(\"x\")) {\n        captures++;\n    }\n}\nSystem.out.println(parts.length + \" moves, \" + captures + \" captures\");\nSystem.out.println(\"Last move: \" + parts[parts.length - 1]);\n```\n\n```output\n8 moves, 2 captures\nLast move: dxc6\n```\n\n- `split(\" \")` gives an array of Strings, one per move, and a for-each loop goes through them.\n- `contains(\"x\")` asks whether the letter appears anywhere in the move. It counts capital letters apart from small ones: `contains(\"X\")` would find nothing here.\n- The last part is at the index `parts.length - 1`.\n\n### A line of comma-separated values\n\nA climbing gym's member list has one line per member: the name, the age and the number of visits this month, separated by commas. Someone typed a space after each comma. The gym calls a member with 8 visits or more in a month a regular.\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        String[] parts = scanner.nextLine().split(\",\");\n        String name = parts[0].trim();\n        int age = Integer.valueOf(parts[1].trim());\n        int visits = Integer.valueOf(parts[2].trim());\n        System.out.println(\"Name: \" + name);\n        System.out.println(\"Age: \" + age);\n        System.out.println(\"Visits: \" + visits);\n        System.out.println(\"Regular: \" + (visits >= 8));\n    }\n}\n```\n\n```input\nMira Koski, 34, 12\n```\n\n```output\nName: Mira Koski\nAge: 34\nVisits: 12\nRegular: true\n```\n\n- The parts are Strings, even when they hold digits. `Integer.valueOf` turns them into ints. Without it, `parts[2].trim() + 1` would join the texts and give `121`.\n- `split(\",\")` cuts only at the commas, so the second part is `\" 34\"`, with the space in front. `Integer.valueOf(\" 34\")` throws a NumberFormatException, and `trim()` removes the space first (module 16).\n- A line with fewer than three parts would crash at `parts[2]` with an ArrayIndexOutOfBoundsException. When lines can be broken, check `parts.length` first and skip the line (module 29).\n","task":"The program reads one line of chess moves, separated by spaces, and prints how many moves there are, how many of them capture a piece (they contain an `x`), and how many give check (they end with `+`). Fill in the blanks. For the input shown, the program prints:\n\n```\nMoves: 12\nCaptures: 3\nChecks: 1\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        String[] moves = scanner.nextLine().[[split]](\" \");\n        int captures = 0;\n        int checks = 0;\n        for (String move : moves) {\n            if (move.[[contains]](\"x\")) {\n                captures++;\n            }\n            if (move.[[endsWith‖contains]](\"+\")) {\n                checks++;\n            }\n        }\n        System.out.println(\"Moves: \" + [[moves.length]]);\n        System.out.println(\"Captures: \" + captures);\n        System.out.println(\"Checks: \" + checks);\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        String[] moves = scanner.nextLine().split(\" \");\n        int captures = 0;\n        int checks = 0;\n        for (String move : moves) {\n            if (move.contains(\"x\")) {\n                captures++;\n            }\n            if (move.endsWith(\"+\")) {\n                checks++;\n            }\n        }\n        System.out.println(\"Moves: \" + moves.length);\n        System.out.println(\"Captures: \" + captures);\n        System.out.println(\"Checks: \" + checks);\n    }\n}\n","hints":["`split(\" \")` cuts the line at every space, into an array of moves. An array's size is its `length`, without parentheses.","`contains` asks whether a piece of text appears anywhere in the move, and `endsWith` whether the move ends with it."],"tests":[{"name":"Test 1","stdin":"e4 e5 Nf3 d6 Bc4 Bg4 Nc3 g6 Nxe5 Bxd1 Bxf7+ Ke7\n","expect":"Moves: 12\nCaptures: 3\nChecks: 1","hidden":false},{"name":"Test 2","stdin":"d4 d5 c4 dxc4\n","expect":"Moves: 4\nCaptures: 1\nChecks: 0","hidden":true},{"name":"Test 3","stdin":"e4 d5 exd5 Qxd5 Nc3 Qa5 d4 c6 Bc4 Bf5 Bd2 e6 Qe2 Bb4 Qxe6+\n","expect":"Moves: 15\nCaptures: 3\nChecks: 1","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A woodworking student writes down each piece to cut: its name, its length and its width in centimeters. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        String line = \"shelf,40,25\";\n        String[] parts = line.split(\",\");\n        System.out.println(parts[1] + parts[2]);\n        System.out.println(Integer.valueOf(parts[1]) + Integer.valueOf(parts[2]));\n        System.out.println(parts[0].length() + parts.length);\n        System.out.println(parts[0] + parts.length);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        String line = \"shelf,40,25\";\n        String[] parts = line.split(\",\");\n        System.out.println(parts[1] + parts[2]);\n        System.out.println(Integer.valueOf(parts[1]) + Integer.valueOf(parts[2]));\n        System.out.println(parts[0].length() + parts.length);\n        System.out.println(parts[0] + parts.length);\n    }\n}\n","hints":["The parts are Strings. `+` between two Strings joins them, and `+` between two ints adds them up.","`parts[0].length()` is the number of letters in `shelf`, and `parts.length` the number of parts. Two ints are added up, but a String followed by an int joins them."],"tests":[{"name":"Output","stdin":"","expect":"4025\n65\n8\nshelf3","hidden":false}],"require":[],"forbid":[],"lines":["4025","65","8","shelf3"]},{"task":"At a chess tournament, the games are written down one per line: the player with the white pieces, the player with the black pieces, and the result, separated by commas, like `Mira,Jonas,1-0`. The result `1-0` means that white won, `0-1` that black won, and `1/2-1/2` is a draw. A win is worth 1 point, a draw half a point, and a loss nothing.\n\nThe first line of input is a player's name. Then come games, until an empty line. Print how many games that player played, and their points, which are a `double`. Skip the games the player wasn't in. A name must match in full: `Ada` isn't in a game of `Adam`. For the input shown, the program prints:\n\n```\nMira played 4 games\nPoints: 2.5\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        String player = scanner.nextLine();\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        String player = scanner.nextLine();\n        int games = 0;\n        double points = 0;\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\",\");\n            String white = parts[0];\n            String black = parts[1];\n            String result = parts[2];\n            if (!white.equals(player) && !black.equals(player)) {\n                continue;\n            }\n            games++;\n            if (result.equals(\"1/2-1/2\")) {\n                points += 0.5;\n            } else if (result.equals(\"1-0\") && white.equals(player)) {\n                points += 1;\n            } else if (result.equals(\"0-1\") && black.equals(player)) {\n                points += 1;\n            }\n        }\n        System.out.println(player + \" played \" + games + \" games\");\n        System.out.println(\"Points: \" + points);\n    }\n}\n","hints":["Read the games in a `while (true)` loop that stops at the empty line. Split each line at the commas: `parts[0]` is white, `parts[1]` black and `parts[2]` the result. When neither player `equals` the name, `continue`.","A draw gives `points += 0.5;`. A win is `1-0` when the player is white, or `0-1` when the player is black. Keep `points` in a `double`, so it prints like `2.5`."],"tests":[{"name":"Test 1","stdin":"Mira\nMira,Jonas,1-0\nJonas,Ada,0-1\nAda,Mira,1/2-1/2\nJonas,Mira,0-1\nMira,Ada,0-1\n\n","expect":"Mira played 4 games\nPoints: 2.5","hidden":false},{"name":"Test 2","stdin":"Theo\nMira,Jonas,1-0\n\n","expect":"Theo played 0 games\nPoints: 0.0","hidden":true},{"name":"Test 3","stdin":"Ada\nAdam,Mira,1-0\nAda,Adam,1/2-1/2\nMira,Ada,1-0\nAda,Theo,1/2-1/2\nTheo,Ada,1/2-1/2\nAda,Mira,1-0\n\n","expect":"Ada played 5 games\nPoints: 2.5","hidden":true}],"require":[],"forbid":[]}]}