{"id":"strings-fixed-format","slug":"fixed-format-data","title":"Data in a fixed format","text":"Programs often read data in which every line has the same shape: a name and a score, or a city and a temperature. The values are separated by a character that doesn't appear in the values themselves, often a comma or a semicolon:\n\n```\nMira,87\nOtto,92\n```\n\nEach line is split at the separator, and the parts are picked out by their index. The parts are Strings, so a number has to be turned into an `int` with `Integer.valueOf` (or into a `double` with `Double.valueOf`) before you can calculate with it:\n\n```java\nString line = \"Mira,87\";\nString[] parts = line.split(\",\");\nString name = parts[0];\nint score = Integer.valueOf(parts[1]);\nSystem.out.println(name + \" scored \" + score);\nSystem.out.println(\"With the bonus: \" + (score + 5));\n```\n\n```output\nMira scored 87\nWith the bonus: 92\n```\n\nWithout `Integer.valueOf`, `parts[1] + 5` would join the two as text and give `875`.\n\nDecimal numbers separated by semicolons work the same way:\n\n```java\nString line = \"Oulu;-4.5\";\nString[] parts = line.split(\";\");\ndouble temperature = Double.valueOf(parts[1]);\nif (temperature < 0) {\n    System.out.println(parts[0] + \" is below freezing\");\n}\n```\n\n```output\nOulu is below freezing\n```\n\n### A space too many\n\nData typed by people isn't always tidy. If a line has a space after the comma, the second part starts with that space, and `Integer.valueOf` refuses it:\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 line = scanner.nextLine();\n        String[] parts = line.split(\",\");\n        int score = Integer.valueOf(parts[1]);\n        System.out.println(parts[0] + \": \" + score);\n    }\n}\n```\n\n```input\nMira, 87\n```\n\n```crash\nException in thread \"main\" java.lang.NumberFormatException: For input string: \" 87\"\n\tat Main.main(Main.java:8)\n```\n\nThe quotes in the message show the culprit: the text was `\" 87\"`, with a space in front. `trim()` removes it, so `Integer.valueOf(parts[1].trim())` works whether the space is there or not.\n\nA line with no comma at all splits into just one part, and `parts[1]` then crashes with an `ArrayIndexOutOfBoundsException`. When the input might have lines like that, check `parts.length` before you use the parts.\n","task":"A training app saves lines such as `running,35`: an activity and how many minutes it took. Fill in the blanks, so the program reads one such line and prints the activity and its length in minutes and in seconds. For the input `running,35` it prints:\n\n```\nrunning for 35 minutes\nThat's 2100 seconds\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 line = scanner.nextLine();\n        String[] parts = line.split(\"[[,]]\");\n        String activity = parts[0];\n        int minutes = Integer.[[valueOf‖parseInt]](parts[1]);\n        System.out.println(activity + \" for \" + minutes + \" minutes\");\n        System.out.println(\"That's \" + (minutes * 60) + \" seconds\");\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 line = scanner.nextLine();\n        String[] parts = line.split(\",\");\n        String activity = parts[0];\n        int minutes = Integer.valueOf(parts[1]);\n        System.out.println(activity + \" for \" + minutes + \" minutes\");\n        System.out.println(\"That's \" + (minutes * 60) + \" seconds\");\n    }\n}\n","hints":["The separator goes between the quotes of `split`. In `running,35` it's the comma.","Text becomes an `int` with `Integer.valueOf(...)`."],"tests":[{"name":"Test 1","stdin":"running,35\n","expect":"running for 35 minutes\nThat's 2100 seconds","hidden":false},{"name":"Test 2","stdin":"yoga,60\n","expect":"yoga for 60 minutes\nThat's 3600 seconds","hidden":true},{"name":"Test 3","stdin":"swimming,5\n","expect":"swimming for 5 minutes\nThat's 300 seconds","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Write a method `toMinutes(String time)` that turns a length of time written as hours and minutes, such as `2:45`, into minutes. There may be spaces around the numbers, as in `1 : 15`. The check runs `System.out.println(toMinutes(\"2:45\"));` and expects:\n\n```\n165\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(toMinutes(\"2:45\"));\n    }\n\n    // Write the toMinutes method here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(toMinutes(\"2:45\"));\n    }\n\n    public static int toMinutes(String time) {\n        String[] parts = time.split(\":\");\n        int hours = Integer.valueOf(parts[0].trim());\n        int minutes = Integer.valueOf(parts[1].trim());\n        return hours * 60 + minutes;\n    }\n}\n","hints":["Split at the colon: `String[] parts = time.split(\":\");`. Then `parts[0]` holds the hours and `parts[1]` the minutes.","Trim each part before turning it into a number, `Integer.valueOf(parts[0].trim())`, and return `hours * 60 + minutes`."],"tests":[{"name":"System.out.println(toMinutes(\"2:45\"));","stdin":"","call":"System.out.println(toMinutes(\"2:45\"));\n","expect":"165","hidden":false},{"name":"System.out.println(toMinutes(\"0:05\"));","stdin":"","call":"System.out.println(toMinutes(\"0:05\"));\n","expect":"5","hidden":true},{"name":"System.out.println(toMinutes(\"10:00\"));","stdin":"","call":"System.out.println(toMinutes(\"10:00\"));\n","expect":"600","hidden":true},{"name":"System.out.println(toMinutes(\"1 : 15\"));","stdin":"","call":"System.out.println(toMinutes(\"1 : 15\"));\n","expect":"75","hidden":true}],"require":[{"pattern":"\\.split\\s*\\(","message":"Cut the time into hours and minutes with `split`."}],"forbid":[]},{"task":"What does this program print? Watch when the parts are text and when they're numbers.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        String line = \"Ana;3;4\";\n        String[] parts = line.split(\";\");\n        System.out.println(parts.length);\n        System.out.println(parts[1] + parts[2]);\n        int sum = Integer.valueOf(parts[1]) + Integer.valueOf(parts[2]);\n        System.out.println(parts[0] + \" \" + sum);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        String line = \"Ana;3;4\";\n        String[] parts = line.split(\";\");\n        System.out.println(parts.length);\n        System.out.println(parts[1] + parts[2]);\n        int sum = Integer.valueOf(parts[1]) + Integer.valueOf(parts[2]);\n        System.out.println(parts[0] + \" \" + sum);\n    }\n}\n","hints":["Two semicolons cut the line into three parts: `Ana`, `3` and `4`.","`parts[1] + parts[2]` joins two Strings. Only after `Integer.valueOf` are they numbers that `+` adds up."],"tests":[{"name":"Output","stdin":"","expect":"3\n34\nAna 7","hidden":false}],"require":[],"forbid":[],"lines":["3","34","Ana 7"]}]}