Что нового

Как удалить дубликаты строк в файле

ynbIpb

Скриптер
Сообщения
399
Репутация
110
У меня тут тоже вопрос по поводу поиска в тексте:
Я с помощью StringRegExp нахожу в HTML файле некий текст и формирую список txt. Но часто встречаются дубликаты, как бы их поудалять?
Код:
$page = FileOpen (@ScriptDir & "\pages\01.htm", 0)
$page_read = FileRead ($page)
FileClose ($page)
$nOffset = 1
$allnames = ""
While 1
$Names = StringRegExp ($page_read, "Автор: <b>(.*?)</b>" , 1, $nOffset)
If @error = 0 Then
        $nOffset = @extended
    Else
        ExitLoop
EndIf
$allnames &= $Names[0]&@CRLF
WEnd
msgbox(0, "", $allnames)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Если нужно удалить дубликаты в файле, тогда вот:

Код:
$sFileName = "Test.txt"
$sFilePath = @ScriptDir & "\"
$sFile = $sFilePath & $sFileName

$iRet = _FileDeleteDuplicateLines($sFile, 0)
$iExtended = @extended

If $iRet = 1 And $iExtended > 0 Then
	MsgBox(64, "Results", StringFormat("В файле <%s> удалено дублирующихся строк: %i", $sFileName, $iExtended))
ElseIf $iExtended = 0 Then
	MsgBox(64, "Results", StringFormat("В файле <%s> нет дублирующихся строк.", $sFileName))
ElseIf @error = 1 Then
	MsgBox(48, "Ошибка", StringFormat("Файл <%s> не найден.", $sFileName))
ElseIf @error = 2 Then
	MsgBox(48, "Ошибка", StringFormat("Ошибка при попытке записи в Файл <%s>.", $sFileName))
EndIf

Func _FileDeleteDuplicateLines($sFile, $iCaseSense=0)
	If Not FileExists($sFile) Then Return SetError(1)
	Local $sFRead = FileRead($sFile)
	Local $aFSplit = StringSplit(StringStripCR($sFRead), @LF)
	Local $sFileContent = "", $iExtended = 0, $sLastChars = StringRight($sFRead, 2)
	
	;Проходим весь массив, и проверяем каждую строку
	For $i = 1 To $aFSplit[0]
		If $aFSplit[$i] = "" Then ContinueLoop
		
		;Тут делаем проверку в переменной, в которую скапливаются строки (не дублирующиеся)
		If Not StringInStr($sFileContent, $aFSplit[$i] & @CRLF, $iCaseSense) Then
			$sFileContent &= $aFSplit[$i] & @CRLF
		Else
			$iExtended += 1
		EndIf
	Next
	
	If $sLastChars <> @CRLF Then $sFileContent = StringTrimRight($sFileContent, 2)
	
	;Пишем в файл уже без дублей
	Local $hFOpen = FileOpen($sFile, 2)
	If $hFOpen = -1 Then Return SetError(2)
	
	FileWrite($hFOpen, $sFileContent)
	FileClose($hFOpen)
	
	Return SetExtended($iExtended, 1)
EndFunc



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

А если просто в строке удалить, то можно так:

Код:
$allnames = StringRegExpReplace($allnames, '(?sm)(^[^\n]+\n?)(.*?)^\1', '\1\2')
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Спасибо, вроде смысл первого понял.
а вот со вторым вариантом недогоняю.
оно только в строке удаляет дубли? тоесть должен быть какойто разделитель?
вот так попробовал ничего:
Код:
$allnames = "раз раз два" 
$allnames = StringRegExpReplace($allnames, '(?sm)(^[^\n]+\n?)(.*?)^\1', '\1\2')
MsgBox (0, "", $allnames)
Если не затруднит, то поподробней, что каждый символ в шаблоне выпоняет.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
ynbIpb [?]
оно только в строке удаляет дубли? тоесть должен быть какойто разделитель?
Удаляет дубликаты строк, да, разделитель это новая строка (@CRLF).

вот так попробовал ничего
Для одной строки можно так:
Код:
$allnames = "one one two"
$allnames = StringRegExpReplace($allnames, '\s?(\b\S+\b)(?=.*\b\1\b)', '')
ConsoleWrite(@extended & @CRLF)
MsgBox (0, "", $allnames)

Хотя для не латинских симолов оно почему то не срабатывает...
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Вот теперь работает.
Код:
$allnames = "раз"&@CRLF&"раз"&@CRLF&"два"
$allnames = StringRegExpReplace($allnames, '(?sm)(^[^\n]+\n?)(.*?)^\1', '\1\2')
MsgBox (0, "", $allnames)

Но! мне хочется понять принцип действия. у меня туго с регекспами, сколько не перечитывал справку.
Если не трудно то словами можно описать порядок происходящих действия в этом выражении, что конкретно в данной ситуации выполняет каждый символ?
 

snoitaleR

AutoIT Гуру
Сообщения
854
Репутация
223
ynbIpb
Вот он - повод для меня начать изучение регулярных выражений... :smile:
Открыл я "regexp2-ref.pdf" и бегло просмотрел его...
Понял одну простую вещь: чтобы понять логику регулярного выражения надо до автоматизма "зазубрить" значение каждого метасимвола, чтобы при разборе каждого символа в выражении не заглядывать в справочник, иначе теряется основная мысль...
Продолжаем изучать дальше... :smile:
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
623
Да. Читаешь слева направо. Каждый символ как правило сам себя и обозначает, помимо специальных.
Встретил слеш (\) значит следующий за ним спецсимвол читает as is, встретил скобки без слешов, значит то, что внутри них единый объект. Ну и да, спецсимволы надо выучить :smile:
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Ну хорошо. бум курить справку дальше. тему отметил как решённую. всем спасибо за участие.
 

Norm

Знающий
Сообщения
129
Репутация
19
Поиск дубликатов СТРОК в тексте с помощью превращения его в массив работает очень медленно,
поэтому я всегда использовал для этого вот эту регулярку "(?ms)^(\V+\R*)^(?=.*\1)" , НО
_ArrayUnique удаляет дубликаты просто мгновенно
Вот упрощенный вариант, для удаления дубликатов строк:
Код:
#Include <Array.au3>

Local $sString = "Cтрока с дубликатом"& @CRLF & _
                              "Строка без дубликата"& @CRLF & _
                              "Cтрока с дубликатом"

MsgBox(Default,"Результат",_StringUnique($sString))

Func _StringUnique(ByRef $sStrng)
    Local $aArray = StringRegExp($sStrng, "([^\v]+)", 3) ; Загоняем строки с массив
    If @error <> 0 Then Return -1
    Local $oDict = ObjCreate('Scripting.Dictionary') ; Создаем словарь
    For $nN = 0 To UBound($aArray)-1
        $oDict.Item($aArray[$nN]) ; Словарь, в котором не будет одинаковых ключей
    Next
    $aArray = $oDict.Keys() ; Перегоняем все кючи в массив
    Return _ArrayToString($aArray, @CRLF) ; Теперь массив превращаем в строку
EndFunc
 
Последнее редактирование:
Верх