{"id":"strings-searching","slug":"searching","title":"Searching in a string","text":"Often a program needs to know whether a string contains some piece of text. The `in` operator tells: `part in text` is `True` when `part` appears somewhere in `text`, and `False` when it doesn't.\n\n```python\ntext = \"strawberry\"\nprint(\"straw\" in text)\nprint(\"berry\" in text)\nprint(\"Berry\" in text)\nprint(\"w\" in text)\n```\n\n```output\nTrue\nTrue\nFalse\nTrue\n```\n\nCapitals count: `\"Berry\"` with a capital B isn't in `\"strawberry\"`. And `not in` is the opposite: `\"x\" not in text` is `True`. Since both give `True` or `False`, they fit right into an `if` or a `while`:\n\n```python\nmessage = input(\"Message: \")\nif \"!\" in message:\n    print(\"Sounds exciting\")\nif \"?\" not in message:\n    print(\"No questions asked\")\n```\n\n```input\nPizza tonight!\n```\n\n```output\nMessage: Pizza tonight!\nSounds exciting\nNo questions asked\n```\n\n### Where is it? find\n\n`in` says whether a piece is in a string, but not where. For that, a string has `find`: `text.find(part)` gives the index where `part` first starts, or -1 if it isn't there at all.\n\n```python\ntext = \"strawberry\"\nprint(text.find(\"berry\"))\nprint(text.find(\"r\"))\nprint(text.find(\"kiwi\"))\n```\n\n```output\n5\n2\n-1\n```\n\nThere are three `r`s in `strawberry`; `find` gives the first one, at the index 2.\n\n`find` is written in a new way: after the string, with a dot. A function that belongs to a value like this is called a **method**. `find` is a method of strings, and `text.find(\"r\")` searches the string `text`, the one in front of the dot. Compare `len(text)`, a function, where the string goes inside the parentheses. Strings have many more methods, and you'll meet them soon.\n\n### An index and a slice together\n\nThe index from `find` goes well with a slice. This program splits a file name at its dot:\n\n```python\nfile_name = input(\"File: \")\ndot = file_name.find(\".\")\nif dot >= 0:\n    print(\"Name: \" + file_name[:dot])\n    print(\"Type: \" + file_name[dot + 1:])\nelse:\n    print(\"No dot in the name\")\n```\n\n```input\nnotes.txt\n```\n\n```output\nFile: notes.txt\nName: notes\nType: txt\n```\n\nCheck for -1 before you use the index. Without the check, a name with no dot would give -1, and `file_name[:-1]` would quietly cut off the last character instead of failing.\n","task":"Fill in the blank so the program says whether the text typed in has an `@` in it.\n\n```\nEmail: ada@example.com\nLooks like an email address\n```\n","kind":"fill","seed":"address = input(\"Email: \")\nif \"@\" [[in]] address:\n    print(\"Looks like an email address\")\nelse:\n    print(\"There's no @ in that\")\n","solution":"address = input(\"Email: \")\nif \"@\" in address:\n    print(\"Looks like an email address\")\nelse:\n    print(\"There's no @ in that\")\n","hints":["One word, an operator, checks whether a piece of text appears in a string.","`part in text` is `True` when `part` is somewhere in `text`."],"tests":[{"name":"Test 1","stdin":"ada@example.com\n","expect":"Email: ada@example.com\nLooks like an email address","hidden":false},{"name":"Test 2","stdin":"ada.example.com\n","expect":"Email: ada.example.com\nThere's no @ in that","hidden":true},{"name":"Test 3","stdin":"@\n","expect":"Email: @\nLooks like an email address","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Write a program that asks for a message and prints `Spam!` if the message contains the word `free` or the word `winner`, and `Looks fine` otherwise. Look for the words in small letters only.\n\n```\nMessage: you are a winner\nSpam!\n```\n","kind":"code","seed":"message = input(\"Message: \")\n","solution":"message = input(\"Message: \")\nif \"free\" in message or \"winner\" in message:\n    print(\"Spam!\")\nelse:\n    print(\"Looks fine\")\n","hints":["`\"free\" in message` is `True` when the message contains `free`.","Join two such conditions with `or`. Each side needs its own `in`: `\"free\" in message or \"winner\" in message`."],"tests":[{"name":"Test 1","stdin":"you are a winner\n","expect":"Message: you are a winner\nSpam!","hidden":false},{"name":"Test 2","stdin":"free pizza for everyone\n","expect":"Message: free pizza for everyone\nSpam!","hidden":true},{"name":"Test 3","stdin":"see you at noon\n","expect":"Message: see you at noon\nLooks fine","hidden":true},{"name":"Test 4","stdin":"the winner gets a free trip\n","expect":"Message: the winner gets a free trip\nSpam!","hidden":true}],"require":[],"forbid":[]},{"task":"Write a program that asks for an email address and prints its user name (the part before the `@`) and its domain (the part after the `@`). If there's no `@` at all, it prints `Not an email address`.\n\n```\nEmail: ada@example.com\nUser: ada\nDomain: example.com\n```\n","kind":"code","seed":"email = input(\"Email: \")\n","solution":"email = input(\"Email: \")\nat = email.find(\"@\")\nif at >= 0:\n    print(\"User: \" + email[:at])\n    print(\"Domain: \" + email[at + 1:])\nelse:\n    print(\"Not an email address\")\n","hints":["`email.find(\"@\")` gives the index of the `@`, or -1 if there's none. Keep it in a variable.","The user name is the slice up to the `@`, `email[:at]`. The domain starts one character after it.","Check for -1 before you slice."],"tests":[{"name":"Test 1","stdin":"ada@example.com\n","expect":"Email: ada@example.com\nUser: ada\nDomain: example.com","hidden":false},{"name":"Test 2","stdin":"grace.hopper@navy.mil\n","expect":"Email: grace.hopper@navy.mil\nUser: grace.hopper\nDomain: navy.mil","hidden":true},{"name":"Test 3","stdin":"nobody\n","expect":"Email: nobody\nNot an email address","hidden":true},{"name":"Test 4","stdin":"x@y\n","expect":"Email: x@y\nUser: x\nDomain: y","hidden":true}],"require":[],"forbid":[]}]}