Что нового

[Данные, строки] Реализовать необычный счётчик

ynbIpb

Скриптер
Сообщения
399
Репутация
109
Здравствуйте.
Возникла такая задача: Есть некая строка, которая может состоять из цифр и букв. Необходимо к ней прибавлять + 1 как будто это строка с цифрами.
Например была она 123abc, сделали +1 и стала 123abd и т.д. Прошли весь набор символов, сдвигаем соседний символ 123ac0 и снова перебираем 123ac1...
Никак не придумаю как это реализовать.
Код:
$iCounter = 1 ;счётчик
$sCharacterString = "123abc" ; исходная строка
$aSymbols = StringSplit ("0123456789abcdefghijklmnopqrstuvwxyz", ""); массив из допустимых символов

While 1 ; бесконечный цикл
	;$sCharacterString += 1
	$sCharacterString = "123ab"&$aSymbols[13+1] ; 123abd
	$sCharacterString = "123abe"
	$sCharacterString = "123abf"
	;....
	$sCharacterString = "123a"&$aSymbols[13]&$aSymbols[1] ; 123ac0
	$sCharacterString = "123ac1"
	;....
	$iCounter += 1 ; каждый проход добавляем + 1
	TrayTip ("", "Текущий круг: "&$iCounter &@CRLF& "Текущее значение строки: "&$sCharacterString, 3)
	Sleep (1000)
WEnd
 

Torotin

Новичок
Сообщения
10
Репутация
2
Доброго дня.
Как вариант - можно через регулярное выражение читать последний символ строки -> перевести в номер символа ascii -> прибавить единицу-> перевести обратно в символ.

Код:
; ascii table
; https://www.autoitscript.com/autoit3/docs/appendix/ascii.htm

$string = "0" ; строка
$startSybm = 0; символ начала отсчета
$endSybm = "z"; символ конца отсчета. после чего добавляется символ начала в конец строки


; 0 - 9
; asc = 48 - 57 

; A - Z
; asc = 65 - 90

; a  - z
; asc = 97 - 122

For $i = 1 to 100
;~ 	ConsoleWrite($i)
	ConsoleWrite(@CRLF & @CRLF)
	ConsoleWrite('Строка на входе в цикл: "'&$String & '"' &  @CRLF)
	ConsoleWrite(@CRLF & @CRLF)
	
	$aString = StringRegExp($string, ".*(.)", 3) 						;поиск последнего символа строки
 	$sString = $aString[0]
	ConsoleWrite("Последний символ строки: " & $sString & @CRLF)

	If $sString = $endSybm Then 										;условие добавление нового символа в конец строки
		ConsoleWrite("Добавляем к строке символ старта" & @CRLF)		
		$string &= $startSybm
		ConsoleWrite("Новое содержимое строки: "& $string & @CRLF)
		$aString = StringRegExp($string, ".*(.)", 3)
		$sString = $aString[0]
		ConsoleWrite("Новый последний символ строки: " & $sString & @CRLF)
	EndIf

	$AscCode = Asc($sString) 											;вычисление кода ascii последнего символа строки
;~ 	ConsoleWrite($AscCode & @CRLF)
	$CheckAcsCode = _SymbCheck($AscCode)								
;~ 	ConsoleWrite($CheckAcsCode & @CRLF)
;~ 	ConsoleWrite(Chr($CheckAcsCode) & @CRLF)
	$NewAscCode	= $CheckAcsCode+1
	
	if StringLen($string) = 1 Then 										;провеврка на длину строки
		$string = Chr($NewAscCode)	; условие выполнения в случае 1-символьной строки
	Else 
		$string = StringRegExpReplace($string, "(.*)(.)", "${1}"&Chr($NewAscCode), 0) ;в случае строки более 1 символа
	EndIf
	
;~ 	ConsoleWrite($NewAscCode & @CRLF)
;~ 	ConsoleWrite(Chr($NewAscCode) & @CRLF)
Next

Func _SymbCheck($CheckData) ; функция проверки допустимого диапазаона последнего сивмвола строки по коду scii table
	Local $newData = $CheckData
	ConsoleWrite("ASCII-код символа на входе в функцию   _SymbCheck: " & $newData & @CRLF)
	If $CheckData > 57 And $CheckData < 65 Then $newData = 65
	If $CheckData > 90 And $CheckData < 97 Then $newData = 97
	ConsoleWrite("ASCII-код символа на выходе из функции _SymbCheck: " & $newData & @CRLF)
	Return $newData
EndFunc
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
109
Благодарю за идею. Не задумывался про то, что ascii коды идут по порядку.
Пытаюсь понять механизм, откуда-то лезет символ двоеточия вместо заглавной буквы A. И если начальная строка $string = "0" больше 1-го символа, то они не учитываются.
Буду думать как подогнать эту идею под себя.

Возможно кто-то ещё подкинет альтернативные решения.
 

ra4o

AutoIT Гуру
Сообщения
1 101
Репутация
223
Если к 123zzz прибавить 1 должно быть 124000 ?
Пересчитать последний символ строки в ascii, добавить 1 и перевести в символ не проблема, как быть в случае переполнения , те нужно уже 1 добавлять к старшему разряду , а младший начинать с начала.
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
109
Да, именно так. Старший разряд должен меняться, младший начинаться сначала.

Вот как-то так мне это видится, но как правильно обрабатывать старшие разряды не придумаю. Столько костылей получится.
Код:
$iCounter = 1 ;счётчик
$sCharacterString = "123abc" ; исходная строка
$aSymbols = StringSplit ($sCharacterString, ""); массив из исходной строки, разбитый по символам
$sCurAsciiStr = "" ; текущая строка преобразованная в ASCII код

While 1 ; бесконечный цикл
	$sCurAsciiSymb = Asc ($aSymbols[$aSymbols[0]]); получаем код последнего символа
	If $sCurAsciiSymb >= 48 And $sCurAsciiSymb <= 56 Then ; проверка входил ли код в диапазаон от 0 до 8
		$sCurAsciiSymb += 1
		$aSymbols[$aSymbols[0]] = Chr ($sCurAsciiSymb); записывает новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb = 57 Then ; проверка является ли код символом "9"
		$aSymbols[$aSymbols[0]] = Chr (97); перескакиваем к букве "a" и записываем новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb >= 97 And $sCurAsciiSymb <= 121 Then ; проверка входил ли код в диапазаон от a до y
		$sCurAsciiSymb += 1
		$aSymbols[$aSymbols[0]] = Chr ($sCurAsciiSymb); записывает новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb = 122 Then ; проверка является ли код последним символом z
		$aSymbols[$aSymbols[0]] = Chr (48); обнуляем последний символ в массиве
		$aSymbols[$aSymbols[0]-1] = Chr (Asc ($aSymbols[$aSymbols[0]-1])+1); делаем +1 в старшем разряде
	EndIf
	For $i=1 To $aSymbols[0]; формируем новую строку из массива
		$sCurAsciiStr &= $aSymbols[$i]
	Next

	$iCounter += 1 ; каждый проход добавляем + 1
	;TrayTip ("", "Текущий круг: "&$iCounter &@CRLF& "Текущее значение строки: "&$sCurAsciiStr, 3)
	ConsoleWrite ("Текущее значение строки:  ["&$sCurAsciiStr&"]  Текущий круг: "&$iCounter&@CRLF)
	Sleep (500)
	$sCurAsciiStr = "" ;обнуляем переменную
WEnd
 

Torotin

Новичок
Сообщения
10
Репутация
2
ynbIpb сказал(а):
Да, именно так. Старший разряд должен меняться, младший начинаться сначала.

Вот как-то так мне это видится, но как правильно обрабатывать старшие разряды не придумаю. Столько костылей получится.
Код:
$iCounter = 1 ;счётчик
$sCharacterString = "123abc" ; исходная строка
$aSymbols = StringSplit ($sCharacterString, ""); массив из исходной строки, разбитый по символам
$sCurAsciiStr = "" ; текущая строка преобразованная в ASCII код

While 1 ; бесконечный цикл
	$sCurAsciiSymb = Asc ($aSymbols[$aSymbols[0]]); получаем код последнего символа
	If $sCurAsciiSymb >= 48 And $sCurAsciiSymb <= 56 Then ; проверка входил ли код в диапазаон от 0 до 8
		$sCurAsciiSymb += 1
		$aSymbols[$aSymbols[0]] = Chr ($sCurAsciiSymb); записывает новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb = 57 Then ; проверка является ли код символом "9"
		$aSymbols[$aSymbols[0]] = Chr (97); перескакиваем к букве "a" и записываем новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb >= 97 And $sCurAsciiSymb <= 121 Then ; проверка входил ли код в диапазаон от a до y
		$sCurAsciiSymb += 1
		$aSymbols[$aSymbols[0]] = Chr ($sCurAsciiSymb); записывает новый символ в массив
		$sCurAsciiSymb = "" ; обнуляем текущий символ
	EndIf
	If $sCurAsciiSymb = 122 Then ; проверка является ли код последним символом z
		$aSymbols[$aSymbols[0]] = Chr (48); обнуляем последний символ в массиве
		$aSymbols[$aSymbols[0]-1] = Chr (Asc ($aSymbols[$aSymbols[0]-1])+1); делаем +1 в старшем разряде
	EndIf
	For $i=1 To $aSymbols[0]; формируем новую строку из массива
		$sCurAsciiStr &= $aSymbols[$i]
	Next

	$iCounter += 1 ; каждый проход добавляем + 1
	;TrayTip ("", "Текущий круг: "&$iCounter &@CRLF& "Текущее значение строки: "&$sCurAsciiStr, 3)
	ConsoleWrite ("Текущее значение строки:  ["&$sCurAsciiStr&"]  Текущий круг: "&$iCounter&@CRLF)
	Sleep (500)
	$sCurAsciiStr = "" ;обнуляем переменную
WEnd
Интересно получается. Но очень костыльно.
Вчера набросал под Вашу задачку набросал код на основе того, что выложил постом выше. Сегодня небыло возможности дома до компа дойти чтоб доработать код...
Как мне кажется в текущей задаче лучше идти через написание дополнительных универсальных функций обработки строки для применения замен символов.

Главный вопрос к вводной задачи: сама строка ограничена количеством символов по длине?

Реализация счётчика "горит" по срокам?

Отправлено с моего SM-N950F через Tapatalk
 

ra4o

AutoIT Гуру
Сообщения
1 101
Репутация
223
Вот мой вариант , смысл такой - переводим число из тридцатишестиричного в десятичное, прибавляем единицу, затем обратно.
Код:
$iCounter = 0 ;счётчик
$sCharacterString = "123abc" ; исходная строка
$aSymbols = StringSplit("0123456789abcdefghijklmnopqrstuvwxyz", "", 2) ; массив из допустимых символов

While 1 ; бесконечный цикл
	$sCharacterString = _IntTo36(_36ToInt($sCharacterString) + 1)
	$iCounter += 1 ; каждый проход добавляем + 1
	ConsoleWrite("Текущий круг: " & $iCounter & @CRLF & "Текущее значение строки: " & $sCharacterString&@CR&@CR)
     ;TrayTip("", "Текущий круг: " & $iCounter & @CRLF & "Текущее значение строки: " & $sCharacterString, 3)
	Sleep(1000)
WEnd

Func _IntTo36($Value)
	$Result = ''
	$Res = ''
	While $Value > 36
		$Res &= $aSymbols[$Value - Int($Value / 36) * 36]
		$Value = Int($Value / 36)
	WEnd
	$Res &= $aSymbols[$Value]

	$SplitRes = StringSplit($Res, '', 2)
	For $i = UBound($SplitRes) - 1 To 0 Step -1
		$Result &= $SplitRes[$i]
	Next

	Return $Result
EndFunc   ;==>_IntTo36

Func _36ToInt($Value)
	$aVal = StringSplit($Value, '', 2)
	$MaxIndex = UBound($aVal) - 1
	$Result = 0
	For $i = 0 To $MaxIndex
		$Result += _Dig($aVal[$i]) * 36 ^ ($MaxIndex - $i)
	Next
	Return $Result
EndFunc   ;==>_36ToInt

Func _Dig($X)
	For $i = 0 To UBound($aSymbols) - 1
		If $aSymbols[$i] = $X Then Return $i
	Next
EndFunc   ;==>_Dig
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
109
Torotin [?]
Главный вопрос к вводной задачи: сама строка ограничена количеством символов по длине?Реализация счётчика "горит" по срокам?
Стока может начинаться и с 1-го символа, а может и сразу с 4-х. Длинна может увеличиться, если все старшие разряды достигнут "z".
Нет, конечно не горит. Это обычная самоделка для себя.

ra4o [?]
Вот мой вариант
Отличная идея! Выдумать свою систему счислений)
В пределах своего количества символов отлично прибавляет. На zzzzzz падает.
 

ra4o

AutoIT Гуру
Сообщения
1 101
Репутация
223
У меня нормально работает и дальше . Измените строку в функции "_IntTo36" на
Код:
While $Value > 35

Пробовал, максимальное число, после которого падает - это "zzzzzzzzzu" (у меня система 64 битная).
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
109
Да, больше 10 символов "z" не переваривает. Видимо упираемся в какое-то ограничение языка.
В общем благодаря идее о 36-ричной системе счисления я пришёл к такому результату:
Код:
$iCounter = 1 ;счётчик
$sCharacterString = "123adc" ; исходная строка

While 1 ; бесконечный цикл
	ConsoleWrite ("Текущее значение строки:  ["&$sCharacterString&"]  Текущий круг: "&$iCounter&@CRLF) ; Выводим результат
	$result = _BaseToBase($sCharacterString, 36, 10) + 1; преобразуем из 36-ричной в десятичную и добавляем +1
	$sCharacterString = _BaseToBase($result, 10, 36); преобразуем из десятичной в 36-ричную
	$iCounter += 1 ; каждый проход добавляем + 1
	Sleep (300)
WEnd

Func _BaseToBase($sIn, $iBaseIn, $iBaseOut)
    Local $sOut = 0
    If $iBaseIn <> 10 Then ; iBaseIn to decimal
        $aVal = StringSplit(StringUpper ($sIn), ""); разбиваем строку на массив, предварительно переводим в верхний регистр
        For $x = 1 to $aVal[0]
         $iDec = Asc($aVal[$x]) - (48 + ($aVal[$x] > "9") * 7)
            $sOut += $iDec * ($iBaseIn ^ ($aVal[0] - $x))
        Next
        $sIn = $sOut
    EndIf
    If $iBaseOut <> 10 Then ; decimal to iBaseOut
        $sOut = ""
        While $sIn >= 1
            $x = Mod($sIn, $iBaseOut)
            $sOut = Chr($x + 48 + ($x > 9) * 7) & $sOut
            $sIn = ($sIn - $x) / $iBaseOut
        WEnd
    EndIf
    Return StringLower ($sOut); возвращаем строку в нижнем регистре
EndFunc

Функцию нашёл тут
Большое спасибо всем!
 
Верх