Redline
AutoIT Гуру
- Сообщения
- 506
- Репутация
- 375
AutoIt: 3.3.0
Версия: 1.0
Категория: Разное
Описание: Утилита для перебора символов из входной строки с задаваемой длиной выходных слов. Есть возможность удалять повторяющиеся символы из входной строки и словах на выходе. Полученные слова могут сохраняться напрямую файл(рекомендуется если комбинаций больше нескольких миллионов, иначе выдача в GUI занимает много времени). Прерывание работы скрипта при переборе - Ctrl-F9.
Код:
Снимок:
Автор: Redline
Версия: 1.0
Категория: Разное
Описание: Утилита для перебора символов из входной строки с задаваемой длиной выходных слов. Есть возможность удалять повторяющиеся символы из входной строки и словах на выходе. Полученные слова могут сохраняться напрямую файл(рекомендуется если комбинаций больше нескольких миллионов, иначе выдача в GUI занимает много времени). Прерывание работы скрипта при переборе - Ctrl-F9.
Код:
Код:
#include <EditConstants.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <StaticConstants.au3>
#include <ProgressConstants.au3>
Global $sCombinations, $iMaxLength, $iMinLength, $fNoMix, $fIgnore, $sWord, $fStop, $iTotal
Global $iCount, $iSimbols, $aS, $sOut, $hFile = @ScriptDir & '\dumb.txt', $hFileWr
$hGUI = GUICreate('Великий комбинатор', 480, 680)
GUICtrlCreateLabel('Введите символы:', 5, 5, 120, 21)
$hLabelCombs = GUICtrlCreateLabel('Количество возможных комбинаций - ', 150, 5, 300, 21)
$hInput = GUICtrlCreateInput('', 5, 25, 470, 17, -1, $WS_EX_STATICEDGE)
GUICtrlCreateLabel('Мин. длина слова:', 5, 50, 110, 21)
$hComboMin = GUICtrlCreateCombo('2', 120, 45, 40, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST))
GUICtrlSetData(-1, '3|4|5|6|7|8|9|10', '2')
GUICtrlCreateLabel('Макс. длина слова:', 5, 70, 110, 21)
$hComboMax = GUICtrlCreateCombo('2', 120, 65, 40, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST))
GUICtrlSetData(-1, '3|4|5|6|7|8|9|10', '3')
$hCheckUniq = GUICtrlCreateCheckbox('Повторять символы в словах на выходе', 170, 45, 300, 20)
GUICtrlSetState(-1, $GUI_CHECKED)
$hCheckTrim = GUICtrlCreateCheckbox('Игнорировать одинаковые символы входной строки', 170, 65, 300, 20)
GUICtrlSetState(-1, $GUI_CHECKED)
GUICtrlCreateLabel('Вывод результата:', 5, 90, 110, 21)
$hComboOutput = GUICtrlCreateCombo('Только в окно программы', 120, 85, 200, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST))
GUICtrlSetData(-1, 'Только в файл|В окно программы и в файл', 'Только в окно программы')
$hFileOutput = GUICtrlCreateLabel(@ScriptDir & '\out.txt', 5, 110, 470, 17, -1, $WS_EX_STATICEDGE)
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateLabel('Слова:', 5, 130, 100, 21)
$hOutput = GUICtrlCreateEdit('', 5, 150, 470, 490, $ES_READONLY + $WS_VSCROLL, $WS_EX_STATICEDGE)
$hProgress = GUICtrlCreateProgress(5, 650, 360, 20, $PBS_SMOOTH)
$hStart = GUICtrlCreateButton('Генерировать', 375, 645, 100, 30, $BS_DEFPUSHBUTTON + $BS_FLAT)
GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')
While 1
$msg = GUIGetMsg()
Select
Case $msg = -3
Exit
Case $msg = $hComboOutput
If StringInStr(GUICtrlRead($hComboOutput), 'файл') Then
GUICtrlSetState($hFileOutput, $GUI_ENABLE)
GUICtrlSetData($hOutput, 'Кликните по ссылке к файлу, чтобы изменить путь')
Else
GUICtrlSetState($hFileOutput, $GUI_DISABLE)
EndIf
Case $msg = $hFileOutput
$sFileOut = FileSaveDialog('Выберите выходной файл:', @ScriptDir, 'Text (*.txt)', 16, 'out.txt')
If $sFileOut = '' Then
GUICtrlSetData($hFileOutput, @ScriptDir & '\out.txt')
Else
GUICtrlSetData($hFileOutput, $sFileOut)
EndIf
Case $msg = $hStart
GUISetState(@SW_DISABLE)
If GUICtrlRead($hInput) = '' Or StringLen(GUICtrlRead($hInput)) = 1 Then
MsgBox(0, 'Ошибка', 'Количество введенных символов слишком мало')
Else
GUICtrlSetData($hOutput, '')
$sCombinations = GUICtrlRead($hInput)
$iMinLength = Number(GUICtrlRead($hComboMin))
$iMaxLength = Number(GUICtrlRead($hComboMax))
If $iMinLength > $iMaxLength Then
MsgBox(0, 'Ошибка', 'Минимум не может превышать максимум')
Else
If GUICtrlRead($hCheckUniq) = $GUI_CHECKED Then
$fNoMix = False
Else
$fNoMix = True
EndIf
If GUICtrlRead($hCheckTrim) = $GUI_CHECKED Then
$fIgnore = True
Else
$fIgnore = False
EndIf
WinSetTitle($hGUI, '', 'Великий комбинатор - [ нажмите Ctrl-F9 для отмены ]')
$fStop = False
HotKeySet('^{F9}', '_Terminate')
GUICtrlSetData($hOutput, 'Обработка...')
_generate($sCombinations, $iMinLength, $iMaxLength, $fNoMix, $fIgnore)
If @error = 1 Then
MsgBox(0, 'Ошибка', 'Введенных символов недостаточно' & @CRLF & 'отмените опцию <Повторять символы в словах> и запустите снова')
GUICtrlSetData($hOutput, '')
EndIf
WinSetTitle($hGUI, '', 'Великий комбинатор')
HotKeySet('^{F9}')
EndIf
EndIf
GUISetState(@SW_ENABLE)
GUICtrlSetState($hInput, $GUI_FOCUS)
GUICtrlSetData($hProgress, 0)
EndSelect
WEnd
Func _generate($sAlphabet, $iLengthMin, $iLengthMax, $fMx, $fIgn)
If $fIgn Then ; перевод алфавита в массив
$sAlphabet_new = ''
For $m = 1 To StringLen($sAlphabet) ; удаление повторяющихся символов, если выбрана данная опция
$sChar = StringMid($sAlphabet, $m, 1)
If Not StringInStr($sAlphabet_new, $sChar) Then $sAlphabet_new &= $sChar
Next
$aS = StringSplit($sAlphabet_new, '')
Else
$aS = StringSplit($sAlphabet, '')
EndIf
Global $iSimbols = UBound($aS) - 1 ; длина алфавита
$iTotal = _countofcombs($iSimbols, $iLengthMin, $iLengthMax, Not $fMx) ; общее количество комбинаций
If $iTotal <= 0 Then ; проверка соответствия длины алфавита к ограничителям длины слова
Return SetError(1)
EndIf
If $iTotal > 50000 Then
If FileExists($hFile) Then FileDelete($hFile) ; очистка файла под временное хранение данных
Global $hFileWr = FileOpen($hFile, 1) ; открытие файла на запись с допиской в конец файла
EndIf
Global $iMinLength = $iLengthMin ; минимальная длина слова
Global $iMaxLength = $iLengthMax ; максимальная длина слова
Global $fNoMix = $fMx ; флаг уникальности всех символов в слове
Global $sOut = '' ; выходной текст
For $z = 1 To $iSimbols ; цикл перебора алфавита
GUICtrlSetData($hProgress, Round(100 * ($z / $iSimbols), 0))
_solid($aS[$z])
If @error = 1 Then ExitLoop
$iMaxLength = $iLengthMax ; сброс счетчика максимальной длины слова
Next
If $iTotal > 50000 Then
GUICtrlSetData($hOutput, 'Выдача результата...')
FileWrite($hFileWr, $sOut) ; запись последней порции слов в файл
FileClose($hFileWr)
If StringInStr(GUICtrlRead($hComboOutput), 'файл') Then FileCopy($hFile, GUICtrlRead($hFileOutput), 9) ; заносим все слова в файл
If StringInStr(GUICtrlRead($hComboOutput), 'окно') Then
GUICtrlSetData($hOutput, FileRead($hFile)) ; заносим все слова в Edit
Else
GUICtrlSetData($hOutput, 'Данные успешно записаны в файл:' & @CRLF & GUICtrlRead($hFileOutput)) ; заносим все слова в Edit
EndIf
FileClose($hFile)
FileDelete($hFile)
Else
GUICtrlSetData($hOutput, 'Выдача результата...')
If StringInStr(GUICtrlRead($hComboOutput), 'файл') Then
$hFileOpen = FileOpen(GUICtrlRead($hFileOutput), 2)
FileWrite($hFileOpen, $sOut) ; заносим все слова в файл
FileClose($hFileOpen)
EndIf
If StringInStr(GUICtrlRead($hComboOutput), 'окно') Then
GUICtrlSetData($hOutput, $sOut) ; заносим все слова в Edit
Else
GUICtrlSetData($hOutput, 'Данные успешно записаны в файл:' & @CRLF & GUICtrlRead($hFileOutput)) ; заносим все слова в Edit
EndIf
EndIf
EndFunc ;==>_generate
Func _solid($sIn) ; рекурсивная функция перебора символов алфавита с занесением полученных в текст
If $fStop Then Return SetError(1)
If $iMaxLength = 1 Then ; достигнута максимальная длина слова
Return
ElseIf StringLen($sOut) > 100000 And $iTotal > 50000 Then ; если объем текста превышает 100К символов, то заносим его в файл(экономия ресурсов памяти)
FileWrite($hFileWr, $sOut)
$sOut = ''
Else
$iMaxLength -= 1 ; длина слова в следующем цикле увеличивается, соответсвенно уменьшаем счетчик
For $i = 1 To $iSimbols
$sWord = $sIn & $aS[$i] ; дописываем символ к уже существующей строке
If StringLen($sWord) >= $iMinLength Then ; если длина слова удовлетворяет минимальной длине...
If $fNoMix And Not StringRegExp($sWord, '(.).*\1', 0) Then ; если включена проверка на уникальность символов в слове и проверка пройдена
$sOut &= $sWord & @CRLF ; заносим полученное слово в текст
_solid($sWord) ; рекурсия
ElseIf Not $fNoMix Then ; проверка на уникальность выключена
$sOut &= $sWord & @CRLF
_solid($sWord) ; рекурсия
EndIf
Else ; если длина слова меньше минимальной, то сразу идем глубже
If $fNoMix And Not StringRegExp($sWord, '(.).*\1', 0) Then ; если включена проверка на уникальность символов в слове и проверка пройдена
_solid($sWord) ; рекурсия
ElseIf Not $fNoMix Then ; проверка на уникальность выключена
_solid($sWord) ; рекурсия
EndIf
EndIf
Next
$iMaxLength += 1 ; после перебора всех символов алфавита плюсуем максимальную длину слова, иначе не будет вызвана следующая рекурсия,
; для предыдущего более короткого слова, как-то так =))))
EndIf
EndFunc ;==>_solid
Func WM_COMMAND($hWnd, $nMsg, $wParam, $lParam)
Local $nNotifyCode = BitShift($wParam, 16)
Local $nID = BitAND($wParam, 0xFFFF)
Local $hCtrl = $lParam
Switch $nID
Case $hInput, $hComboMin, $hComboMax, $hCheckUniq ; были внесены изменения в данных элементах
Switch $nNotifyCode
Case $EN_UPDATE, $CBN_SELCHANGE, $BN_CLICKED ; сообщения: обновление для InputBox, выбор элемента для ComboBox, клик по CheckBox
If GUICtrlRead($hCheckUniq) = $GUI_CHECKED Then
$fUn = True
Else
$fUn = False
EndIf
If GUICtrlRead($hCheckTrim) = $GUI_CHECKED Then
$sInp_old = GUICtrlRead($hInput)
$sInp_new = ''
For $d = 1 To StringLen($sInp_old)
$sChar = StringMid($sInp_old, $d, 1)
If Not StringInStr($sInp_new, $sChar, 1) Then $sInp_new &= $sChar
Next
Else
$sInp_new = GUICtrlRead($hInput)
EndIf
$iInp_new = StringLen($sInp_new)
$iMinimum = GUICtrlRead($hComboMin)
$iMaximum = GUICtrlRead($hComboMax)
$iResult = _countofcombs($iInp_new, $iMinimum, $iMaximum, $fUn)
GUICtrlSetData($hLabelCombs, 'Количество возможных комбинаций - ' & StringRegExpReplace($iResult, '(\d)(?=(\d{3})+$)', '$1 '))
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_COMMAND
Func _countofcombs($iInp, $iMin, $iMax, $fUniq) ; немного комбинаторики
If $fUniq Then ; на выходе строки без повторяющихся символов
$iCombs = 0
For $y = $iMin To $iMax
$iCombs += $iInp ^ $y
Next
Return $iCombs ; NumCombs = n^k + n^(k-1) + n^(k-2) + ...
Else ; все строки
$iCombs = 0
$iFactor_max = 1
For $h = 2 To $iInp
$iFactor_max *= $h
Next
For $y = $iMin To $iMax
If $iInp >= $y Then
$iFactor_next = 1
For $f = 1 To ($iInp - $y)
$iFactor_next *= $f
Next
$iCombs += $iFactor_max / $iFactor_next
EndIf
Next
Return $iCombs ; NumComb = n!/(n-k)! + n!/(n-(k-1))! + n!/(n-(k-2))! + ...
EndIf
EndFunc ;==>_countofcombs
Func _terminate()
$fStop = True
GUICtrlSetData($hOutput, 'Обработка прервана пользователем!!' & @CRLF)
EndFunc ;==>_terminate
Снимок:
Автор: Redline