Показать полную графическую версию : [решено] Поиск и замена
Добрый день.
Имеется тектовый файл, размером более 5000 строк. Вида:
pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26916,1000,3750,'','','11',null,NULL,1)
pla (IdPl,EncLevel,IdSection) Values (26916,2,21)
pla(IdPl,EncLevel,IdSection) Values (26916,1,1065)
Pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26917,2900,3750,'','','11',null,NULL,1)
Pla(IdPl,EncLevel,IdSection) Values (26917,2,21)
Pla (IdPl,EncLevel,IdSection) Values (26917,1,1065)
Pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26918,1050,3750,'','','11',null,NULL,1)
Pla (IdPl,EncLevel,IdSection) Values (26918,2,21)
Pla (IdPl,EncLevel,IdSection) Values (26918,1,1065)
Pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26919,1100,3750,'','','11',null,NULL,1)
Pla (IdPl,EncLevel,IdSection) Values (26919,2,21)
Pla (IdPl,EncLevel,IdSection) Values (26919,1,1065)
Задача состоит в том, что-бы заменить все Выделенные жирным цветом значения(они меняются +1 каждую четвертую строчку), на отрицательные цифры по порядку: 26916 == -1 , 26917 == -2 , 26918 == -3 ...
greg zakharov
18-03-2016, 19:08
user689, уважаемый, Вы в своем уме? Обрабатывать файл в пять тысяч строк на командном языке - что-то из разряда утонченного извращения. PowerShell'то достаточно долго думал, к слову, решение на нем будет выглядеть примерно так:
gc file | % {$a=-1;$b=0}{$_ -replace '(\d{5})', $a;$b++;if($b -eq 4){$b=0;$a+=-1}}
Наименее затратным по времени оказался Perl:
perl -pe 's/(\d{5})/-($1-26915)/e' file
Чуть более затратным оказался Python, далее - Ruby. sed'ом еще не пробовал, но, нужно полагать, он немногим уступает тому же Python'у или Perl'у.
Foreigner
18-03-2016, 20:16
На PowerShell можно еще так:
$a=0; (gc file.txt -read 4) | foreach { $_ -replace '\d{5}', --$a } | sc file.txt
или, если это будет "затратно", то сначала создать временный файл, а потом уже заменить им исходный.
greg zakharov
18-03-2016, 20:36
Foreigner, тогда уж лучше:
gc file -r 4|%{$a=0}{$_ -replace '\d{5}', --$a}
Но все равно медленне Perl'а.
Foreigner
18-03-2016, 21:07
Но все равно медленне Perl'а. »
Ничего не попишешь. А Perl какой и под какую платформу?
greg zakharov
18-03-2016, 22:01
В принципе, если гибридить JScript с командным языком, то:
0</* :
@cscript /nologo /e:jscript "%~f0" %*&exit /b */0;
(function(file) {
with (new ActiveXObject('Scripting.FileSystemObject')) {
if (!FileExists(file)) {
WScript.echo('File not found or does not exist.');
return;
}
var fs = OpenTextFile(GetAbsolutePathName(file), 1);
while (!fs.atEndOfStream) {
var s = fs.ReadLine();
if (s !== null) {
WScript.echo(s.replace(/\d{5}/, "-" + (s.match(/\d{5}/)-26915)));
}
}
fs.Close();
}
}(
WScript.Arguments.length !== 1
? (function() {
WScript.echo('Usage: ' + WScript.ScriptName + ' <file>');
WScript.echo('.e.g.: ' + WScript.ScriptName + ' E:\\sandbox\\file.txt');
WScript.Quit(1);
}()) : WScript.Arguments.Unnamed(0)
));
По скорости все же быстрее PowerShell'а. Правда операции над группами при замене не пракатывают, приходится еще и match задействовать.
gawk при замерах также показывает неплохой результат.
gawk 'match($0,/(.*\()([0-9]{5})(,.*)/,a) {$0=a[1]"-"a[2]-26915a[3]} 1' file
Спасибо за ответы!
PowerShell справился с задачей.
А как быть если в тексте встречаются дополнительные строки, количество их может быть разное, например:
pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26916,1000,3750,'','','11',null,NULL,1)
pla (IdPl,EncLevel,IdSection) Values (26916,2,21)
pla(IdPl,EncLevel,IdSection) Values (26916,1,1065)
go
Pl (IdPl,X,Y,TitleLine,Name,Description,idRowMetric,idPlMetric,Person) Values (26917,2900,3750,'','','11',null,NULL,1)
Pla(IdPl,EncLevel,IdSection) Values (26917,2,21)
Pla (IdPl,EncLevel,IdSection) Values (26917,1,1065)
commit
go
...
...
...
Однако перед каждым заменяемым значением всегда присутствуют "Values ("
А как быть если… »
Лучшим было бы прикладывать образец реального файла, упакованного в архив.
Пример файла во вложении.
135122
Foreigner
21-03-2016, 10:00
user689, Попробуйте такой вариант:
$a = sls '\d{5}' ttv.txt
$b = gc ttv.txt
# $a.matches.value[0]..$a.matches.value[($a.matches.value.count-1)] | # если версия PowerShell ниже четвертой
$a.matches.value[0]..$a.matches.value[-1] |
foreach { $n=0 } { $b = $b -replace $_, --$n }
$b | sc ttv-new.txt
PS C:\Documents and Settings\Администратор> $a.matches.value[0]..$a.matches.value[-1] | foreach { $n=0 } { $b = $b -repl
ace $_, --$n }
Не удается индексировать в массив NULL.
строка:1 знак:18
+ $a.matches.value[ <<<< 0]..$a.matches.value[-1] | foreach { $n=0 } { $b = $b -replace $_, --$n }
+ CategoryInfo : InvalidOperation: (0:Int32) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Foreigner
21-03-2016, 12:52
user689, У меня все отработало. И если запускать, как скрипт и если интерактивно -- в консоли:
http://s13.postimg.org/5qqg52z1f/image.jpg (http://postimg.org/image/5qqg52z1f/)
Попробуйте обращаться к индексу последнего элемента массива через свойство count, как показано на скриншоте:
$a.matches.value.count-1
на сервере версия 2.0 - не сработало, в 4.0 - все хорошо.
Спасибо!
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.