Комментарии 19
Как, опять?..
Да, но нет!
Да и да…
Мой пример на php (чтобы разобраться в апи телеграмм потратил 5 минут):
— при желании этот код можно сократить до 5 строк, но тогда его будет совсем сложно читать, поэтому не пойму тех кто хвастается кол-вом строк в коде.

На основе этого кода собрал бота который сидит у меня в рабочем чате и делает заметки, посмотреть на его работу можно добавив его: @jReminderBot
$api = "https://api.telegram.org/bot111111111:AAHKeYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
// получаем данные
$update = json_decode(file_get_contents("php://input"), TRUE);
$message = $update["message"];
// все команды
$commands = array(
"всем привет" => "Дратути",
"кто самый" => "Без сомнения {$message['from']['first_name']} {$message['from']['last_name']}",
);
// не учитываем регистр
$text_lower = mb_convert_case($message["text"], MB_CASE_LOWER);
// искать команду будем по первым 200 символам.
if (strlen($text_lower) > 200) $text_lower = substr($text_lower, 0, 200);
// крутим текст сообщения от конца до 1го символа в поисках существующего ключа в $commands
for ($i=0; $i < strlen($text_lower); $i++) {
$text_lower_new = substr($text_lower, 0, strlen($text_lower)-$i);
if (isset($commands[$text_lower_new])) {
$text_lower = $text_lower_new;
break;
}
}
// сам ответ
if (isset($commands[$text_lower])) $answer = $commands[$text_lower];
// отправляем ответ в чат
if (!empty($answer)) file_get_contents("{$api}/sendmessage?chat_id={$message["chat"]["id"]}&text={$answer}");
— при желании этот код можно сократить до 5 строк, но тогда его будет совсем сложно читать, поэтому не пойму тех кто хвастается кол-вом строк в коде.

На основе этого кода собрал бота который сидит у меня в рабочем чате и делает заметки, посмотреть на его работу можно добавив его: @jReminderBot
все ещё пытаюсь понять логику перебора строки посимвольно, да еще и с конца, если
а) одна из команд «здравствуйте» и базируясь на общепринятых правилах можно ожидать ее в начале строки, а не перебирать 200 символов.
б) существует strpos($text, $command)
а) одна из команд «здравствуйте» и базируясь на общепринятых правилах можно ожидать ее в начале строки, а не перебирать 200 символов.
б) существует strpos($text, $command)
ну тут просто не очевидно на примере для чего это…
ну вот в @jReminderBot я пишу "/save очень длинный текст" и вместо того что бы поставить условие:
— я ищу этот ключ в массиве перебирая строку с конца до начала:
/save очень длинный текст
/save очень длинный текс
/save очень длинный тек
/save очень длинный те
…
/save оч
/save о
/save
/save — бинго! этот ключ есть и дальше идёт перебрасывание на функцию.
Таким способом после самой команды может быть любой длинны текст… Тот же FatherBot в телеграмм запрашивает параметр для команды отдельно — пишешь /setname, после он просит придумать новое имя и отправить следующим сообщением, в моём примере это бы выглядело следующим образом: "/setname Новое имя"
При этом имя функции я так же вписываю в сам массив, примерно так это выглядит:
ну и согласитесь писать ключи в массиве гораздо удобнее и компактнее нежели всегда писать условие под каждую команду… Видимо нужно было сразу написать что не ставил цели писать обычный ехо-бот… Ну а сам массив у меня уже перекочевал в json формат, вынесенный отдельно в файл и там уже более 40 функций по мониторингу основного сайта и ещё пару шуточных функций и ответов…
Я даже думал на хабре пост написать как на php этот бот пишется закрытыми глазами, но такие статьи уже не встречают восторгом тут…
ну вот в @jReminderBot я пишу "/save очень длинный текст" и вместо того что бы поставить условие:
if (strlen($message['text']) >= 5 && substr($message['text'], 0, 5) == '/save') {
// выполняем запись текста после "/save" в бд
}
— я ищу этот ключ в массиве перебирая строку с конца до начала:
/save очень длинный текст
/save очень длинный текс
/save очень длинный тек
/save очень длинный те
…
/save оч
/save о
/save
/save — бинго! этот ключ есть и дальше идёт перебрасывание на функцию.
Таким способом после самой команды может быть любой длинны текст… Тот же FatherBot в телеграмм запрашивает параметр для команды отдельно — пишешь /setname, после он просит придумать новое имя и отправить следующим сообщением, в моём примере это бы выглядело следующим образом: "/setname Новое имя"
При этом имя функции я так же вписываю в сам массив, примерно так это выглядит:
$cmd = new Commands($message); // тут все функции
$commands = array(
"всем привет" => "Дратути",
"/save" => "fun_saveText"
);
// проверки тут разные, в цикле перебор строки и т.д всё копипастить не буду.. в предыдущем комментарии это есть.
if (strlen($commands[$text_lower]) > 3 && substr($commands[$text_lower], 0, 4) == 'fun_') {
$fun_name = substr($commands[$text_lower], 4);
if (method_exists($cmd, $fun_name)) {
$answer = call_user_func(array($cmd, $fun_name));
}else{
$answer = "Функция {$fun_name} не найдена =(";
}
}else{
$answer = $commands[$text_lower];
}
ну и согласитесь писать ключи в массиве гораздо удобнее и компактнее нежели всегда писать условие под каждую команду… Видимо нужно было сразу написать что не ставил цели писать обычный ехо-бот… Ну а сам массив у меня уже перекочевал в json формат, вынесенный отдельно в файл и там уже более 40 функций по мониторингу основного сайта и ещё пару шуточных функций и ответов…
Я даже думал на хабре пост написать как на php этот бот пишется закрытыми глазами, но такие статьи уже не встречают восторгом тут…
коллега, давайте еще раз,
— в тексте "/save очень длинный текст" команда идет первой,
— strpos() по религиозным причинам отпадает,
но что мешает начать перебор не с конца Войны и Мир, а с начала строки? каким образом на это влияет хранение команд в массиве?
— в тексте "/save очень длинный текст" команда идет первой,
— strpos() по религиозным причинам отпадает,
но что мешает начать перебор не с конца Войны и Мир, а с начала строки? каким образом на это влияет хранение команд в массиве?
прошу простить, я с утра не совсем уловил суть вашего вопроса…
что же, действительно тут вы правы:
— так мы из "/save очень длинный текст" будем двигаться от 1го символа до последнего (предварительно ограничив длину до 200 символов)
/
/s
/sa
/sav
/save — бинго, ключ найден. И вместо того что бы проверять ключ 21 раз, мы проверили его 5 раз… Что в 4 раза быстрее на данном примере.
Но если целиться на расширение команд на будущее то может произойти так что команда будет содержать в себе первым словом другую команду, на примере:
статистика — покажет общую статистику
статистика вчера — показывает статистику за вчерашний день
пример конечно с потолка, но если мне нужно будет выполнить команду "статистика вчера" — то перебирая символы с начала строки выполнится команда "статистика", именно поэтому я и решил перебирать символы с конца. Пока у меня в командах нет подобного противоречия, но кто знает… когда их будет за пару сотен, могут появиться.
P.S
всё же условие, занимает значительно больше места нежели ключ в массиве… А вот то что я вместо strpos использую substr этому нет объяснения, видимо сонный был и затупил…
P.P.S вот за что люблю хабр, что тут люди всегда посоветуют то что лучше, сейчас заменю substr на strpos и временно переключу перебор строки с первого символа, а когда появятся противоречия в командах, верну обратно перебор с конца. Grogina, вам спасибо.
что же, действительно тут вы правы:
for ($i=1; $i < strlen($text_lower); $i++) {
$text_lower_new = substr($text_lower, 0, $i);
if (isset($commands[$text_lower_new])) {
$text_lower = $text_lower_new;
break;
}
}
— так мы из "/save очень длинный текст" будем двигаться от 1го символа до последнего (предварительно ограничив длину до 200 символов)
/
/s
/sa
/sav
/save — бинго, ключ найден. И вместо того что бы проверять ключ 21 раз, мы проверили его 5 раз… Что в 4 раза быстрее на данном примере.
Но если целиться на расширение команд на будущее то может произойти так что команда будет содержать в себе первым словом другую команду, на примере:
статистика — покажет общую статистику
статистика вчера — показывает статистику за вчерашний день
пример конечно с потолка, но если мне нужно будет выполнить команду "статистика вчера" — то перебирая символы с начала строки выполнится команда "статистика", именно поэтому я и решил перебирать символы с конца. Пока у меня в командах нет подобного противоречия, но кто знает… когда их будет за пару сотен, могут появиться.
P.S
if (strpos($text_lower, "/save") == 0) {
// действие
}
всё же условие, занимает значительно больше места нежели ключ в массиве… А вот то что я вместо strpos использую substr этому нет объяснения, видимо сонный был и затупил…
P.P.S вот за что люблю хабр, что тут люди всегда посоветуют то что лучше, сейчас заменю substr на strpos и временно переключу перебор строки с первого символа, а когда появятся противоречия в командах, верну обратно перебор с конца. Grogina, вам спасибо.
Ребята, вы конечно простите, но на дворе 2017 год.
Чем вам регулярные выражения так в душу нагадили, что вы начали перебирать «Войну и мир»?
Я понимаю и знаю, что они медленные, но в данном случае — это просто панацея отхламавелосипедов. Можно будет команды буквально в любую позицию строки писать.
Чем вам регулярные выражения так в душу нагадили, что вы начали перебирать «Войну и мир»?
Я понимаю и знаю, что они медленные, но в данном случае — это просто панацея от
даже если у вас их будет несколько сотен и вы хотите реализовать все в таком миксе текста и команд, ничто не мешает начать, бог с ним, перебор с позиции strlen($command_with_max_length)-1
поэтому не пойму тех кто хвастается кол-вом строк в коде
Мне странно, что вы где-то увидели хвастовство.
"...50 строк кода" в заголовке — это означает, что кода в статье немного и он не сложный. Не ищите подтекста там, где его нет.
Читаю такие статьи и ни в одной не описано, зачем, используя вебхук, еще дополнительно дергать sendMessage? Ведь в webHook явно сказано, что вместо того, чтобы просто отвечать 200 — можно сразу ответить сообщением и оно уйдет в телеграм.
Какие-то накладные расходы? Минусы? Поделитесь, пожалуйста?
Отличный гайд, у меня все сработало. Только несколько поправочек для тех, кто деплоит на Хероку.
1. Запускать из командной строки проще так. Хероку автоматически проксирует все запросы.
А ваш пример почему-то удалял вебхук.
2. Также херока сам проставляет порт из переменной окружения:
Подробнее про деплой Питон приложений на Хероку тут
Кому-то может быть полезным. У Хероки есть бесспорные плюсы:
Пробовала сделать на вебхуках через ноду, но пост запросы к моему приложению не проходили, видимо потому что response не тот возвращался.
1. Запускать из командной строки проще так. Хероку автоматически проксирует все запросы.
heroku run curl -X POST "https://api.telegram.org/botTOKEN/setWebhook?url=HOST/api/v1"
А ваш пример почему-то удалял вебхук.
2. Также херока сам проставляет порт из переменной окружения:
port=os.environ.get('PORT', 8080)
Подробнее про деплой Питон приложений на Хероку тут
Кому-то может быть полезным. У Хероки есть бесспорные плюсы:
- Проксирование запросов к апи телеграмма
- Бесплатно
Пробовала сделать на вебхуках через ноду, но пост запросы к моему приложению не проходили, видимо потому что response не тот возвращался.
*
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Telegram-бот, webhook и 50 строк кода