Исходник Гайд AHK RegExMatch | SAMP | Пишем свой авто-ответчик

BASS_DEVSOFTWARE

Известный 🇺🇦
Автор темы
Друг
264
567
Приветствую всех! 👋

Данная статья должна помочь разобраться новичкам в Регулярных выражениях и помочь им самостоятельно писать скрипты на автоматический ответ, при появлении в чате N-строки (по задумке).


🆘🆘🆘

Перед игроком появляется будто бы непреодолимая стена, посмотрев на которую, он побежит по форумам просить помощи.

🆘🆘🆘


autohotkey.png



Хочу предупредить - данная статья рассчитана на незнающих пользователей. Поэтому подробность данной статьи - это скорее плюс (как по мне).




Для начала, предлагаю взять каркас нашего скрипта:​
AutoHotKey:
#Include samp.ahk
#IfWinActive GTA:SA:MP
ChatLog = C:\Users\User\Documents\GTA San Andreas User Files\SAMP\chatlog.txt
loop    {
lastline := GetNewLine(ChatLog)
;Здесь будет наше регулярное выражение
If expression !=
   SendChat("команда")
}
GetNewLine(filename)    {
static old
static new
if !old    {
        FileGetSize, old, %filename%
        new := old
    }
while old = new    {
        sleep 100 ;задержка
        FileGetSize, new, %filename%
    }
old := new
Loop, read, %filename%
if A_LoopReadLine    {
        last := A_LoopReadLine
    }
return last
}
!end::ExitApp
end::Reload
Примечание: Для работы вам потребуется скачать AutoHotKey и SAMP UDF.



Что же мы имеем в нашем каркасе? Давайте разберёмся:
AutoHotKey:
;Строка # 1 отвечает за загрузку библиотеки SAMP UDF (обязательно действие при написании скриптов с использованием UDF)
;Строка # 2 исполняет скрипт только в открытом приложении GTA
#Include samp.ahk
#IfWinActive GTA:SA:MP

AutoHotKey:
;Путь к chatlog.txt, а именно к файлу, где сохраняются все сообщения из чата игры
ChatLog = C:\Users\User\Documents\GTA San Andreas User Files\SAMP\chatlog.txt

AutoHotKey:
; Начало нашего цикла
loop
{
AutoHotKey:
; lastline - переменная, что хранит в себе данные, полученные с функции GetNewLine.
lastline := GetNewLine(ChatLog)
AutoHotKey:
;Здесь будет наше регулярное выражение и этим всё сказано (вернёмся позже).
AutoHotKey:
;Условие, которое будет исполнено при НЕ пустой переменной регулярного выражения.
If expression !=
{
AutoHotKey:
;SendChat - функция, которая позволяет писать в чат не используя клавиатуру и базовые возможности АХК. (Send, SendInput, SendRaw и.т.д.)
SendChat("команда")
AutoHotKey:
; 1. Закрыли условие expression
; 2. Закрыли цикл loop
}
}
AutoHotKey:
; Далее идёт функция, что определяет появившуюся строку в чате.
; На данном этапе не вижу смысла разбирать эту функцию построчно,
; но в будущем, при потребности - мы обязательно это сделаем.

GetNewLine(filename)
{
static old
static new
if !old
    {
        FileGetSize, old, %filename%
        new := old
    }
while old = new
    {
        sleep 100
        FileGetSize, new, %filename%
    }
old := new
Loop, read, %filename%
if A_LoopReadLine
    {
        last := A_LoopReadLine
    }
return last
}
AutoHotKey:
; Строка № 1 - Сочетание клавиш Alt+END - завершит процесс данного скрипта
; Строка № 2 - Нажатие END - перезагрузит скрипт, после чего он будет готов к работе
!end::ExitApp
end::Reload




Надеюсь, вы поняли структуру и что за чем идёт.
Теперь смело копируйте каркас нашего скрипта, чтобы мы смогли вместе его редактировать.
(Копируйте цельным блоком, что я предоставил вам в самом начале)

И вот мы подошли к моменту, на котором желторотики вскрывают себе вены, а новички бьются в конвульсиях, я говорю о РеГуЛяРнЫх ВыРаЖеНиЯх.

Я не собираюсь копировать термин из Википедии, что такое "Регулярные выражения". Скажу своими словами: Регулярные выражения - это возможность копировать/вырезать/отправлять, одним словом - обработать необходимую нам строку и достать из неё N-слова. Будь они статичны или переменны - роли не играет.

:hunter:Строку, что нам нужна, будем определять благодаря этим же Регулярным выражениям.:hunter:
В нашем случае - мы будем рассматривать строки такого типа:​
[16:24:44] Nick_Name[7]: по чём штаны?

[20:33:41] - рюмка водки (Nick_Name) [178]

[54:23:41] [23] - Патрик, привет! (Nick_Name)




Ну что, включаем мозг?



В Регулярных выражениях есть такое понятие, как литеральный текст. Звучит страшно, но расскажу максимально понятно и только то, что нужно.

\
.
*
?
+
[
{
|
(
)
^
$

Если в искомой строке есть/могут быть литеральные символы, необходимо - нет, не плакать.
Перед и После литеральный символ необходимо обставить \Q и \E соответственно.
Таким образом, например " [ ", будет считаться не буквально и будет воспринято как часть строки.
AutoHotKey:
; Строка в стандартном виде
Nick_Name[7]
; Строка в виде регулярного выражения
Nick_Name\Q[\E7\Q]\E
; Или же
Nick_Name\[7\]
Поправка: \Q .. \E в написании, можно заменить на \ перед любым литеральным символом.
Пример выше.


Главное - не забыть о существовании литеральных символов в принципе.
Запомнили? Молодцы.

Так же, Регулярное выражение не прощает опечаток!
Лишний пробел или его отсутствие может запороть любую "регулярку". И уж поверьте - одним криком от отчаяния и злости от глупого прокола вы не обойдётесь.
Поэтому, всегда следите при написании Регулярного выражения за тем, чтобы они были 1 в 1: "регулярка" в своём понимании, а наша строка - в своём.
AutoHotKey:
;Пример № 1, правильно составленное регулярное выражение:
var = ert tre zsdf
RegExMatch(var, "ert t(.)e zsdf", var)
MsgBox % var1

;Пример № 2, НЕправильно составленное регулярное выражение:
var = ert tre zsdf
RegExMatch(var, "ert t(.)e  zsdf", var)
MsgBox % var1

;Ошибка примера № 2, в виде лишнего пробела перед zsdf.
;Не допускайте таких ошибок.

Структура Регулярного выражения до боли проста:
AutoHotKey:
RegExMatch(ПеременнаяОтСюдаЧитаем, "Опции искомой строки", результат на выходе)



autohotkey2.png




Плавно подошли к написанию собственного Регулярного выражения.

Возьмём за пример эту строку:​
[16:24:44] Nick_Name[7]: по чём штаны?



Из неё нам необходимо "вытащить" Фамилию, ID и само сообщение. Приступим?​
AutoHotKey:
;Для примера нам необходимо создать переменную var, в которой будет находиться наша строка.
var = [16:24:44] Nick_Name[7]: по чём штаны?


Выражение (.*), иногда называют ВсёЧтоУгодно, оно позволит скопировать необходимые нам части сообщения.​
AutoHotKey:
RegExMatch(var, "[16:24:44] Nick_(.*)[(\d\d?\d?)]: (.*)", find)


Теперь занимаемся литеральными символами. У нас их 4.
Две [ скобочки и две ] скобки.​
AutoHotKey:
RegExMatch(var, "\[16:24:44\] Nick_(.*)\[(.*)\]: (.*)", find)


Так как наша строка будет читаться из чатлога, время из [16:24:44] и при необходимости Nick_ будут переменны. Поэтому добавляем выражение и для них:​
AutoHotKey:
RegExMatch(var, "\[(\d\d):(\d\d):(\d\d)\] (.*)_(.*)\[(\d\d?\d?)\]: (.*)", find)


Что мы имеет на выходе?
Строка, что будет подходить под параметры нашего Регулярного выражения, будет читаться.
И переменная " find " обретёт содержимое.
Хочу добавить примеры строк, что могут и будут определены:​
[16:24:44] Boll_Name[7]: по чём штаны?​
[08:14:34] Trol_Toga[228]: Стол твёрдый.​
[56:44:24] Sjjj_Oma[12]: Афганистан - это страна!​
[02:54:14] WQaa_Side[82]: Эвропа загнивает?​

Теперь немного о переменной find.
Как вы помните, выражение (.*) позволяет не только пропускать N-слова в строчке под условие,
но и определять их для дальнейшего использования.
В данном выражении у нас есть 7 элементов​
AutoHotKey:
RegExMatch(var, "\[(\d\d):(\d\d):(\d\d)\] (.*)_(.*)\[(\d\d?\d?)\]: (.*)", find)

Для того, чтобы использовать каждый элемент для своих нужд, необходимо слитно с переменной find записать порядковый номер элемента (.*)​
AutoHotKey:
;[16:24:44] Nick_Name[7]: по чём штаны?
;RegExMatch(var, "\[(\d\d):(\d\d):(\d\d)\]\ (.*)_(.*)\[(\d\d?\d?)\]: (.*)", find)
msgbox % find5 ; покажет нам Name
msgbox % find7 ; покажет нам сообщение
msgbox % find6 ; покажет нам ID



Используем наше выражение​



Вот мы и составили наше Регулярное выражение. Теперь вставляем его в пример ниже:​
AutoHotKey:
#Include samp.ahk
#IfWinActive GTA:SA:MP
ChatLog = C:\Users\User\Documents\GTA San Andreas User Files\SAMP\chatlog.txt

loop
{
lastline := GetNewLine(ChatLog)
RegExMatch(var, "\[(\d\d):(\d\d):(\d\d)\] (.*)_(.*)\[(\d\d?\d?)\]: (.*)", find)
If find6 !=
{
   SendChat("команда")
}
}

GetNewLine(filename)
{
static old
static new
if !old
    {
        FileGetSize, old, %filename%
        new := old
    }
while old = new
    {
        sleep 100 ;задержка
        FileGetSize, new, %filename%
    }
old := new
Loop, read, %filename%
if A_LoopReadLine
    {
        last := A_LoopReadLine
    }
return last
}
!end::ExitApp
end::Reload

Если элемент "ID" не будет пуст, в чат будет отправлено сообщение "команда".
Дальше уже можно по своему вкусу изменять данное условие. Приведу лишь пару примеров:​
AutoHotKey:
If find6 !=
{
   SendChat("/mute " find6 " 30 флуд")
}
; Если элемент "ID" не будет пуст, в чат от вас последует команда /mute id 30 флуд, что выдаст мут по данному ID
AutoHotKey:
If find5 !=
    SendChat("Адмирал " find5 " , что вы хотели этим сказать?")
;В чат будет отправлено сообщение: Адмирал Name, что вы хотели этим сказать?
AutoHotKey:
If find7 !=
{
SendChat("Цитирую: " find7)
}
;В чат будет отправлено сообщение: Цитирую: по чём штаны?


На этом тема данной статьи подошла к концу.
Используйте данный пример, составляйте свои "регулярки" и будьте всегда первыми в конкурсе "Решите пример: 557 + 992"​


Немного о функции SendChat
Для отправки сообщения, необходимо его закрыть в "", чтобы получилось так:​
AutoHotKey:
   SendChat("Адмирал")
Чтобы в строке читалась переменная, необходимо закрыть открытую " и вписать имя переменной, не используя %%, так как в этом случае значение переменной будет читаться так же, как переменная.
AutoHotKey:
   SendChat("Адмирал" var)
Немного о функции addChatMessage
addChatMessage позволяет отправлять в чат фэйк-сообщения, которые видите только вы.
Это можно использовать для того, чтобы при запуске скрипта - в чат было отправлено сообщение о запуске, при любом действии, и т.д.​
AutoHotKey:
addChatMessage("Сообщение")
; Самое стандартное сообщение
Чтобы изменить цвет сообщения, необходимо добавить HTML коды цветов:
AutoHotKey:
addChatMessage("{FF8C00} bass_devware")





Подведём итоги

Я не заявляю, что данный гайд самый подробный и при прочтении его вы обязательно научитесь составлять Регулярные выражения любой сложности.
Нет.
Однако нюанс в том, что таких гайдов и не будет.
В конце статьи я оставлю справку по Регулярным выражениям для тех, кому интересно и для тех, кому не понятно до сих пор.


Любые вопросы можете задавать в данной теме и просьба БЛАГОДАРИТЬ тех, кто вам поможет своим ответом.
Светлого будущего и удачи!
Спасибо, что дочитали до конца.








RegEx | RegExMatch | RegExReplace | samp.udf | AutoHotKey
 
Последнее редактирование:

Belo4ka_belka

Известный
191
7
А зачем такие сложности с \Q \E? Можно \[ использовать и тоже будет все воспринято буквально. Ещё совету уточнить что .* означает не просто ВсеЧтоУгодно а и пустоту ибо обычно в голове всплывает наличие чего-либо но никто не додумается что под этот термин попадет и отсутствие.
 

BASS_DEVSOFTWARE

Известный 🇺🇦
Автор темы
Друг
264
567
бесконечные циклы на ахк ммм...
Что мешает сделать это на луа в несколько раз проще? Заштооо
Мешает желание пользователя.
Данная тема демонстрирует альтернативу с использованием autohotkey.

А зачем такие сложности с \Q \E? Можно \[ использовать и тоже будет все воспринято буквально. Ещё совету уточнить что .* означает не просто ВсеЧтоУгодно а и пустоту ибо обычно в голове всплывает наличие чего-либо но никто не додумается что под этот термин попадет и отсутствие.
1. Допишу в виде нюанса. Но для начала лучше использовать через \Q, для лучшего понимания структуры Регулярного выражения.
2. ВсёЧтоУгодно - символ, слово, предложение, включает в себя и ничего.
 

Belo4ka_belka

Известный
191
7
1. Допишу в виде нюанса. Но для начала лучше использовать через \Q, для лучшего понимания структуры Регулярного выражения.
2. ВсёЧтоУгодно - символ, слово, предложение, включает в себя и ничего.
1. Не знаю есть ли смысл понимания структуры если ты в сампике применяешь. Банальный пример это тот самый .* который является самым нерекомендованным шаблоном из всех (ввиду своего значения), но в сампике все легко проходит за счёт пробелов (многие даже ни разу с жадностью не сталкивались потому что пробелы на серверах очень сейвят от этого). Ты же не собираешься html шаблоны разбирать потому \и стоит рассматривать как основной вариант (который даже в html кстати зайдет нормально).
2. Не спорю, только это очень неочевидная вещь. Ты же пишешь статью тем, кто только умеет создавать на форуме "помогите сделать скрипт который удерживает кнопку". Уверен что 90 процентов целевой аудитории твоей статьи даже не смогут определить примерное место возникновения ошибки времени исполнения. Лучше уточнить в общем).
 

EmmanuelCas

Новичок
25
4
Может я тупой, но почему в таком коде, который я составил по твоей интрукции, после того, как в чате появляется 2, то оно начинает флудить, неважно какая функция SendChat, addChatMEssage и т.п, как решить?
AutoHotKey:
ChatLog = %A_ScriptDir%\chatlog.txt

loop
{
lastline := GetNewLine(ChatLog)
RegExMatch(lastline, "\[\(.*):(.*):(.*)\]\ \[\(.*)\]\ (.*) (.*) говорит: (.*)", find)
If find7 != 2
{
   SendChat("/b")
}
}
 
  • Нравится
Реакции: ProstoTakChelik

BASS_DEVSOFTWARE

Известный 🇺🇦
Автор темы
Друг
264
567
Может я тупой, но почему в таком коде, который я составил по твоей интрукции, после того, как в чате появляется 2, то оно начинает флудить, неважно какая функция SendChat, addChatMEssage и т.п, как решить?
AutoHotKey:
ChatLog = %A_ScriptDir%\chatlog.txt

loop
{
lastline := GetNewLine(ChatLog)
RegExMatch(lastline, "\[\(.*):(.*):(.*)\]\ \[\(.*)\]\ (.*) (.*) говорит: (.*)", find)
If find7 != 2
{
   SendChat("/b")
}
}
(.*) - всё что угодно.
Поэтому использовать ПОДРЯД всё что угодно нельзя, нужна точка остановки.

RegExMatch(lastline, "\[(.*):(.*):(.*)\]\ \[(.*)\] (.*) говорит: (.*)", find)

Теперь find6 содержит нужную нам информацию. А ещё, после [ не нужно ставить \. После \ след.символ будет воспринят уже как литеральный. Исключение, если используешь \q \e.
 

EmmanuelCas

Новичок
25
4
(.*) - всё что угодно.
Поэтому использовать ПОДРЯД всё что угодно нельзя, нужна точка остановки.

RegExMatch(lastline, "\[(.*):(.*):(.*)\]\ \[(.*)\] (.*) говорит: (.*)", find)

Теперь find6 содержит нужную нам информацию. А ещё, после [ не нужно ставить \. После \ след.символ будет воспринят уже как литеральный. Исключение, если используешь \q \e.

Поставил ту строку, которую вы предложили, флуд остался и даже начинается при отсутствии 2 в чате
Код остался такой же, как я скидывал, кроме строки с RegExMatch.
А и два (.*) я поставил из-за того, что там идет [timestamp] [ID] Name Surname говорит:
 

EmmanuelCas

Новичок
25
4
Строку покажи.
AutoHotKey:
ChatLog = %A_ScriptDir%\chatlog.txt

loop{
lastline := GetNewLine(ChatLog)

RegExMatch(lastline, "\[(.*):(.*):(.*)\] \[(.*)\] (.*) говорит: (.*)", find)

If find6 != 2{
    SendChat("/b")
}

}

Поставив скопку на одной строке с if я смог фиксануть игнор условия, но флуд все равно есть
 

EmmanuelCas

Новичок
25
4
\[\d\d:\d\d:\d\d\] \[\d\d?\d?\] .*: (.*)
Если там где ID цифры, то регулярка определит так как нужно.

find1 - текст.
Регулярка то определяет нормально текст, но флуд все равно остался, то есть, в моем случае, при нахождении цифры 2 оно начинает флудить SendChat("/b") до тех пор пока не крашнет/не оффну скрипт
 

EmmanuelCas

Новичок
25
4
Я малость не понял, нужно чтобы при нахождении цифры писало в чат? Убери ! перед = в условии.
Та емае, вот регулярка нашла нужный текст и все, начинается флуд, а мне надо, что бы 1 раз отправило и все, код юзаю тот, что я скинул выше
 

BASS_DEVSOFTWARE

Известный 🇺🇦
Автор темы
Друг
264
567
Та емае, вот регулярка нашла нужный текст и все, начинается флуд, а мне надо, что бы 1 раз отправило и все, код юзаю тот, что я скинул выше
AutoHotKey:
ChatLog = %A_ScriptDir%\chatlog.txt

loop
{
lastline := GetNewLine(ChatLog)

RegExMatch(lastline, "\[\d\d:\d\d:\d\d\] \[\d\d?\d?\] .*: (.*)", find)

if find1 =
continue

If find1 = 2
{
    SendChat("/b")
}

}
 
  • Нравится
Реакции: EmmanuelCas