Тема: JScript: удаление повторов строк в файле
Юниксовая команда uniq сжимает идущие подряд повторы строк, оставляя в файле повторяющиеся строки, если они идут не подряд. Чтобы она выводила только уникальные строки, приходится сортировать входной файл, что зачастую неприемлемо.
Этот скрипт оставляет в выходном файле только одну уникальную строку на весь файл. Порядок строк при этом не нарушается. Файлы целиком в память не грузятся, а обрабатываются построчно. Пустые строки учитываются так же, как и все остальные. Есть 2 режима:
/1 - записывать в выходной файл первую встретившуюся строку, прочие дубли отбрасывать
/2 - наоборот, записывать последнюю строку из всех повторов, а первые дубли отбрасывать
Параметр /i - обработка без учета регистра символов. При запуске без параметров скрипт выдает справку. Разбор командной строки самый простой, поэтому важен порядок следования параметров, и нельзя опускать промежуточные параметры.
var
WSH = new ActiveXObject ("WScript.Shell"),
ARG = WScript.Arguments,
FSO = new ActiveXObject("Scripting.FileSystemObject"),
ForReading = 1,
ForWriting = 2,
ForAppending = 8,
buf = new Array(),
fCountAll=0,
fCount=0,
fNumLine,
fBufLine,
fInFile,
fOutFile,
fInFileName,
fOutFileName;
// Если скрипт запущен через WScript, перезапускаем его в консоли
if (WScript.FullName.toLowerCase() == (WScript.Path+'\\wscript.exe').toLowerCase()) {
var args='';
for (var i=0; i<ARG.length; i++) {
args+='"'+ARG(i)+'" ';
}
WSH.Run ('cscript.exe "'+WScript.ScriptName+'" '+args);
WScript.Quit();
}
if ( ARG.length == 0 ) {
WScript.Echo("Искусно расширенный и грамотно дополненный аналог UNIX команды uniq.\n");
WScript.Echo("Удаляет из входного файла повторяющеся строки и записывает результат в\nвыходной файл.\n");
WScript.Echo("Файл может быть несортированным.\n\n");
WScript.Echo(WScript.ScriptName+" файл [выходной файл [/(1|2) [/i]]]");
WScript.Echo("/1\t1 вариант - записывать первую встретившуюся строку, а прочие дубли\n \t отбрасывать");
WScript.Echo("/2\t2 вариант - записывать последнюю строку из всех повторов, а первые\n \t дубли отбрасывать");
WScript.Echo("/i\tБез учета регистра символов");
WScript.Echo("\nPress Enter to exit");
WScript.StdIn.ReadLine();
WScript.Quit();
}
fInFileName = ARG(0);
fOutFileName = ( ARG.length >=2 ) ? ARG(1) : ARG(0)+".out"
fCond = ((ARG.length >=3 ) ? ((ARG(2) == "/1" ) ? 1 : ((ARG(2) == "/2" )? 2 : 1 ) ) : 1 )
isCaseSensitive = ((ARG.length >=4 ) ? ((ARG(2).toLowerCase() == "/i" ) ? true : false ) : true )
fInFile = FSO.OpenTextFile (fInFileName, ForReading );
fOutFile = FSO.OpenTextFile(fOutFileName, ForWriting, true);
if(fCond == 1) {
WScript.Echo('1 вариант - записывать первую встретившуюся строку, а прочие дубли отбрасывать');
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// здесь записанные строки запоминаются в памяти
//
//while (!fInFile.AtEndOfStream) {
// fBufLine = fInFile.ReadLine();
// fCountAll++;
// if (!IsPresent (fBufLine)){ // если текущая строка еще не была записана в выходной файл
// fOutFile.WriteLine (fBufLine); // то пишем ее туда
// buf.unshift (fBufLine); // запоминаем что записали
// fCount++;
// }
//}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// здесь строки проверяются на присутствие в файле (медленно, но меньше требования к памяти)
//
while (!fInFile.AtEndOfStream) {
fBufLine = fInFile.ReadLine();
fCountAll++;
if (!IsPresentInOutput (fBufLine, isCaseSensitive)){ // если текущая строка еще не была записана в выходной файл
fOutFile.WriteLine (fBufLine); // то пишем ее туда
fCount++;
}
WScript.StdOut.Write(fCountAll+'\r');
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WScript.Echo('Уникальных записей: '+fCount+', всего: '+fCountAll);
} else if(fCond == 2) {
WScript.Echo('2 вариант - записывать последнюю строку из всех повторов, а первые дубли отбрасывать');
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// здесь строки проверяются на присутствие в файле (медленно, но меньше требования к памяти)
//
while (!fInFile.AtEndOfStream) {
fNumLine = fInFile.Line; // WScript.Echo("fNumLine = "+fNumLine);
fBufLine = fInFile.ReadLine();// WScript.Echo(fBufLine);
fCountAll++;
if (!IsPresentInFile (fInFile, fBufLine, isCaseSensitive)) { // если текущая строка уже не встречается в остатке файла
fOutFile.WriteLine (fBufLine); // то пишем ее туда
fCount++;
}
fInFile.Close();
fInFile = FSO.OpenTextFile (ARG(0), ForReading );
for (var i=0; i<fNumLine; i++) fInFile.SkipLine();
WScript.StdOut.Write(fCountAll+'\r');
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WScript.Echo('Уникальных записей: '+fCount+', всего: '+fCountAll);
}
function IsPresentInOutput(fLine, isCaseSens) {
var
res;
fOutFile.Close(); // закрываем выходной файл, открытый на запись
fOutFile = FSO.OpenTextFile(fOutFileName, ForReading, true); // открываем выходной файл на чтение
res = IsPresentInFile (fOutFile, fLine, isCaseSens); // ищем в нем строку
fOutFile = FSO.OpenTextFile(fOutFileName, ForAppending, true); // открываем выходной файл на добавление
return res;
}
// проверяет файл от текущей позиции до конца на предмет наличия в нем строки
function IsPresentInFile(fFile, fLine, isCaseSens) {
var
fTmpStr;
while (!fFile.AtEndOfStream) {
//fTmpStr = fFile.ReadLine()
if (isCaseSens){
if (fLine == fFile.ReadLine()) return true;
} else {
if (fLine.toLowerCase() == fFile.ReadLine().toLowerCase()) return true;
}
}
return (false);
}
function IsPresent(fLine) {
for (var i = 0; i < buf.length; i++) {
if (buf[i] == fLine) return (true);
}
return (false);
}
Автор скрипта - delpher.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.