{"id":"strings-negative-indexes","slug":"negative-indexes","title":"Counting from the end","text":"`word[len(word) - 1]` gets the last character, but Python has a shorter way: **negative indexes**, which count from the end. The index -1 is the last character, -2 the one before it, and so on:\n\n```text\n p   y   t   h   o   n\n-6  -5  -4  -3  -2  -1\n```\n\n```python\nword = \"python\"\nprint(word[-1])\nprint(word[-2])\nprint(word[-6])\n```\n\n```output\nn\no\np\n```\n\n`word[-1]` is always the same character as `word[len(word) - 1]`, whatever the length of the word. Negative indexes run out too: `\"python\"` has nothing at the index -7, so `word[-7]` is an `IndexError`, just as `word[6]` is.\n\n### Empty input\n\nWhen the user just presses Enter, `input` gives the empty string. It has no characters, so it has no first or last character, and every index is out of range:\n\nThis program makes an English noun plural in a simple way: a word that ends in `s`, such as `bus`, gets `es`, and any other word gets `s`. Pressing Enter without a word stops it:\n\n```python\nword = input(\"Word: \")\nif word[-1] == \"s\":\n    print(word + \"es\")\nelse:\n    print(word + \"s\")\n```\n\n```input\n\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 2, in <module>\n    if word[-1] == \"s\":\n       ~~~~^^^^\nIndexError: string index out of range\n```\n\nWhen a program can get an empty string, check the length before you use an index. Here the check comes first, so by the time Python gets to `word[-1]`, the word has at least one character:\n\n```python\nword = input(\"Word: \")\nif len(word) == 0:\n    print(\"No word, no plural\")\nelif word[-1] == \"s\":\n    print(word + \"es\")\nelse:\n    print(word + \"s\")\n```\n\n```input\n\n```\n\n```output\nWord:\nNo word, no plural\n```\n\n### Backwards through a string\n\nA loop can go through a string from its end. Here the index starts at -1 and goes down by one in every round, until it has passed the first character, which is at `-len(word)`:\n\n```python\nword = \"stressed\"\nbackwards = \"\"\nindex = -1\nwhile index >= -len(word):\n    backwards += word[index]\n    index -= 1\nprint(backwards)\n```\n\n```output\ndesserts\n```\n\n`stressed` has 8 characters, so `-len(word)` is -8. The loop runs with the indexes -1, -2 and so on down to -8, adding one character in every round, and ends when `index` is -9. The same works with ordinary indexes: start from `len(word) - 1`, the last index, and go down while the index is at least 0.\n","task":"Fill in the blanks so the program prints the first and the last character of the word typed in. Use a negative index for the last one.\n\n```\nWord: banana\nFirst: b\nLast: a\n```\n","kind":"fill","seed":"word = input(\"Word: \")\nprint(\"First: \" + word[[[0]]])\nprint(\"Last: \" + word[[[-1]]])\n","solution":"word = input(\"Word: \")\nprint(\"First: \" + word[0])\nprint(\"Last: \" + word[-1])\n","hints":["The first character has the index 0.","Counting from the end, the last character has the index -1."],"tests":[{"name":"Test 1","stdin":"banana\n","expect":"Word: banana\nFirst: b\nLast: a","hidden":false},{"name":"Test 2","stdin":"Python\n","expect":"Word: Python\nFirst: P\nLast: n","hidden":true},{"name":"Test 3","stdin":"x\n","expect":"Word: x\nFirst: x\nLast: x","hidden":true}],"require":[{"pattern":"\\[\\s*-\\s*1\\s*\\]","message":"Use the negative index -1 for the last character."}],"forbid":[],"more":[{"task":"A palindrome is a word that reads the same backwards, like `level` or `racecar`. Write a program that asks for a word and says whether it's a palindrome.\n\n```\nWord: level\nlevel is a palindrome\n```\n\nFor a word that isn't, it prints, for example, `python is not a palindrome`.\n","kind":"code","seed":"word = input(\"Word: \")\n","solution":"word = input(\"Word: \")\nbackwards = \"\"\nindex = -1\nwhile index >= -len(word):\n    backwards += word[index]\n    index -= 1\nif backwards == word:\n    print(f\"{word} is a palindrome\")\nelse:\n    print(f\"{word} is not a palindrome\")\n","hints":["First build the word backwards in a new string, as in the lesson's last example.","Then compare: if the backwards string is equal to the word (`==`), it's a palindrome."],"tests":[{"name":"Test 1","stdin":"level\n","expect":"Word: level\nlevel is a palindrome","hidden":false},{"name":"Test 2","stdin":"python\n","expect":"Word: python\npython is not a palindrome","hidden":true},{"name":"Test 3","stdin":"racecar\n","expect":"Word: racecar\nracecar is a palindrome","hidden":true},{"name":"Test 4","stdin":"ab\n","expect":"Word: ab\nab is not a palindrome","hidden":true},{"name":"Test 5","stdin":"noon\n","expect":"Word: noon\nnoon is a palindrome","hidden":true}],"require":[],"forbid":[]},{"task":"Write a program that asks for a sentence and looks at its last character. If it's `?`, the program prints `A question`; if it's `!`, it prints `An exclamation`; otherwise it prints `A statement`. If the user types nothing at all, it prints `Nothing to read`.\n\n```\nSentence: Is it raining?\nA question\n```\n","kind":"code","seed":"sentence = input(\"Sentence: \")\n","solution":"sentence = input(\"Sentence: \")\nif len(sentence) == 0:\n    print(\"Nothing to read\")\nelif sentence[-1] == \"?\":\n    print(\"A question\")\nelif sentence[-1] == \"!\":\n    print(\"An exclamation\")\nelse:\n    print(\"A statement\")\n","hints":["The last character is `sentence[-1]`. Compare it with `\"?\"` and `\"!\"` in an `if` and `elif`s.","An empty sentence has no last character, so check for it first, before any index is used.","The empty sentence has the length 0: `if len(sentence) == 0:`."],"tests":[{"name":"Test 1","stdin":"Is it raining?\n","expect":"Sentence: Is it raining?\nA question","hidden":false},{"name":"Test 2","stdin":"Watch out!\n","expect":"Sentence: Watch out!\nAn exclamation","hidden":true},{"name":"Test 3","stdin":"It is raining.\n","expect":"Sentence: It is raining.\nA statement","hidden":true},{"name":"Test 4","stdin":"\n","expect":"Sentence:\nNothing to read","hidden":true},{"name":"Test 5","stdin":"?\n","expect":"Sentence: ?\nA question","hidden":true}],"require":[],"forbid":[]}]}