{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Строки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Из программы экзамена\n",
    "\n",
    "> 12.\tСтроки. Понятие неизменяемости строки. Срезы строки. «Обращение» строки. Поиск в строке: методы `find()` и  `rfind()`. Методы `replace()` и `count()`. Поиск в строке количества подстрок с наложением («задача о котиках»).  Методы `lower()` и `upper()`.  «Выравнивание» строки: методы `rjust()` и `ljust()`.  Типовые задачи о строках: подсчет количества символов, удовлетворяющих заданному условию, удаление подстроки, замена подстроки другой подстрокой, перестановка частей строки."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Строка  &ndash; набор символов в кавычках. Одинарных, двойных или тройных. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Привет!\n",
      "John's dog\n",
      "\n",
      "Еду. Тихо. Слышны звоны\n",
      "Под копытом на снегу,\n",
      "Только серые вороны\n",
      "Расшумелись на лугу.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "s1 = 'Привет!'\n",
    "s2 = \"John's dog\"\n",
    "s3 = '''\n",
    "Еду. Тихо. Слышны звоны\n",
    "Под копытом на снегу,\n",
    "Только серые вороны\n",
    "Расшумелись на лугу.\n",
    "'''\n",
    "print(s1)\n",
    "print(s2)\n",
    "print(s3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Индексация (нумерация символов) в строке начинается **с нуля**.  \n",
    "Обратная нумерация: последний элемент имеет индекс -1, предпоследний -2 и т.д. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "||||||Нумерация символов в строке |\n",
    "|:--|:--|:--|:--|:--|:--|\n",
    "| 0 | 1 | 2 | 3 | 4 | 5 | \n",
    "|<font size=+2>С|<font size=+2>Т|<font size=+2>Р|<font size=+2>О|<font size=+2>К|<font size=+2>А| \n",
    "| -6 | -5 | -4 | -3 | -2 | -1 | "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "К\n",
      "Р\n"
     ]
    }
   ],
   "source": [
    "s = 'СТРОКА'\n",
    "print(s[4])\n",
    "print(s[-4])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Про неизменяемость**.\n",
    "\n",
    "The _value_ of some objects can change. Objects whose value can change are said to be <em>mutable</em>; objects whose value is unchangeable once they are created are called immutable... An object’s mutability is determined by its type; for instance, numbers, **strings** and tuples are immutable, while dictionaries and lists are mutable.\n",
    "\n",
    "<div align=right>\n",
    "    <a href=https://docs.python.org/3/reference/datamodel.html#objects-values-and-types>The Python Language Reference. 3. Data model </a>\n",
    "</div>\n",
    "\n",
    "\n",
    "Доступ к символу `s[i]` &ndash; только на чтение, изменить отдельный символ строки нельзя. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Иллюстрации**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'str' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[3], line 3\u001b[0m\n\u001b[0;32m      1\u001b[0m s \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbanana\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m      2\u001b[0m \u001b[38;5;28mprint\u001b[39m(s[\u001b[38;5;241m0\u001b[39m])\n\u001b[1;32m----> 3\u001b[0m \u001b[43ms\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mc\u001b[39m\u001b[38;5;124m'\u001b[39m\n",
      "\u001b[1;31mTypeError\u001b[0m: 'str' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "s = 'banana'\n",
    "print(s[0])\n",
    "s[0] = 'c'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b: id = 140718075023624\n",
      "a: id = 140718075023576\n",
      "n: id = 140718075024200\n",
      "a: id = 140718075023576\n",
      "n: id = 140718075024200\n",
      "a: id = 140718075023576\n"
     ]
    }
   ],
   "source": [
    "for i in range(0,6):\n",
    "    print (f'{s[i]}: id = {id(s[i])}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1598935386944"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(s)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "banana ananas\n"
     ]
    }
   ],
   "source": [
    "s += ' ananas'\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1598941317232"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "banana 1598935386944\n",
      "banana ananas 1598941320240\n"
     ]
    }
   ],
   "source": [
    "s = 'banana'\n",
    "print(s, id(s))\n",
    "s += ' ananas'\n",
    "print(s, id(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Escape-последовательности\n",
    "\n",
    "Escape-последовательность, или экранированная последовательность, или управляющая последовательность &ndash; это часть строки, которая начинается с символа \"\\\\\", за которым следует один или более символов. Такие конструкции не являются видимой частью строки, в том смысле, что при выводе их на экран функцией `print` выполняется некоторое действие или изображается нечто другое.\n",
    "\n",
    "В таблице приведены некоторые последовательности, работающие в Python 3 Shell и/или в среде Jupyter Notebook\n",
    "\n",
    "|Последовательность| Описание | Пример | Результат выполнения |\n",
    "|:---|:---|:---|:---|\n",
    "|`\\n`| Перенос строки (новая строка). | `print('привет\\nмир')` |<div style=\"font-family: monospace \">привет<br>мир</div> | \n",
    "|`\\t`| Горизонтальная табуляция. | `print('привет\\tмир')` |<div style=\"font-family: monospace \">привет&nbsp;&nbsp;&nbsp;&nbsp;мир</div> |\n",
    "|`\\r`|Возврат курсора в начало строки<sup>1</sup>. <br> Новые символы выводятся, \"заменяя\" старые. | `print('привет\\rмир')` |<div style=\"font-family: monospace \">мирвет</div> |\n",
    "|`\\b`|Аналог клавиши Backspace. Возврат курсора на одну позицию влево, удаление символа слева<sup>1</sup>.  | `print('привет\\bмир')` |<div style=\"font-family: monospace \">привемир</div> |\n",
    "|`\\N{описание символа}`|Выводит символ по его описанию в базе данных Юникода. Например, так можно вывести многие эмодзи<sup>2</sup>.| `print('\\N{flushed face}')` |😳| \n",
    "|`\\xhh`|Символ с шестнадцатеричным кодом hh (две шестнадцатеричные цифры).| `print('\\xC4')` |<div style=\"font-family: monospace \">Ä</div> |\n",
    "|`\\uhhhh`|16-битный символ Юникода, т.е. символ кодируемый двумя байтами (четыре шестнадцатеричные цифры).|`print('\\u265E')`|♞|\n",
    "|`\\Uhhhhhhhh`|32-битный символ Юникода, т.е. символ кодируемый четырьмя байтами (восемь шестнадцатеричных цифр). Таким способом тоже можно выводить эмодзи<sup>2</sup> | `print('\\U0001F609')` |😉|\n",
    "|`\\\\`|Экранирование обратного слэша. Позволяет включить в строку символ ```\\```. | `print('привет\\\\мир')` |<div style=\"font-family: monospace \">привет\\мир</div> |\n",
    "|`\\'`|Экранирование апострофа. Позволяет включить в строку символ апострофа ```'```. | `print('привет\\'мир')` |<div style=\"font-family: monospace \">привет'мир</div> |\n",
    "|`\\\"`|Экранирование кавычки. Позволяет включить в строку символ кавычки ```\"```. | `print(\"привет\\\"мир\")` |<div style=\"font-family: monospace \">привет\"мир</div> |\n",
    "|`\\[конец строки]`|Запись одной строки на нескольких строках в тексте программы. | `print('привет\\`<br>`всем\\`<br>`всем')` |<div style=\"font-family: monospace \">приветвсемвсем</div> |\n",
    "\n",
    "\n",
    "<sup>1</sup> Не работает в Shell (Windows)<br>\n",
    "<sup>2</sup> <a href=\"https://unicode.org/emoji/charts/emoji-list.html\">Emoji List, v13.1</a> \n",
    "\n",
    "Подробная информация: https://pyprog.pro/python/py/str/esqape_sec.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "\n",
    "**r-строки**, или _сырые_ строки. В строках вида `r'привет\\nмир'` игнорируются управляющие последовательности "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "**f-строки**. Возможность использования значений переменных внутри строки. Примеры, в том числе использования форматирования &ndash; ниже."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "31.41592\n",
      "31.42\n",
      "31.41592000\n",
      "3.141592e+01\n",
      "            31.41592\n",
      "31.41592            \n",
      "            31.41592\n"
     ]
    }
   ],
   "source": [
    "x = 31.41592      # число\n",
    "y = '31.41592'    # строка\n",
    "print(f'{x}')     # вывод \"как есть\"\n",
    "print(f'{x:.2f}') # два знака после десятичной точки\n",
    "print(f'{x:.8f}') # восемь знаков после десятичной точки\n",
    "print(f'{x:e}')   # вывод в экспоненциальном формате\n",
    "print(f'{x:20}')  # числа выравниваются по правому краю\n",
    "print(f'{y:20}')  # остальные строки - по левому краю\n",
    "print(f'{y:>20}') # но если очень хочется...\n",
    "                  # есть еще варианты < и  ^\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Краткий справочник по некоторым функциям и методам строк**<sup>3</sup>\n",
    "\n",
    "| Операция, функция или метод| Назначение  |\n",
    "|:---|:---|\n",
    "|`s1 + s2`|Конкатенация или слияние строк|\n",
    "|`s * n`|Повторение строки `n` раз|\n",
    "|`s[i]`|Доступ к символу по его индексу (отсчет индексов идёт с нуля)|\n",
    "|`s[i:j:step]`|Получение среза|\n",
    "|`len(s)`|Длина строки|\n",
    "|`s.find(str, start, end)`|Поиск подстроки в строке. Возвращает номер ***первого*** вхождения или -1, если подстрока не найдена. По умолчанию `start=0`, то есть поиск идет с начала строки, а `end` соответствует последнему символу строки.|\n",
    "|`s.rfind(str, start, end)`|Поиск подстроки в строке. Возвращает номер ***последнего*** вхождения или -1|\n",
    "|`s.replace(pattern, new_substr)`|Замена шаблона `pattern` новой строкой|\n",
    "|`s.upper()`|Преобразование строки к верхнему регистру|\n",
    "|`s.lower()`|Преобразование строки к нижнему регистру|\n",
    "|`s.count(str, start, end)`|Возвращает количество непересекающихся вхождений подстроки `str` в диапазоне [начало, конец]. По умолчанию &ndash;  от начала и до конца строки|\n",
    "|`s.rstrip()`|Удаление пробельных символов в конце строки|\n",
    "|`s.ljust(width, fillchar=' ')`|Делает длину строки не меньшей `width`, по необходимости заполняя последние символы символом `fillchar`|\n",
    "|`s.rjust(width, fillchar=' ')`|Делает длину строки не меньшей `width`, по необходимости заполняя первые символы символом `fillchar`|\n",
    "|`s.center(width, fillchar=' ')`|Возвращает отцентрованную строку, по краям которой стоит символ `fillchar` |\n",
    "|`ord(c)`|Вычисление Юникода заданного символа `c`|\n",
    "|`chr(n)`|Вычисление символа по его Юникоду `n`|\n",
    "| | |\n",
    "|`s.split(sep)`|Разбиение строки на части по символу-разделителю `sep`; по умолчанию разбивается по пробелу, а получающиеся пустые строки игнорируются|\n",
    "|`s.join(lst)`|Объединение списка строк в одну строку; в качестве склейки выступает строка `s`|\n",
    "\n",
    "<sup>3</sup> Полный список функций и методов с подробным описанием можно посмотреть здесь: https://pythonru.com/osnovy/stroki-python\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "олово\n"
     ]
    }
   ],
   "source": [
    "# пример  среза\n",
    "s = 'головоломка'\n",
    "print(s[1:6])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "халат\n"
     ]
    }
   ],
   "source": [
    "# потренируемся ? \n",
    "# что выведет этот код?\n",
    "s = 'холоп'\n",
    "s = s.replace('о', 'а').replace('п', 'т')\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "холоп\n"
     ]
    }
   ],
   "source": [
    "s = 'холоп'\n",
    "s.replace('о', 'а')\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div align = right>\n",
    "    Ниже приведены задачи с сайта <a href=\"http://www.pythontutor.ru\">ПИТОНТЬЮТОР</a>\n",
    "</div>    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Делаем срезы**.  <br/>\n",
    "Дана строка.<br/>\n",
    "Сначала выведите третий символ этой строки.<br/> \n",
    "Во второй строке выведите предпоследний символ этой строки.<br/> \n",
    "В третьей строке выведите первые пять символов этой строки.<br/> \n",
    "В четвертой строке выведите всю строку, кроме последних двух символов.<br/> \n",
    "В пятой строке выведите все символы с четными индексами (считая, что индексация начинается с 0, поэтому символы выводятся, начиная с первого).<br/> \n",
    "В шестой строке выведите все символы с нечетными индексами, то есть, начиная со второго символа строки. <br/>\n",
    "**В седьмой строке выведите все символы в обратном порядке**. <br/>\n",
    "В восьмой строке выведите все символы строки через один в обратном порядке, начиная с последнего. <br/>\n",
    "В девятой строке выведите длину данной строки. <br/>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "r\n",
      "r\n",
      "Abrak\n",
      "Abrakadab\n",
      "Arkdba\n",
      "baaar\n",
      "arbadakarbA\n",
      "abdkrA\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "s = 'Abrakadabra'\n",
    "#s = 'Hello'\n",
    "print(s[2])\n",
    "print(s[-2])\n",
    "print(s[:5])\n",
    "print(s[:-2])\n",
    "print(s[::2])\n",
    "print(s[1::2])\n",
    "print(s[::-1])\n",
    "print(s[::-2])\n",
    "print(len(s))\n"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "=== для строки 'Hello' должно получиться:\n",
    "l\n",
    "l\n",
    "Hello\n",
    "Hel\n",
    "Hlo\n",
    "el\n",
    "olleH\n",
    "olH\n",
    "5\n",
    "=== для строки 'Abrakadabra' должно получиться:\n",
    "r\n",
    "r\n",
    "Abrak\n",
    "Abrakadab\n",
    "Arkdba\n",
    "baaar\n",
    "arbadakarbA\n",
    "abdkrA\n",
    "11"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Количество слов**. <br/>\n",
    "Дана строка, состоящая из слов, разделенных пробелами. Определите, сколько в ней слов. Используйте для решения задачи метод `count`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7\n"
     ]
    }
   ],
   "source": [
    "s0 = 'Шла Саша по шоссе и сосала сушку'\n",
    "# скороговорка. Народное?\n",
    "print(s0.count(' ')+1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "s ='1234'\n",
    "print(s.count(''))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**А если между словами не один пробел?**  \n",
    "В строке найдите все серии подряд идущих пробелов и замените каждую на один пробел"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Шла*Саша*по*шоссе*и*сосала*сушку\n"
     ]
    }
   ],
   "source": [
    "# для наглядности заменим пробелы звездочками\n",
    "def remove_spaces(s):\n",
    "    while \"**\" in s:\n",
    "        s = s.replace(\"**\", \"*\")\n",
    "    return s    \n",
    "\n",
    "s0 = 'Шла****Саша******по*****шоссе**и***сосала**сушку'\n",
    "print(remove_spaces(s0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Переставить два слова**. <br/> \n",
    "Дана строка, состоящая ровно из двух слов, разделенных пробелом. Переставьте эти слова местами. Результат запишите в строку и выведите получившуюся строку.<br/> \n",
    "При решении этой задачи не стоит пользоваться циклами и инструкцией `if`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "мир привет\n"
     ]
    }
   ],
   "source": [
    "s = 'привет мир'\n",
    "k = s.find(' ')\n",
    "s1 = s[k+1:] + ' ' + s[:k]\n",
    "print(s1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Первое и последнее вхождения**. <br/>\n",
    "Дана строка. Если в этой строке буква f встречается только один раз, выведите её индекс. Если она встречается два и более раз, выведите индекс её первого и последнего появления. Если буква f в данной строке не встречается, ничего не выводите."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 17\n"
     ]
    }
   ],
   "source": [
    "# тестовые строки (раскомментировать нужное)\n",
    "s = 'I like football'\n",
    "s = 'We are the champions!'\n",
    "s = '\"fifa2020\" is my favorite game'\n",
    "s = '\"Fifa2020\" is my favorite game'\n",
    "n = s.count('f')\n",
    "if n==1:\n",
    "    print(s.find('f'))\n",
    "elif n>1:\n",
    "    print(s.find('f'), s.rfind('f'))\n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Второе вхождение**. <br/> \n",
    "Дана строка. Найдите в этой строке второе вхождение буквы f, и выведите индекс этого вхождения. Если буква f в данной строке встречается только один раз, выведите число -1, а если не встречается ни разу, выведите число -2\n",
    "\n",
    "<div style=\"color:blue;\">\n",
    "\n",
    "*Самостоятельно проанализировать приведенное решение!*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# тестовые строки (раскомментировать нужное)\n",
    "# s = 'I like football'\n",
    "# s = 'We are the champions!'\n",
    "# s = '\"fifa2020\" is my favorite game'\n",
    "s = '\"Fifa2020\" is my favorite game'\n",
    "n = s.find('f')\n",
    "if n==-1:\n",
    "    print(-2)\n",
    "else:\n",
    "    n = s.find('f', n+1)\n",
    "    print(n)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Удаление фрагмента**. <br/> \n",
    "Дана строка, в которой буква h встречается минимум два раза. Удалите из этой строки первое и последнее вхождение буквы h, а также все символы, находящиеся между ними."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tone.\n"
     ]
    }
   ],
   "source": [
    "# тестовые строки (раскомментировать нужное)\n",
    "s = 'This phone is better than iPhone.'\n",
    "# s = 'пример_h_на русском_h_языке'\n",
    "k1 = s.find('h')\n",
    "k2 = s.rfind('h')\n",
    "s = s[:k1]+s[k2+1:]\n",
    "print(s)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div align = right>\n",
    "    Ниже приведены задачи с сайта <a href=\"http://ptaskbook.com/ru/tasks/string.php\">Programming Taskbook</a>\n",
    "</div> "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**String3**.     \n",
    "Дан символ `c`. Вывести два символа, первый из которых предшествует символу `c` в кодовой таблице, а второй следует за символом `c`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "c:  z\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "y {\n"
     ]
    }
   ],
   "source": [
    "# String 3\n",
    "c = input(\"c: \")\n",
    "n = ord(c)\n",
    "print(chr(n-1), chr(n+1))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "😀\n",
      "😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🙐🙑🙒🙓🙔🙕🙖🙗🙘🙙🙚🙛🙜🙝🙞🙟🙠🙡🙢🙣🙤🙥🙦🙧🙨🙩🙪🙫🙬🙭🙮🙯🙰🙱🙲🙳🙴🙵🙶🙷🙸🙹🙺🙻🙼🙽🙾🙿🚀🚁🚂🚃🚄🚅🚆🚇🚈🚉🚊🚋🚌🚍🚎🚏🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚝🚞🚟🚠🚡🚢🚣🚤🚥🚦🚧🚨🚩🚪🚫🚬🚭🚮🚯🚰🚱🚲🚳🚴🚵🚶🚷🚸🚹🚺🚻🚼🚽🚾🚿🛀🛁🛂🛃🛄🛅🛆🛇🛈🛉🛊🛋🛌🛍🛎🛏🛐🛑🛒🛓🛔🛕🛖🛗🛘🛙🛚🛛🛜🛝🛞🛟🛠🛡🛢🛣🛤🛥🛦🛧🛨🛩🛪🛫🛬🛭🛮🛯🛰🛱🛲🛳🛴🛵🛶🛷🛸🛹"
     ]
    }
   ],
   "source": [
    "# А как посмотреть на те эмоджи, которые может вывести Питон?\n",
    "face = '\\N{grinning face}'\n",
    "print(face)\n",
    "n = ord(face) \n",
    "#  а дальше?\n",
    "for i in range(n, n+250):\n",
    "    print(chr(i), end='')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**String25**.   \n",
    "Дана строка, изображающая десятичную запись целого положительного числа. Вывести строку, изображающую двоичную запись этого же числа."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "101001\n"
     ]
    }
   ],
   "source": [
    "# String 25\n",
    "s_10 = '41'\n",
    "n = int(s_10)\n",
    "s_2 = ''\n",
    "while n>0:\n",
    "    s_2 = str(n%2) + s_2\n",
    "    n //= 2\n",
    "print(s_2)    \n",
    "\n",
    "# 41 = 4*10**1 + 1*10**0\n",
    "# 101001 = 1*2**5 + 0*2**4 + 1*2**3 + 0*2**2 + 0*2**1 +1*2**0\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "41 = 4\\cdot10^1 + 1\\cdot10^0\n",
    "$$\n",
    "$$\n",
    "101001_2 = 1\\cdot2^5 + 0\\cdot2^4 + 1\\cdot2^3 + 0\\cdot2^2 + 0\\cdot2^1 +1\\cdot2^0\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on built-in function bin in module builtins:\n",
      "\n",
      "bin(number, /)\n",
      "    Return the binary representation of an integer.\n",
      "\n",
      "    >>> bin(2796202)\n",
      "    '0b1010101010101010101010'\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# используем \"внутренние резервы\" Питона\n",
    "help(bin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "101001\n"
     ]
    }
   ],
   "source": [
    "s = '41'\n",
    "n = int(s)\n",
    "print(bin(n)[2:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**String53**.  \n",
    "Дана строка-предложение на русском языке. Подсчитать количество содержащихся в строке знаков препинания."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7000000 4.458608150482178\n",
      "7000000 0.13246941566467285\n"
     ]
    }
   ],
   "source": [
    "from time import time\n",
    "# String 53\n",
    "s0 = 'Шла, Саша? по! шоссе!!! и: сосала сушку'*10**6\n",
    "znaki = '.,!?:;'\n",
    "# вариант 1\n",
    "start = time()\n",
    "k = 0\n",
    "for c in s0:\n",
    "    if c in znaki:\n",
    "        k += 1\n",
    "finish = time()\n",
    "print(k, finish-start)        \n",
    "# вариант 2\n",
    "start = time()\n",
    "k = 0\n",
    "for z in znaki:\n",
    "    k += s0.count(z)\n",
    "finish = time()\n",
    "print(k, finish-start)    \n",
    "\n",
    "# s0=s0*10**7\n",
    "# сравнить время работы\n",
    "# почему такая разница?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Recur13**. \n",
    "Описать рекурсивную функцию `palindrome(s)` логического типа, возвращающую `True`, если строка `s` является палиндромом (т. е. читается одинаково слева направо и справа налево), и `False` в противном случае. Оператор цикла в теле функции не использовать. Вывести значения функции `palindrome` для пяти данных строк."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Лирическое отступление о палиндромах\n",
    "\n",
    "<img src=\"buratino.jpg\" width=\"200\" align = left style=\"padding-right: 20px\">\n",
    "<p>\n",
    "<em>\n",
    "– У вас нет никаких способностей к математике, – с огорчением сказала\n",
    "девочка. – Займемся диктантом. <br>\n",
    "Она подняла к потолку хорошенькие глаза.\n",
    "<br>\n",
    "– Пишите: “А роза упала на лапу Азора”. Написали? Теперь прочтите эту\n",
    "волшебную фразу наоборот.\n",
    "<br>\n",
    "Нам уже известно, что Буратино никогда даже не видел пера и чернильницы.\n",
    "<br>\n",
    "Девочка сказала: “Пишите”, – и он сейчас же сунул в чернильницу свой\n",
    "нос и страшно испугался, когда с носа на бумагу упала чернильная клякса.\n",
    "</em>\n",
    "<div align=right>\n",
    "А.Н. Толстой. Золотой ключик, или Приключения Буратино\n",
    "</div>    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def palindrome(s):\n",
    "    if len(s)<2:\n",
    "        return True\n",
    "    return s[0]==s[-1] and palindrome(s[1:-1])    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(palindrome('А роза упала на лапу Азора'))\n",
    "print(palindrome('арозаупаланалапуазора'))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Корректировка: напишем новый `palindrom1` так, чтобы оба варианта давали `True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def palindrome1(s):\n",
    "    return palindrome(s.lower().replace(' ', ''))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "palindrome1('А роза упала на лапу Азора')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А как написать максимально короткий нерекурсивный вариант функции `palindrom`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "def palindrome2(s):\n",
    "    return s == s[::-1]\n",
    "\n",
    "print(palindrome2('арозаупаланалапуазора'))\n",
    "print(palindrome2('привет'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Дополнительные задачи на строки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Усложнение задачи про палиндром**. Дана строка. Какую минимально возможную строку к ней нужно добавить, чтобы получился палиндром?\n",
    "\n",
    "Например, для строки `'море'` это будет строка `'ром'`, для строки `'арозаупаланалапу'` это будет строка `'азора'`, для строки `'арозаупаланалапуазора'` ответом будет пустая строка.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_palindrome(s):\n",
    "    v = ''\n",
    "    i = 0\n",
    "    while not palindrome(s+v):\n",
    "        v = s[i] + v\n",
    "        i += 1\n",
    "    return v    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ром\n",
      "азора\n",
      "\n",
      "cba\n"
     ]
    }
   ],
   "source": [
    "# тестируем\n",
    "s = 'море'\n",
    "print(make_palindrome(s))\n",
    "\n",
    "s = 'арозаупаланалапу'\n",
    "print(make_palindrome(s))\n",
    "\n",
    "s = 'арозаупаланалапуазора'\n",
    "print(make_palindrome(s))\n",
    "\n",
    "s = 'abcd'\n",
    "print(make_palindrome(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Задачи для самостоятельного решения.   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1. Числа-палиндромы**. \n",
    "\n",
    "Натуральное число $N$ назовем *палиндромом*, если оно читается одинаково справа налево и слева направо. Например, числа 121 и 2002 являются палиндромами, а числа 10, 123 и 2022 - не являются.\n",
    "\n",
    "Напишите функцию `is_palindrome(n)`, возвращающую `True`, если `n` $-$ это палиндром, и `False` $-$ в противном случае.\n",
    "\n",
    "**Важно**: использовать перевод числа в строку и наоборот **не разрешается**.\n",
    "\n",
    "*За представленное вовремя решение этой задачи можно получить до двух бонусных баллов*\n",
    "\n",
    "\n",
    "\n",
    "**2. Поломай палиндром!**\n",
    "\n",
    "Дана строка-палиндром `palindrome`, состоящая из маленьких букв русского алфавита. \n",
    "Напишите программу, которая заменяет в этой строке ровно одну букву, \n",
    "так что полученная в результате строка уже не является палиндромом, при этом новая\n",
    "строка является лексикографически самой маленькой их всех возможных. \\\n",
    "В качестве ответа программа должна выдавать исправленную строку. \n",
    "Если нет такого способа заменить символ, чтобы строка перестала быть палиндромом, \n",
    "программа должна выдавать строку, состоящую из трех восклицательных знаков, ```'!!!'```.\n",
    "\n",
    "*Примечание*. Строка `s1` лексикографически меньше, чем строка `s2` той же длины, если в той позиции, где  `s1`  `s2`впервые различаются, символ строки  `s1` меньше (то есть встречается в алфавите раньше), чем соответствующий символ в строке `s2`. Например, `\"вагон\"` лексикографически меньше, чем `\"вальс\"`, потому что эти слова отличаются в первый раз в третьем символе, а `'г'` встречается в русском алфавите раньше, чем `'л'`. Если все буквы первого слова два слова полностью совпадают с буквами второго, но второе длиннее, то первое считается меньшим. Например, `'кот'` меньше, чем `'котёнок'`.\n",
    "\n",
    "**Пример**. `palindrome = 'кок'`. \\\n",
    "**Правильный ответ:** `'аок'`. \\\n",
    "**Пояснение:** Испортить палиндром можно разными способами, например, `'ток'` или `'кот'`. Но `'аок'` - лексикографически самая маленькая строка\n",
    "\n",
    "\n",
    "\n",
    "*За представленное вовремя решение этой задачи можно получить до трех бонусных баллов*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача «про котиков»**. <br/>\n",
    "Метод `count` вычисляется количество непересекающихся подстрок в строке, поэтому \n",
    "для строки \n",
    "\n",
    "```python\n",
    "s='котик котик'\n",
    "``` \n",
    "`s.count('котик')=2`, а для строки\n",
    "\n",
    "```python\n",
    "s='котикотик'\n",
    "```\n",
    "\n",
    "`s.count('котик')=1`. <br/>\n",
    "\n",
    "Написать функцию `total_count(s, sub)`, которая определяет количество всех вхождений подстроки `sub` в строку `s`, в том числе и пересекающихся, так что\n",
    "\n",
    "```python\n",
    "total_count('котикотик', 'котик')=2 \n",
    "total_count('мамамамама', 'мама')=4\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# вариант 1\n",
    "def total_count(s, sub):\n",
    "    k = 0\n",
    "    p = s.find(sub)\n",
    "    while p>=0:\n",
    "        k += 1\n",
    "        p = s.find(sub, p+1)   \n",
    "    return k    \n",
    "# вариант 2 ?\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on method_descriptor:\n",
      "\n",
      "find(...) unbound builtins.str method\n",
      "    S.find(sub[, start[, end]]) -> int\n",
      "\n",
      "    Return the lowest index in S where substring sub is found,\n",
      "    such that sub is contained within S[start:end].  Optional\n",
      "    arguments start and end are interpreted as in slice notation.\n",
      "\n",
      "    Return -1 on failure.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(str.find)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert total_count('котик котик', 'котик')==2, 'Test0'\n",
    "assert total_count('мама мама мама', 'мама')==3, 'Test1'\n",
    "assert total_count('котикотик', 'котик')==2, 'Test2'\n",
    "assert total_count('мамамамама', 'мама')==4, 'Test3'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "котикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотикотик\n",
      "100\n"
     ]
    }
   ],
   "source": [
    "n = 10**2\n",
    "s = 'коти'*n+'к'\n",
    "print(s)\n",
    "print(total_count(s, 'котик'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Составь сто**.   \n",
    "Дана строка цифр: `'123456789'`. Между некоторыми из цифр разрешается вставить знаки `+`, `-`, так что в результате будут получаться выражения вида `123+45-6+7+89`. Найти все такие выражения, значение которых равно 100.\n",
    "\n",
    "<div style=\"color:blue;\">\n",
    "\n",
    "*Приведенный ниже код - для самостоятельного обдумывания. Можно ли придумать более красивое решение?*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "123+45-67+8-9\n",
      "123+4-5+67-89\n",
      "123-45-67+89\n",
      "123-4-5-6-7+8-9\n",
      "12+3+4+5-6-7+89\n",
      "12+3-4+5+67+8+9\n",
      "12-3-4+5-6+7+89\n",
      "1+23-4+56+7+8+9\n",
      "1+23-4+5+6+78-9\n",
      "1+2+34-5+67-8+9\n",
      "1+2+3-4+5+6+78+9\n"
     ]
    }
   ],
   "source": [
    "# программируем быстро. Получится ли красиво?\n",
    "s = '123456789'\n",
    "znaki = '', '+', '-'\n",
    "for z1 in znaki:\n",
    "    for z2 in znaki:\n",
    "        for z3 in znaki:\n",
    "            for z4 in znaki:\n",
    "                for z5 in znaki:\n",
    "                    for z6 in znaki:\n",
    "                        for z7 in znaki:\n",
    "                            for z8 in znaki:\n",
    "                                s = '1'+z1+'2'+z2+'3'+z3+'4'+z4+'5'+z5+'6'+z6+'7'+z7+'8'+z8+'9'\n",
    "                                if eval(s)==100:\n",
    "                                    print(s)\n",
    "\n",
    "                               "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Про функцию eval"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Шифрование-1 (шифр Цезаря)**. Написать функцию `c_code(s)`, которая осуществляет шифрование предложения на русском языке `s` путем циклической замены каждой буквы на следующую за ней в алфавите и сохранив при этом регистр букв («А» перейдет в «Б», «а» — в «б», «Б» — в «В», «я» — в «а» и т. д.). Знаки препинания и пробелы не изменять.  Написать также функцию `c_decode(s)`, которая по зашифрованной строке восстанавливает исходную строку."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "ALPHABET ='АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯА'\n",
    "ALPHABET += ALPHABET.lower()\n",
    "def c_char(a):\n",
    "    if a in ALPHABET:\n",
    "        n = ALPHABET.find(a)\n",
    "        return ALPHABET[n+1]\n",
    "    else:\n",
    "        return a\n",
    "\n",
    "def c_code(s):\n",
    "    s1 = ''\n",
    "    for c in s:\n",
    "        s1 += c_char(c)\n",
    "    return s1    \n",
    "\n",
    "def dc_char(a):\n",
    "    if a in ALPHABET:\n",
    "        n = ALPHABET.rfind(a)\n",
    "        return ALPHABET[n-1]\n",
    "    else:\n",
    "        return a\n",
    "    \n",
    "def c_decode(s):\n",
    "    s1 = ''\n",
    "    for c in s:\n",
    "        s1 += dc_char(c)\n",
    "    return s1    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__add__',\n",
       " '__class__',\n",
       " '__contains__',\n",
       " '__delattr__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__getnewargs__',\n",
       " '__getstate__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__iter__',\n",
       " '__le__',\n",
       " '__len__',\n",
       " '__lt__',\n",
       " '__mod__',\n",
       " '__mul__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__rmod__',\n",
       " '__rmul__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'capitalize',\n",
       " 'casefold',\n",
       " 'center',\n",
       " 'count',\n",
       " 'encode',\n",
       " 'endswith',\n",
       " 'expandtabs',\n",
       " 'find',\n",
       " 'format',\n",
       " 'format_map',\n",
       " 'index',\n",
       " 'isalnum',\n",
       " 'isalpha',\n",
       " 'isascii',\n",
       " 'isdecimal',\n",
       " 'isdigit',\n",
       " 'isidentifier',\n",
       " 'islower',\n",
       " 'isnumeric',\n",
       " 'isprintable',\n",
       " 'isspace',\n",
       " 'istitle',\n",
       " 'isupper',\n",
       " 'join',\n",
       " 'ljust',\n",
       " 'lower',\n",
       " 'lstrip',\n",
       " 'maketrans',\n",
       " 'partition',\n",
       " 'removeprefix',\n",
       " 'removesuffix',\n",
       " 'replace',\n",
       " 'rfind',\n",
       " 'rindex',\n",
       " 'rjust',\n",
       " 'rpartition',\n",
       " 'rsplit',\n",
       " 'rstrip',\n",
       " 'split',\n",
       " 'splitlines',\n",
       " 'startswith',\n",
       " 'strip',\n",
       " 'swapcase',\n",
       " 'title',\n",
       " 'translate',\n",
       " 'upper',\n",
       " 'zfill']"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(str)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Епвспё фусп!\n"
     ]
    }
   ],
   "source": [
    "# тестируем написанные функции\n",
    "print(c_code('Доброе утро!'))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Доброе утро!\n"
     ]
    }
   ],
   "source": [
    "print(c_decode('Епвспё фусп!'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Шифрование-2**.  \n",
    "Написать функцию `xor_code`, принимающую 2 аргумента: строку, которую нужно зашифровать, и ключ шифрования, а возвращающуют строку, зашифрованную путем применения функции `xor` над символами строки с ключом. \n",
    "\n",
    "А как восстановить данные? Написать функцию `xor_decode`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def xor_code(text, key):\n",
    "    n = len(text)\n",
    "    m = len(key)\n",
    "    if m<n:\n",
    "        key = key*(n//m+1)\n",
    "    res = ''\n",
    "    for i in range(n):\n",
    "        x = ord(text[i])^ord(key[i])\n",
    "        res += chr(x)\n",
    "    return res    \n",
    "   \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# кодируем\n",
    "print(xor_code('Доброе утро!', 'привет'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# декодируем\n",
    "print(xor_code('+~\tr\u000b",
    "wП\u0003zr\u000b",
    "ѣ', 'привет'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "***Прежде чем писать код:***\n",
    "\n",
    "Появился повод поговорить о битовых операциях.\n",
    "\n",
    "|Логическая операция|Битовая операция|Пример|Результат|\n",
    "|:---|:---:|:---:|:---:|\n",
    "|логическое **И**, `and`|`&`|`5 & 6`|4|\n",
    "|логическое **ИЛИ**, `or`|`\\|`|`5 \\| 6`|7|\n",
    "|исключающее **ИЛИ** |`^`|`5 ^ 6`|3|\n",
    "|логическое отрицание,`not`|`~`|`~5`|-6|\n",
    "\n",
    "\n",
    "Несколько неожиданный результат в последней строке связан со спецификой хранения отрицательных целых чисел в памяти компьютера. Подробнее с этим можно познакомиться, например, <a hef=\"https://foxford.ru/wiki/informatika/otritsatelnye-chisla-v-pamyati-kompyutera-dopolnitelnyy-kod\">здесь</a>."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# демонстрация\n",
    "x, y = 5, 6\n",
    "print(x, bin(x))\n",
    "print(y, bin(y))\n",
    "print(x ^ y, bin(x ^ y))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# исследуем подробнее операцию XOR\n",
    "a = 5860\n",
    "b = 3443\n",
    "c = a^b\n",
    "# кодирование\n",
    "print(c)\n",
    "# декодирование\n",
    "print(c^b)\n",
    "\n",
    "# 1 ^ 0 ^ 0 = 1\n",
    "# 1 ^ 1 ^ 1 = 1\n",
    "# 0 ^ 0 ^ 0 = 0\n",
    "# 0 ^ 1 ^ 1 = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Ну и в завершение темы: как перевести в двоичный формат число в диапазоне (0, 1), например 0.25?\n",
    "\n",
    "Напоминание:\n",
    "$$534_{10} = 5\\cdot10^2+3\\cdot10^1+4\\cdot10^0$$\n",
    "\n",
    "$$10110_2 = 1\\cdot2^4+ 0\\cdot2^3+ 1\\cdot2^2+ 1\\cdot2^1+ 0\\cdot2^0 = 22_{10}$$\n",
    "\n",
    "Аналогично:\n",
    "$$0,534_{10} = 0 + 5\\cdot10^{-1}+ 3\\cdot10^{-2}+ 4\\cdot10^{-3}$$\n",
    "\n",
    "$$0,10110_2 = \\\\0 +  1\\cdot2^{-1}+ 0\\cdot2^{-2}+ 1\\cdot2^{-3}+ 1\\cdot2^{-4}+ 0\\cdot2^{-5} = 0,6875_{10}$$\n",
    "\n",
    "Алгоритм вычисления десятичных цифр после запятой в некотором смысле противоположен уже использованному ранее: надо не делить на 10, а умножать на 10, а потом вычислять целую часть. Основной вопрос: когда закончить?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# проверяем на десятичных числах\n",
    "x = 0.543\n",
    "s = '0.'\n",
    "n = 3 \n",
    "for i in range(n):\n",
    "    x *= 10\n",
    "    c = int(x)\n",
    "    s += str(c)\n",
    "    x -= c\n",
    "print(s)    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# проверяем на двоичных числах\n",
    "x = 0.6875\n",
    "s = '0.'\n",
    "n = 5 \n",
    "for i in range(n):\n",
    "    x *= 2\n",
    "    c = int(x)\n",
    "    s += str(c)\n",
    "    x -= c\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# можно ли поменять for на while?\n",
    "x = 0.1     # 0.6875\n",
    "s = '0.'\n",
    "while x>0:\n",
    "    x *= 2\n",
    "    c = int(x)\n",
    "    s += str(c)\n",
    "    x -= c\n",
    "print(s)\n",
    "\n",
    "# 0.00011001100110011001100110011001100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вроде бы ok.  \n",
    "Но теперь попробуем (без компьютера) выполнить этот же алгоритм для числа 0.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Задача на строки из индивидуальной работы\n",
    "\n",
    "Разработать функцию, которая в данной строке `s` ищет подстроку, удовлетворяющую следующим \n",
    "условиям:  \n",
    "* Начинается с последовательности символов `start_substr`,  \n",
    "* имеет длину `substr_length`,  \n",
    "* в свою очередь содержит подстроку `has_substr`,  \n",
    "* к началу строки расположена не ближе чем `leftMargin`  \n",
    "\n",
    "```python\n",
    "def findSubstr(s, start_substr, substr_length, has_substr, left_margin):\n",
    "```    \n",
    "\n",
    "\n",
    "\n",
    "Результатом функции должен быть кортеж, состоящий из целого числа и строки, \n",
    "определяемых по следующему правилу:   \n",
    "Если подходящая подстрока обнаружена, то результатом функции является номер ее \n",
    "первого символа внутри строки `s` и сама эта подстрока. Если подходящая подстрока не \n",
    "обнаружена, то результатом функции должно быть число `-1` и пустая строка. Если входные \n",
    "параметры не имеют смысла (например, длина подстроки отрицательна, или \n",
    "последовательности символов – пустые), результатом функции должно быть число `-2` и пустая \n",
    "строка. \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "s = 'Чудесная загадка соответствия математического языка \\\n",
    "законам физики является удивительным даром, \\\n",
    "который мы не в состоянии понять \\\n",
    "и которого мы, возможно, недостойны. \\\n",
    "(Юджин Пол Вигнер)'\n",
    "\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Первый этап работы:**  \n",
    "определим, какие варианты входных параметров можно считать \"не имеющими смысла\":\n",
    "1. \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Второй этап работы:**  \n",
    "определим, когда можно \"не работать\", потому что входные параметры противоречат друг другу:\n",
    "1. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"color:blue\">Если <b>реализовать</b> эти два этапа, то уже можно рассчитывать на пару-тройку баллов за задачу</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Третий этап работы**: описать алгоритм\n",
    "\n",
    "\n",
    "Например, такой вариант:  \n",
    "1. Устанавливаем начальное значение точки поиска, `p`, в позицию, соответствующую `left_margin`\n",
    "2. Начиная с позиции `p`, ищем вхождение начала подстроки, `start_substr`\n",
    "3. Если не нашли, возвращаем `-1, ''`; выход из функции\n",
    "4. (Нашли, например, `k`) Вычисляем расстояние от `k`-го символа, до конца строки. \n",
    "5. Если оно меньше, чем `substr_length`, возвращаем `-1,''`; выход из функции\n",
    "6. Если срез `s[k:k+substr_length]` содержит подстроку `has_substr`, возвращаем `k` и этот срез.\n",
    "7. Позиции поиска `p` присваиваем значение `k+1`  и повторяем этапы, начиная со второго\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def findSubstr(s, start_substr, substr_length, \n",
    "               has_substr, left_margin):\n",
    "    \n",
    "    n = len(s)\n",
    "    # Первый этап\n",
    "    if start_substr=='' or substr_length<=0 or \\\n",
    "        has_substr=='' or left_margin<0:\n",
    "        return -2, '' \n",
    "    # Второй этап\n",
    "    if len(start_substr)>n or len(has_substr)>n or \\\n",
    "        left_margin>=n:\n",
    "        return -1, ''\n",
    "    # Третий этап\n",
    "    p = left_margin\n",
    "    k = s.find(start_substr, p)\n",
    "    while k>=0:\n",
    "        if n-k<substr_length:   #5\n",
    "            return -1, ''\n",
    "        if has_substr in s[k:k+substr_length]:\n",
    "            return k,s[k:k+substr_length]\n",
    "        p = k+1\n",
    "        k = s.find(start_substr, p)\n",
    "    return -1, ''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "findSubstr(s, 'загадка', 58, 'физики', 5)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "findSubstr(s, 'мы', 25, 'не', 50) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "findSubstr(s, 'загадка', 58, 'физика', 5) "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
