Что нового

Удаление повторяющихся строк в постоянно дозаписывающемся файле при определённом условии.

Maria

Новичок
Сообщения
29
Репутация
0
Добрый день. Очень нужна ваша помощь

Сторонняя программа записывает в текстовой файл текст примерно следующего содержания (Файл прикрепил)
Пример
Номер товара "цена"цена"цена"цена"цена"

3836262312"32.98"32.99"33.00"34.00"34.90"34.90"34.90"34.90"35.00"36.69"37.04"
3658235837"59.90"59.90"59.90"59.90"60.65"66.86"77.54"
3667111746"31.39"31.99"32.00"34.90"34.90"34.90"34.90"34.90"

Нужно, что бы при запуске этот скрипт открывал файл, считывал строку в массив (где разделитель это знак " ) Где $Array[0] - это номер и [1]..[4]... это цены. Количество цен в строках может быть разным.
И при каждом добавлении новой строки, скрипт начинал считывать с первой строчки номер, искать его в последующих строках и удалять их (полностью всю строку). И так каждый раз с первой строки до последней - новой. Разумеется номер из 100 - ой строки не должен искаться выше, а только со 101-ой и до конца.
Я понимаю, что это "энергозатратный" вариант, так как файл может доходить до 200 тыс. строк. Но мне что то ничего другого в голову не приходит.

Во второй части скрипта нужно, что бы скрипт считывал каждую новую строчку в массив при каждом добавлении и сравнивал цены (но только новые, он не должен проходить все строки, как при первом задании) с лево на право в процентом соотношении следующим образом.
Пример
"32.98"32.99"33.00"34.00"34.90"

[1]Array < [2 ]Array на 30 процентов or [2]Array < [3 ] на 30 процентов итд и так до последней переменной, которую уже ни с чем нельзя сравнить.
если условия выполняются то Msgboxс номером и теми ценами, которые показали между собой разницу в 30 процентов.

Иногда бывает так, что в ценах могут быть буквы, из-за чего может произойти ошибка, поэтому, если переменная не является числом, то её нужно пропустить.
Пример
тут номер 2 мы сравниваем с номером 4, а номер 4 с номером 5. Номер 3 пропускаем.
[1]Array = 20.35< [2 ]Array=30.48 [3]Array =20Х < [4 ]Array=[5]Array =40.20 < [6 ]Array=60

Я понимаю, что указал много условий и задач в одной теме, но именно в таком варианте всё это имеет смысл.
Буду очень ждать Вашей помощи.
 

Вложения

  • filename.txt
    930 байт · Просмотры: 7

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Нужно, что бы при запуске этот скрипт открывал файл, считывал строку в массив
Какую?
Всё очень сумбурно.
при каждом добавлении новой строки, скрипт начинал считывать с первой строчки номер
Разумеется номер из 100 - ой строки не должен искаться выше, а только со 101-ой и до конца.
Вы понимаете что здесь противоречие?

Разложите задачу по пунктам.
 
Автор
M

Maria

Новичок
Сообщения
29
Репутация
0
Что ожидается на выходе после обработки скриптом?
Здравствуйте. Что то я действительно перемудрил, извиняюсь. Я смог решить проблему для которого нужно было удаление строк.
Если у Вам не сложно, помогите пожалуйста с решение второй части.
В этом случае на выходе мне нужен будет только .
Сообщение автоматически объединено:

Здравствуйте. Что то я действительно перемудрил, извиняюсь. Я смог решить проблему для которого нужно было удаление строк.
Если у Вам не сложно, помогите пожалуйста с решение второй части.
В этом случае на выходе мне нужен будет только Msbox .
Сообщение автоматически объединено:

Только MsgBox

Извиняюсь, не нашёл, как можно редактировать сообщения.
 
Автор
M

Maria

Новичок
Сообщения
29
Репутация
0
Как определять где новая строчка?

В приведённом примере это не так.
Нужно ровно на 30%?
Задача упростилась.

Есть просто файл, он уже готов и не дозаписывается.
Скрипт должен считать по строкам его и выполнить условия, которые я указал во второй части, в самом первом сообщении.
Пример условный, я буду в последствии менять параметры, а пока пусть будет < 30%

"В приведённом примере это не так." Что вы имеете ввиду.?

Я хотел толь лишь показать конструкцию.
Код:
if
[1]Array <  на 30 процентов [2 ]Array  or [2]Array < на 30 процентов [3 ]Array ...  и так до последней переменной в массиве
then
 msgbox.
endif

Сообщение автоматически объединено:

Но лучше конечно сделать считывание с каждой новой строчки в файле, который дозаписывается.

Вот что то вроде такого
Определять изменение и брать последнюю строку в файле.

Код:
While 1
        $sFile1Size = FileGetSize($sFile1)
        Select
            Case $sFile1SizePrev < $sFile1Size
                $sFile1SizePrev = $sFile1Size
            Case $sFile1SizePrev > $sFile1Size
                $sFile1SizePrev = 0
                _FilesOpen_Reads(0)
        EndSelect
 
Последнее редактирование:

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Короче вот пример, при первом запуске считает строки файла (filename.txt в папке скрипта), далее если хоть одна строка будет изменена или добавлена, скрипт проверит её цены на предмет разницы в процентах (30 или выше), и если найдёт разницу то выведет результат в MsgBox.

Код:
HotKeySet('{ESC}', _Exit)
AdlibRegister('_CheckLines', 100)

While 1
    Sleep(100)
WEnd

Func _CheckLines()
    Local $sFile = @ScriptDir & '\filename.txt'
    
    If Not FileExists($sFile) Then
        Return
    EndIf
    
    Local Static $aLast_Lines = -1
    Local $aLines = FileReadToArray($sFile)
    
    If $aLast_Lines = -1 Then
        $aLast_Lines = $aLines
        Return
    EndIf
    
    Local $iFound = 0, $sNewLine = ''
    
    For $i = 0 To UBound($aLines) - 1
        If $aLines[$i] = '' Then
            ContinueLoop
        EndIf
        
        $iFound = 0
        
        For $j = 0 To UBound($aLast_Lines) - 1
            If $aLast_Lines[$j] = '' Then
                ContinueLoop
            EndIf
            
            If $aLines[$i] = $aLast_Lines[$j] Then
                $iFound = 1
                ExitLoop
            EndIf
        Next
        
        If Not $iFound Then
            $sNewLine = $aLines[$i]
            ExitLoop
        EndIf
    Next
    
    $aLast_Lines = $aLines
    
    If $sNewLine Then
        Local $aSplit = StringRegExp($sNewLine, '"?([\d\.]+)"', 3)
        Local $iUbnd = UBound($aSplit)
        Local $sDiff = ''
        
        For $i = 1 To $iUbnd - 1
            If $i + 1 < $iUbnd Then
                $iPrcntDiff = _NumPrecentDiff($aSplit[$i], $aSplit[$i + 1])
                
                If $iPrcntDiff >= 30 Or $iPrcntDiff <= -30 Then
                    $sDiff &= ($sDiff ? @CRLF : '') & $aSplit[$i] & ' ' & ($iPrcntDiff >= 30 ? '<' : '>') & ' ' & $aSplit[$i + 1] & ' (' & $iPrcntDiff & ' %)'
                EndIf
            EndIf
        Next
        
        If $sDiff Then
            MsgBox(64, @ScriptName, $aSplit[0] & @CRLF & $sDiff)
        EndIf
    EndIf
EndFunc

Func _NumPrecentDiff($iNum1, $iNum2)
    If $iNum1 > $iNum2 Then
        Return -Round((($iNum1 - $iNum2) / $iNum2) * 100, 2)
    ElseIf $iNum2 > $iNum1 Then
        Return Round((($iNum2 - $iNum1) / $iNum1) * 100, 2)
    EndIf
    
    Return 0
EndFunc

Func _Exit()
    Exit
EndFunc
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Определять изменение и брать последнюю строку в файле.
Тогда тот же вариант но попроще:
Код:
HotKeySet('{ESC}', _Exit)
AdlibRegister('_CheckLines', 1000)

While 1
    Sleep(100)
WEnd

Func _CheckLines()
    Local $sFile = @ScriptDir & '\filename.txt'
    
    If Not FileExists($sFile) Then
        Return
    EndIf
    
    Local $iFSize = FileGetSize($sFile)
    Local Static $iLast_FSize = $iFSize
    
    If $iLast_FSize == $iFSize Then
        Return
    EndIf
    
    $iLast_FSize = $iFSize
    
    Local $sNewLine = FileReadLine($sFile, -1)
    
    If $sNewLine Then
        Local $aSplit = StringRegExp($sNewLine, '"?([\d\.]+)"', 3)
        Local $iUbnd = UBound($aSplit)
        Local $sDiff = '', $iPrcntDiff
        
        For $i = 1 To $iUbnd - 1
            If $i + 1 < $iUbnd Then
                $iPrcntDiff = _NumPrecentDiff($aSplit[$i], $aSplit[$i + 1])
                
                If $iPrcntDiff >= 30 Or $iPrcntDiff <= -30 Then
                    $sDiff &= ($sDiff ? @CRLF : '') & $aSplit[$i] & ' ' & ($iPrcntDiff >= 30 ? '<' : '>') & ' ' & $aSplit[$i + 1] & ' (' & $iPrcntDiff & ' %)'
                EndIf
            EndIf
        Next
        
        If $sDiff Then
            MsgBox(64, @ScriptName, $aSplit[0] & @CRLF & $sDiff)
        EndIf
    EndIf
EndFunc

Func _NumPrecentDiff($iNum1, $iNum2)
    If $iNum1 > $iNum2 Then
        Return -Round((($iNum1 - $iNum2) / $iNum2) * 100, 2)
    ElseIf $iNum2 > $iNum1 Then
        Return Round((($iNum2 - $iNum1) / $iNum1) * 100, 2)
    EndIf
    
    Return 0
EndFunc

Func _Exit()
    Exit
EndFunc
 
Автор
M

Maria

Новичок
Сообщения
29
Репутация
0
Спасибо, работает. Но при тестировании я столкнулась с одной проблемой. Я увидела, что в файл могут быть записаны сразу несколько строк за один раз, я думала что туда идёт запись всегда только по одной строке.
Но за один раз могут быть записаны сразу более чем одна строка, на пример 10 и в этом случае, скрипт читает только самую первую строку из добавленных десяти.

И второй момент, мне нужно, что бы скрипт при первом запуске считывал уже имеющиеся строки и сравнил цены, а далее уже только в новых.
Скрипт будет подключаться к уже "работающему" текстовому файлу, который уже будет иметь строки.
Если у Вам не сложно измените пожалуйста.
Сообщение автоматически объединено:

Извините пожалуйста, что не сразу заметила большое количество строк, которые могу добавится за один раз.
Я понимаю это наверно усложнит задачу.
Сообщение автоматически объединено:

Ps
Я протестировала именно первый скрипт.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Код:
HotKeySet('{ESC}', _Exit)
AdlibRegister(_CheckLines, 1000)

While 1
    Sleep(100)
WEnd

Func _CheckLines()
    Local $sFile = @ScriptDir & '\filename.txt'
    
    If Not FileExists($sFile) Then
        Return
    EndIf
    
    Local $iFSize = FileGetSize($sFile)
    Local Static $iLast_FSize = -1
    
    If $iLast_FSize == $iFSize Then
        Return
    EndIf
    
    Local $aLines = FileReadToArray($sFile)
    Local Static $aLast_Lines = $aLines
    
    Local $iFound = 0
    Local $aNewLines[1]
    
    If $iLast_FSize = -1 Then
        $aNewLines = $aLines
    Else
        For $i = 0 To UBound($aLines) - 1
            If $aLines[$i] = '' Then
                ContinueLoop
            EndIf
            
            $iFound = 0
            
            For $j = 0 To UBound($aLast_Lines) - 1
                If $aLast_Lines[$j] = '' Then
                    ContinueLoop
                EndIf
                
                If $aLines[$i] = $aLast_Lines[$j] Then
                    $iFound = 1
                    ExitLoop
                EndIf
            Next
            
            If Not $iFound Then
                ReDim $aNewLines[UBound($aNewLines) + 1]
                $aNewLines[UBound($aNewLines) - 1] = $aLines[$i]
            EndIf
        Next
    EndIf
    
    $iLast_FSize = $iFSize
    $aLast_Lines = $aLines
    
    If UBound($aNewLines) > 0 Then
        Local $aSplit, $iUbnd, $sDiff, $iPrcntDiff
        
        For $iL = 0 To UBound($aNewLines) - 1
            $aSplit = StringRegExp($aNewLines[$iL], '"?([\d\.]+)"', 3)
            
            If @error Then
                ContinueLoop
            EndIf
            
            $iUbnd = UBound($aSplit)
            $sDiff = ''
            
            For $i = 1 To $iUbnd - 1
                If $i + 1 < $iUbnd Then
                    $iPrcntDiff = _NumPrecentDiff($aSplit[$i], $aSplit[$i + 1])
                    
                    If $iPrcntDiff >= 30 Or $iPrcntDiff <= -30 Then
                        $sDiff &= ($sDiff ? @CRLF : '') & $aSplit[$i] & ' ' & ($iPrcntDiff >= 30 ? '<' : '>') & ' ' & $aSplit[$i + 1] & ' (' & $iPrcntDiff & ' %)'
                    EndIf
                EndIf
            Next
            
            If $sDiff Then
                MsgBox(64, @ScriptName, $aSplit[0] & @CRLF & $sDiff)
            EndIf
        Next
    EndIf
EndFunc

Func _NumPrecentDiff($iNum1, $iNum2)
    If $iNum1 > $iNum2 Then
        Return -Round((($iNum1 - $iNum2) / $iNum2) * 100, 2)
    ElseIf $iNum2 > $iNum1 Then
        Return Round((($iNum2 - $iNum1) / $iNum1) * 100, 2)
    EndIf
    
    Return 0
EndFunc

Func _Exit()
    Exit
EndFunc


Тут на каждую строчку сравнения будет показан MsgBox.
 
Автор
M

Maria

Новичок
Сообщения
29
Репутация
0
Спасибо Вам большие, теперь точно всё работает как надо!)
Сообщение автоматически объединено:

При тестировании обнаружила обнаружила, что Asin -Номера могут заканчиваться на Х.
И поэтому этот патерн их не видит "StringRegExp($aNewLines[$iL], '"?([\d\.]+)"', 3)"
Сама я не смогла исправить. Помогите пожалуйста.
Пример файла с номерами, которые заканчиваются на Х, я прикрепила.
Сообщение автоматически объединено:

Ещё очень не хватает, что бы я могла регулировать глубину цен.
Например цен 20, но пусть скрипт проверит на пример первые 6. Это не должна быть кнопка ввода, просто в самом скрипте, что бы было видно и я могла менять 3,4,10 идт.
 

Вложения

  • filename.txt
    487 байт · Просмотры: 2
Последнее редактирование:

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Номера могут заканчиваться на Х
Речь про номер который в начале? А что с ценами, они тоже могут заканчиваться на Х?

Например цен 20, но пусть скрипт проверит на пример первые 6
Цен имеется в виду в одной строке, или 20 это число строк?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Код:
Global $iCheck_Prices_Depth = 5 ;Макс. число ценников на проверку, установите -1 для проверки всех ценников
Global $sFile = @ScriptDir & '\filename.txt'

If Not FileExists($sFile) Then
    MsgBox(48, @ScriptName, 'File not found.')
    Exit
EndIf


HotKeySet('{ESC}', _Exit)
AdlibRegister(_CheckLines, 1000)

While 1
    Sleep(100)
WEnd

Func _CheckLines()
    Local $iFSize = FileGetSize($sFile)
    Local Static $iLast_FSize = -1
    
    If $iLast_FSize == $iFSize Then
        Return
    EndIf
    
    Local $aLines = FileReadToArray($sFile)
    Local Static $aLast_Lines = $aLines
    
    Local $iFound = 0
    Local $aNewLines[1]
    
    If $iLast_FSize = -1 Then
        $aNewLines = $aLines
    Else
        For $i = 0 To UBound($aLines) - 1
            If $aLines[$i] = '' Then
                ContinueLoop
            EndIf
            
            $iFound = 0
            
            For $j = 0 To UBound($aLast_Lines) - 1
                If $aLast_Lines[$j] = '' Then
                    ContinueLoop
                EndIf
                
                If $aLines[$i] = $aLast_Lines[$j] Then
                    $iFound = 1
                    ExitLoop
                EndIf
            Next
            
            If Not $iFound Then
                ReDim $aNewLines[UBound($aNewLines) + 1]
                $aNewLines[UBound($aNewLines) - 1] = $aLines[$i]
            EndIf
        Next
    EndIf
    
    $iLast_FSize = $iFSize
    $aLast_Lines = $aLines
    
    If UBound($aNewLines) > 0 Then
        Local $aSplit, $sDiff, $iPrcntDiff
        
        For $iL = 0 To UBound($aNewLines) - 1
            $aSplit = StringSplit($aNewLines[$iL], '"')
            $sDiff = ''
            
            For $i = 2 To $aSplit[0]
                If $iCheck_Prices_Depth <> -1 And $i > $iCheck_Prices_Depth Then
                    ExitLoop
                EndIf
                
                ;Ели это последний ценник, или следующий ценник пуст, или это не цифра, то продолжаем цикл со следующей итерации
                If $i = $aSplit[0] Or $aSplit[$i + 1] = '' Or Not StringRegExp($aSplit[$i], '^[0-9\.]+$') Then
                    ContinueLoop
                EndIf
                
                $iPrcntDiff = _NumberPercentDiff($aSplit[$i], $aSplit[$i + 1])
                
                If $iPrcntDiff >= 30 Or $iPrcntDiff <= -30 Then
                    $sDiff &= ($sDiff ? @CRLF : '') & $aSplit[$i] & ' ' & ($iPrcntDiff >= 30 ? '<' : '>') & ' ' & $aSplit[$i + 1] & ' (' & $iPrcntDiff & ' %)'
                EndIf
            Next
            
            If $sDiff Then
                MsgBox(64, @ScriptName, $aSplit[1] & @CRLF & $sDiff)
            EndIf
        Next
    EndIf
EndFunc

Func _NumberPercentDiff($iNum1, $iNum2)
    $iNum1 = Number($iNum1)
    $iNum2 = Number($iNum2)
    
    If $iNum1 = 0 Or $iNum2 = 0 Then
        Return SetError(1, 0, 0)
    EndIf
    
    If $iNum1 > $iNum2 Then
        Return -Round((($iNum1 - $iNum2) / $iNum2) * 100, 2)
    ElseIf $iNum2 > $iNum1 Then
        Return Round((($iNum2 - $iNum1) / $iNum1) * 100, 2)
    EndIf
    
    Return 0
EndFunc

Func _Exit()
    Exit
EndFunc
 
Автор
M

Maria

Новичок
Сообщения
29
Репутация
0
Вы правильно поняли и сделали как раз то что нужно. Спасибо Вам ещё раз )
 
Верх