Как это сделать в PowerShell? Или: какой язык использовать для работы с файлами и строками? - PullRequest
4 голосов
/ 14 июня 2009

Какой язык мне использовать для работы с файлами и строками?

Это может показаться объективным, но на самом деле я не думаю. Есть много, чтобы сказать об этом. Например, я ясно вижу, что для большинства случаев Perl будет более очевидным кандидатом, чем Java. Мне нужно делать это довольно часто, и в настоящее время я использую для этого C #, но я бы хотел, чтобы это был более похожий на сценарий язык.

Я могу представить, что Perl будет кандидатом на это, но я бы хотел сделать это в PowerShell , поскольку PowerShell может получить доступ к библиотеке .NET (легко). Или Python лучший кандидат на это? Если мне нужно выучить новый язык, то в моем списке наверняка будет Python, а не Perl.

Например, я хочу прочитать файл, внести некоторые изменения и сохранить его снова. Например: откройте его, пронумеруйте все строки (скажем, с 3 цифрами) и закройте его. Любой пример на любом языке приветствуется, но чем короче, тем лучше. Мне нужны здесь служебные скрипты, а не OO, TDDeveloped, тестируемые модульные вещи, конечно.

Я бы очень хотел увидеть что-то вроде ( псевдокод здесь):

open foobar.as f

foreach  line in f.lines 
 line.addBefore(currenIteratorCounter.format('ddd') + '. ')

close f

Итак:

bar.txt 

Frank Zappa
Cowboy Henk
Tom Waits

numberLines bar.txt

bar.txt 

001. Frank Zappa
002. Cowboy Henk
003. Tom Waits

ОБНОВЛЕНИЕ:

Примеры Perl и Python здесь великолепны и определенно соответствуют тому, что я надеялся и ожидал. Но разве нет парней из PowerShell?

Ответы [ 6 ]

11 голосов
/ 14 июня 2009

Это на самом деле довольно просто в PowerShell :

function Number-Lines($name) {
    Get-Content $name | ForEach-Object { $i = 1 } { "{0:000}. {1}" -f $i++,$_ }
}

То, что я делаю здесь, это получение содержимого файла, это вернет String[], по которому я итерирую с ForEach-Object и применю строку формата, используя оператор -f. Результат просто выпадает из конвейера как еще один String[], который может быть перенаправлен в файл при необходимости.

Вы можете немного сократить его, используя псевдонимы:

gc .\someFile.txt | %{$i=1}{ "{0:000}. {1}" -f $i++,$_ }

но я не буду рекомендовать это для определения функции.

Кстати, вы хотите рассмотреть возможность использования двух проходов и построения строки формата на лету, чтобы приспособиться к большему количеству строк. Если имеется 1500 строк {0:000}, этого больше не будет достаточно, чтобы получить аккуратно выровненный вывод.

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

  • краткость кода (Perl там будет трудно победить, особенно в одном ответе на другой)
  • удобочитаемость и удобство обслуживания кода
  • доступность инструментов (Perl и Python по умолчанию не установлены в Windows (PowerShell только после Windows 7), поэтому развертывание может быть затруднено.)

В свете последнего пункта вам, возможно, будет даже лучше использовать cmd для этой задачи. Код также довольно прост:

@echo off
setlocal
set line=1
for /f "delims=" %%l in (%1) do call :process %%l
endlocal
goto :eof

:process
call :lz %line%
echo %lz%. %*
set /a line+=1
goto :eof

:lz
if %1 LSS 10 set lz=00%1&goto :eof
if %1 LSS 100 set lz=0%1&goto :eof
set lz=%1&goto :eof
goto :eof

Это предполагает, конечно, что он должен работать где-то еще, кроме вашей собственной машины. Если нет, то используйте то, что соответствует вашим потребностям: -)

2 голосов
/ 14 июня 2009

Это не то, что вы хотели, но, пожалуйста, время от времени вспомните findstr.exe (и find.exe) ...

findstr / n ". *" Имя файла найти "" / v / n имя файла

2 голосов
/ 14 июня 2009
perl -i -ne 'printf("00%d. %s",$.,$_)' your-filename-here

Вместо этого вы можете захотеть% 03d.

1 голос
/ 14 июня 2009

В системе Debian (и, возможно, в других дистрибутивах Linux) вы можете сделать это:

$ nl -w 3 -n rz -s ". " [filename] > [newfilename]
1 голос
/ 14 июня 2009

Определенно Perl. Он поддерживает встроенную замену (в Windows вы должны запустить скрипт с помощью perl .i.bak (поскольку Windows не может сделать это встроенным и создает файл .bak с тем же именем).

open(IN,'+>'.$yourfile) || die "Can not open file $yourfile: $!";

my $line_no = 1;

while(<IN>){
   print "$line_no. $_";
   $line_no++;
}
close IN;

Код, набранный из памяти без тестирования. Но это должно сработать. Возможно, вы захотите добавить некоторую логику для форматирования $ line_no (например, сначала подсчитайте количество строк, а затем добавьте столько нулевых цифр, сколько вам нужно.)

1 голос
/ 14 июня 2009

Python

target = open( "bar_with_numbers.txt", "w" )
source = open( "bar.txt", "r" )
for count, line in enumerate( source ):
    target.write( "%3d. %s\n" % ( count+1, line ) )
source.close()
target.close()

Во-первых, плохая политика - "обновлять" файлы на месте. В конечном итоге это становится прискорбным решением, потому что отладка усложняется потерей истории.

Если вы используете функции перенаправления ОС, эту программу можно упростить.

import sys
for count, line in enumerate( sys.stdin ):
    sys.stdout.write( "%3d. %s\n" % ( count+1, line ) )

Затем вы можете запустить это enumerate.py следующим образом

python enumerate.py <bar.txt >bar_with_numbers.txt

Что еще более важно, вы также можете сделать это.

python enumerate.py <bar.txt | the_next_step
...