{"id":"strings-comparing","slug":"comparing-strings","title":"Comparing strings","text":"Module 6 showed that text is compared with `equals`. Here's the rule once more, with the reason behind it. `==` asks whether two variables refer to one and the same String object in memory, while `equals` compares the characters:\n\n```java\nanswer == \"yes\"         // wrong: are they the very same object?\nanswer.equals(\"yes\")    // right: do they have the same characters?\n```\n\nWhat makes `==` tricky is that it sometimes seems to work. Java may reuse one String object for equal texts written in the code, and whether two strings end up as the same object depends on where they came from and on Java's own internals. So a program that compares text with `==` can pass a quick test and then fail on real input. With `equals`, the result depends only on the text. (For `int` and `char` values, which aren't objects, `==` is the right tool.)\n\n### Ignoring capitals\n\n`equals` counts capitals: `\"Yes\".equals(\"yes\")` is `false`. When capitals shouldn't matter, use `equalsIgnoreCase`:\n\n```java\nScanner scanner = new Scanner(System.in);\nSystem.out.println(\"Play again? (yes/no)\");\nString answer = scanner.nextLine();\nif (answer.equalsIgnoreCase(\"yes\")) {\n    System.out.println(\"New game!\");\n} else {\n    System.out.println(\"Thanks for playing\");\n}\n```\n\n```input\nYES\n```\n\n```output\nPlay again? (yes/no)\nNew game!\n```\n\nTwo more tools go well with comparing:\n\n- `!` in front turns the result around: `if (!answer.equals(\"no\"))` runs its block for every answer except `no`.\n- People sometimes type a space before or after a word without noticing. `answer.trim().equalsIgnoreCase(\"yes\")` trims first and then compares, so `\" Yes \"` counts too.\n\nA method can return the result of a comparison as a `boolean`:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(isWeekend(\"Sunday\"));\n        System.out.println(isWeekend(\"monday\"));\n        System.out.println(isWeekend(\"SATURDAY\"));\n    }\n\n    public static boolean isWeekend(String day) {\n        return day.equalsIgnoreCase(\"saturday\") || day.equalsIgnoreCase(\"sunday\");\n    }\n}\n```\n\n```output\ntrue\nfalse\ntrue\n```\n","task":"A shop's checkout takes one discount code, `SPRING10`, and capitals don't matter: `spring10` and `Spring10` work too. Ask for the code, read it, and print `Code accepted` for the right code, otherwise `Unknown code`. For the input `spring10` the program prints:\n\n```\nDiscount code:\nCode accepted\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        System.out.println(\"Discount code:\");\n        String code = 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        System.out.println(\"Discount code:\");\n        String code = scanner.nextLine();\n        if (code.equalsIgnoreCase(\"SPRING10\")) {\n            System.out.println(\"Code accepted\");\n        } else {\n            System.out.println(\"Unknown code\");\n        }\n    }\n}\n","hints":["`equals` would say no to `spring10`, because capitals count. `equalsIgnoreCase` doesn't count them.","`if (code.equalsIgnoreCase(\"SPRING10\")) { ... } else { ... }`"],"tests":[{"name":"Test 1","stdin":"spring10\n","expect":"Discount code:\nCode accepted","hidden":false},{"name":"Test 2","stdin":"SPRING10\n","expect":"Discount code:\nCode accepted","hidden":true},{"name":"Test 3","stdin":"Spring10\n","expect":"Discount code:\nCode accepted","hidden":true},{"name":"Test 4","stdin":"SPRING1\n","expect":"Discount code:\nUnknown code","hidden":true},{"name":"Test 5","stdin":"SUMMER10\n","expect":"Discount code:\nUnknown code","hidden":true}],"require":[],"forbid":[{"pattern":"(==|!=)\\s*\"\"|\"\"\\s*(==|!=)","message":"Compare text with `equals` or `equalsIgnoreCase`, not `==`."}],"more":[{"task":"Write a method `isYes(String answer)` that returns `true` when the answer is `yes` or `y`, in any capitals and with or without spaces around it, and `false` for anything else. The check runs `System.out.println(isYes(\" Yes \"));` and expects:\n\n```\ntrue\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(isYes(\" Yes \"));\n    }\n\n    // Write the isYes method here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(isYes(\" Yes \"));\n    }\n\n    public static boolean isYes(String answer) {\n        String cleaned = answer.trim();\n        return cleaned.equalsIgnoreCase(\"yes\") || cleaned.equalsIgnoreCase(\"y\");\n    }\n}\n","hints":["Trim the answer first and keep the result: `String cleaned = answer.trim();`.","Then compare twice and join the two comparisons with `||`, the way `isWeekend` does."],"tests":[{"name":"System.out.println(isYes(\" Yes \"));","stdin":"","call":"System.out.println(isYes(\" Yes \"));\n","expect":"true","hidden":false},{"name":"System.out.println(isYes(\"y\"));","stdin":"","call":"System.out.println(isYes(\"y\"));\n","expect":"true","hidden":true},{"name":"System.out.println(isYes(\"no\"));","stdin":"","call":"System.out.println(isYes(\"no\"));\n","expect":"false","hidden":true},{"name":"System.out.println(isYes(\"YES\"));","stdin":"","call":"System.out.println(isYes(\"YES\"));\n","expect":"true","hidden":true},{"name":"System.out.println(isYes(\"yesterday\"));","stdin":"","call":"System.out.println(isYes(\"yesterday\"));\n","expect":"false","hidden":true},{"name":"System.out.println(isYes(\"Y  \"));","stdin":"","call":"System.out.println(isYes(\"Y  \"));\n","expect":"true","hidden":true}],"require":[{"pattern":"\\.trim\\s*\\(","message":"Remove the spaces around the answer with `trim()`."}],"forbid":[{"pattern":"(==|!=)\\s*\"\"|\"\"\\s*(==|!=)","message":"Compare text with `equals` or `equalsIgnoreCase`, not `==`."}]},{"task":"Read words, one per line, until a word is the same as the one just before it (capitals count). Then print `Said twice: ` and that word. For the input `red`, `green`, `blue` and `blue` the program prints:\n\n```\nSaid twice: blue\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 previous = \"\";\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 previous = \"\";\n        while (true) {\n            String word = scanner.nextLine();\n            if (word.equals(previous)) {\n                System.out.println(\"Said twice: \" + word);\n                break;\n            }\n            previous = word;\n        }\n    }\n}\n","hints":["`previous` keeps the last word. In each round, read a new word and compare it with `previous` before you overwrite it.","`if (word.equals(previous)) { ... break; }`, and after the `if`, `previous = word;`."],"tests":[{"name":"Test 1","stdin":"red\ngreen\nblue\nblue\n","expect":"Said twice: blue","hidden":false},{"name":"Test 2","stdin":"go\ngo\n","expect":"Said twice: go","hidden":true},{"name":"Test 3","stdin":"a\nA\nb\nb\n","expect":"Said twice: b","hidden":true},{"name":"Test 4","stdin":"one two\none\none two\none two\n","expect":"Said twice: one two","hidden":true}],"require":[],"forbid":[{"pattern":"\\b(word|previous)\\s*(==|!=)|(==|!=)\\s*(word|previous)\\b|(==|!=)\\s*\"\"|\"\"\\s*(==|!=)","message":"Compare the words with `equals`: `==` checks whether two strings are the same object, not whether they hold the same text."}]}]}