2012-07-27 10 views

Odpowiedz

9

Oczywiście, ale podobnie jak większość przetwarzania plików tekstowych za pomocą partii, nie jest ładna i nie jest szczególnie szybka.

To rozwiązanie ignoruje wielkość liter podczas wyszukiwania duplikatów i sortuje linie. Nazwa pliku jest przekazywana jako pierwszy i jedyny argument skryptu wsadowego.

@echo off 
setlocal disableDelayedExpansion 
set "file=%~1" 
set "sorted=%file%.sorted" 
set "deduped=%file%.deduped" 
::Define a variable containing a linefeed character 
set LF=^ 


::The 2 blank lines above are critical, do not remove 
sort "%file%" >"%sorted%" 
>"%deduped%" (
    set "prev=" 
    for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%sorted%") do (
    set "ln=%%A" 
    setlocal enableDelayedExpansion 
    if /i "!ln!" neq "!prev!" (
     endlocal 
     (echo %%A) 
     set "prev=%%A" 
    ) else endlocal 
) 
) 
>nul move /y "%deduped%" "%file%" 
del "%sorted%" 

W tym rozwiązaniu rozróżniana jest wielkość liter i pozostawia wiersze w oryginalnej kolejności (z wyjątkiem oczywiście duplikatów). Ponownie nazwa pliku jest przekazywana jako pierwszy i jedyny argument.

@echo off 
setlocal disableDelayedExpansion 
set "file=%~1" 
set "line=%file%.line" 
set "deduped=%file%.deduped" 
::Define a variable containing a linefeed character 
set LF=^ 


::The 2 blank lines above are critical, do not remove 
>"%deduped%" (
    for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file%") do (
    set "ln=%%A" 
    setlocal enableDelayedExpansion 
    >"%line%" (echo !ln:\=\\!) 
    >nul findstr /xlg:"%line%" "%deduped%" || (echo !ln!) 
    endlocal 
) 
) 
>nul move /y "%deduped%" "%file%" 
2>nul del "%line%" 


EDIT

Oba rozwiązania powyżej paska wierszy. Nie sądziłem, że puste linie warte są zachowania, gdy mówimy o różnych wartościach.

Zmodyfikowałem oba rozwiązania, aby wyłączyć opcję FOR/F "EOL", aby zachować wszystkie niepuste linie, niezależnie od tego, czym jest 1. znak. Zmodyfikowany kod ustawia opcję EOL na znak posuwu liniowego.


Nowe rozwiązanie 13.04.2016: JSORT.BAT

Można używać mojego JSORT.BAT hybrid JScript/batch utility skutecznie sortowania i usunąć duplikaty wierszy z jednej prostej liniowej (plus ruch nadpisać oryginalny plik z wynikiem końcowym). JSORT to czysty skrypt, który działa natywnie na dowolnym komputerze z systemem Windows od XP.

@jsort file.txt /u >file.txt.new 
@move /y file.txt.new file.txt >nul 
+0

Przeszukiwany ciąg do szukania finstrów jest zbyt długi. –

+1

@Dreadedsemicolon - Tak, nie myślałem o tym, że druga opcja nie powiedzie się, jeśli jakakolwiek linia przekroczy długość 511 (127 na XP) z powodu ograniczeń FINDSTR. – dbenham

3
set "file=%CD%\%1" 
sort "%file%">"%file%.sorted" 
del /q "%file%" 
FOR /F "tokens=*" %%A IN (%file%.sorted) DO (
SETLOCAL EnableDelayedExpansion 
if not [%%A]==[!LN!] (
set "ln=%%A" 
echo %%A>>"%file%" 
) 
) 
ENDLOCAL 
del /q "%file%.sorted" 

To powinno działać dokładnie tak samo. Ten przykład dbenham wydawał mi się zbyt dla mnie zbyt trudny, przetestowałem więc własne rozwiązanie. wykorzystanie ex .: filedup.cmd filename.ext

+0

Po prostu FYI: Pierwsze polecenie 'set' nie zawsze działa. Widziałem, że% CD% nie działa i/lub jest wielokrotnie zastępowany! Powinieneś użyć tego zamiast "set" file =% ~ dpnx1 "'. Litery w% 1 są zdefiniowane jako: d = dysk, p = ścieżka, n = nazwa pliku (bez rozszerzenia), x = rozszerzenie. Działa to dla pierwszego argumentu, nawet jeśli tylko przekazujesz nazwę pliku (bez ścieżki). – wasatchwizard

0

Natknąłem się na tę kwestię i musiałem rozwiązać to samodzielnie, ponieważ wykorzystanie było w znacznym stopniu uzależnione od moich potrzeb. Potrzebowałem znaleźć zduplikowane adresy URL i kolejność wierszy, które były odpowiednie, więc musiały zostać zachowane. Wiersze tekstu nie powinny zawierać podwójnych cudzysłowów, nie powinny być zbyt długie i nie można ich sortować.

Tak więc zrobiłem to:

setlocal enabledelayedexpansion 
type nul>unique.txt 
for /F "tokens=*" %%i in (list.txt) do (
    find "%%i" unique.txt 1>nul 
    if !errorlevel! NEQ 0 (
     echo %%i>>unique.txt 
    ) 
) 

pomocnicze: jeśli tekst nie zawiera cudzysłów następnie WYSZUKAJ musi użyć filtrowaną zmienną jest ustawiony w sposób opisany w tym poście: Escape double quotes in parameter

więc zamiast:

find "%%i" unique.txt 1>nul 

byłoby więcej takich jak:

set test=%%i 
set test=!test:"=""! 
find "!test!" unique.txt 1>nul 

W ten sposób znalezisko będzie wyglądało jak znaleźć "" "co" "i plik %% i pozostanie niezmieniony.

1

Użyłem fałszywy „tablicy”, aby osiągnąć ten

@echo off 
:: filter out all duplicate ip addresses 
REM you file would take place of %1 
set file=%1% 
if [%1]==[] goto :EOF 
setlocal EnableDelayedExpansion 
set size=0 
set cond=false 
set max=0 
for /F %%a IN ('type %file%') do ( 
     if [!size!]==[0] (
      set cond=true 
      set /a size="size+1" 
      set arr[!size!]=%%a 

    ) ELSE (
       call :inner 
       if [!cond!]==[true] (
        set /a size="size+1" 
        set arr[!size!]=%%a&& ECHO > NUL      
       ) 
    ) 
) 
break> %file% 
:: destroys old output 
for /L %%b in (1,1,!size!) do echo !arr[%%b]!>> %file% 
endlocal 
goto :eof 
:inner 
for /L %%b in (1,1,!size!) do ( 
      if "%%a" neq "!arr[%%b]!" (set cond=true) ELSE (set cond=false&&goto :break)         
) 
:break 

użycie etykiety dla pętli wewnętrznej jest coś konkretnego do cmd.exe i jest to jedyny sposób, w jaki udało zagnieżdżanie pętli jeden w drugim. Zasadniczo porównuje każdą nową wartość, która jest przekazywana jako ogranicznik i jeśli nie ma dopasowania, program doda wartość do pamięci. Kiedy to się robi to zniszczy zawartość pliki docelowe i zastąpić je unikatowych ciągów

2

plik wsadowy poniżej tego, co chcesz:

@echo off 
setlocal EnableDelayedExpansion 
set "prevLine=" 
for /F "delims=" %%a in (theFile.txt) do (
    if "%%a" neq "!prevLine!" (
     echo %%a 
     set "prevLine=%%a" 
    ) 
) 

Jeśli potrzebujesz bardziej wydajny sposób, spróbuj tego okresową Skrypt hybrydowy JScript, opracowany jako filtr , podobny do programu Unix uniq. Zapisać go z rozszerzeniem .bat, jak uniq.bat:

@if (@CodeSection == @Batch) @then 

@CScript //nologo //E:JScript "%~F0" & goto :EOF 

@end 

var line, prevLine = ""; 
while (! WScript.Stdin.AtEndOfStream) { 
    line = WScript.Stdin.ReadLine(); 
    if (line != prevLine) { 
     WScript.Stdout.WriteLine(line); 
     prevLine = line; 
    } 
} 

Oba programy zostały skopiowane z this post.

2

Czysta partia - 3 efektywne linie.

@ECHO OFF 
SETLOCAL 
:: remove variables starting $ 
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a=" 

FOR /f "delims=" %%a IN (q34223624.txt) DO SET $%%a=Y 
(FOR /F "delims=$=" %%a In ('set $ 2^>Nul') DO ECHO %%a)>u:\resultfile.txt 

GOTO :EOF 

Działa szczęśliwie, jeśli dane nie zawierają znaków, których partia ma czułość.

"q34223624.txt", ponieważ kwestia 34223624 zawierał te dane

1.1.1.1 
1.1.1.1 
1.1.1.1 
1.2.1.2 
1.2.1.2 
1.2.1.2 
1.3.1.3 
1.3.1.3 
1.3.1.3 

na którym działa idealnie.

Powiązane problemy