Нумерация строк - реализовать nl


13

Ваша задача - реализовать программу, аналогичную nlинструменту командной строки из основных утилит GNU.

Стандартные лазейки запрещены.

Вы не можете использовать какие-либо встроенные или внешние функции, программы или утилиты для нумерации строк файла или строки, например, nlсебя или =команды в GNU sed.

Спецификация

вход

Программа принимает имена файлов в качестве аргументов. Ваш код не обязательно должен быть кроссплатформенным; должен использоваться формат имени операционной системы, в которой выполняется код, т. е. если вы находитесь в Windows, разделитель каталогов может быть \или /.

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

В списке имен файлов, -представляет стандартный ввод.

Если указаны имена файлов, прочитайте их в том порядке, в котором они указаны, и объедините их содержимое, вставив новую строку между каждым и в конце. Если вы не можете прочитать одно или несколько имен файлов (поскольку файл не существует или у вас нет прав на чтение), игнорируйте их. Если все указанные имена файлов недействительны, ничего не выводить.

Если имена файлов не заданы, читайте со стандартного ввода. Чтение только из стандартного ввода, если имена файлов не указаны или -указаны.

Выход

Выход программы будет на стандартный вывод, вход с линиями пронумерованы таким образом (можно предположить , что вход имеет \n, \r\nили \rконца строки, выбрать наиболее удобный для вас, но указать , какой из них):

<5 spaces>1<tab><content of line 1 of input>
<5 spaces>2<tab><content of line 2 of input>
...
<4 spaces>10<tab><content of line 10 of input>
...
<3 spaces>100<tab><content of line 100 of input>
...
...

Для номера строки выделяется 6 символов пробела, и он вставляется в конце этих символов; остальные становятся пробелами (например, 1будет 5 пробелов, 22будет 4 пробела, ...). Если ввод достаточно длинный, у вас в конце концов останется недостаточно места для номера строки в строке 999999. Вы не должны ничего выводить после строки 999999.

Если вход пуст, ничего не выводить.

Статус выхода

Нижние числа имеют приоритет: если возникли ошибки 1 и 2, выйдите со статусом 1.

Выйдите со статусом 0, если вход был успешно получен, а строки успешно пронумерованы и выведены.

Выход со статусом 1, если один или несколько файлов, указанных в командной строке, не найдены или не могут быть прочитаны.

Выход со статусом 2, если задано слишком много файлов (более 64).

Выход со статусом 3, если ввод был слишком длинным (более 999999 строк). \

счет

Это код-гольф - выигрывает самая короткая программа!

Я могу добавить бонусы позже для реализации определенных опций, которые nlесть. На данный момент бонусов нет.


Является ли нумерация строк непрерывной или короткой, она «сбрасывает» себя для каждого отдельного файла?
Британцы

@britishtea Это непрерывно

1
Так нужно ли использовать узел, если мы хотим отправить что-то в js? Или мы можем использовать аргументы функции или prompt()эмулировать аргументы программы и стандартный ввод?
DankMemes

1
Бинарные файлы? Кодирование? Unicode маркеры?
edc65

Ответы:


6

Баш, 121

s=$[2*($#>64)]
for f in "$@";{ [ -f $f ]||s=1;}
((s))&&exit $s
awk '{if(NR>=10**6){exit 3}printf("%6d\t%s\n",NR,$0)}' $@

1
Вы можете сделать свои ifвыражения немного короче, если используете арифметические выражения, например(($#>64))&&s=2
Digital Trauma

2
@DigitalTrauma Я узнал кое-что!
Саммит

1
Вы можете заменить s=0;(($#>64))&&s=2на s=$[2*($#>64)], (($s==0))||с ((s))&&и ifзаявление с [ -f "$f" ]||s=1.
Деннис


2
awkбудет также объединяться, если передано несколько файлов, так что это официально считается бесполезным использованием cat ;-). Вместо этого я думаю, что это сработает:awk '...' $@
Digital Trauma

2

Рубин, 195

o,l=$*[64]?[2]:[],999999
($*==[]?[?-]:$*).each{|n|f=n==?-?STDIN: open(n)rescue o<<1&&next
s=f.read.lines
s[l]?o<<3:1
puts s[0..l].map.with_index(1){|l,i|i.to_s.rjust(6)+?\t+l}}
exit !o[0]?0:o.min

Я думаю, что STDINпсевдоним $<.
Мартин Эндер

Это псевдоним для ARGF, который также будет считывать оставшиеся файлы в качестве аргументов. Я думаю, что это может быть использовано для дальнейшего использования ARGFкаким-либо образом (даже кажется, "-"что он считается стандартным).
Британцы

britishteanl: 4: in block in <main>': undefined method [] 'для # <перечислитель: 0x000006002980c8> (NoMethodError) из britishteanl: 2: в each' from britishteanl:2:in <main>' - что не так? Я запустил его какruby britishteanl folder/filename

Я подозреваю, что это разница в версии Ruby. Я запустил образец на Ruby 2.0.0 и Ruby 2.1.2 без проблем. Какую версию ты используешь?
Британцы

2

Perl, 84 + 2 ( -pl) = 86 байт

perl -ple'BEGIN{map{-r||exit 1}@ARGV;@ARGV>63&&exit 2}$.>=1e6&&exit 3;$_=printf"%5d\t%s",$.,$_'

Deparsed:

perl -MO=Deparse -ple'BEGIN{map{-r||exit 1}@ARGV;@ARGV>63&&exit 2}$.>=1e6&&exit 3;$_=printf"%5d\t%s",$.,$_' output.txt; echo $?

BEGIN { $/ = "\n"; $\ = "\n"; }
sub BEGIN {
    map {exit 1 unless -r $_;} @ARGV;
    exit 2 if @ARGV > 63;
}
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    exit 3 if $. >= 1000000;
    $_ = printf("%5d\t%s", $., $_);
}
continue {
    die "-p destination: $!\n" unless print $_;
}
-e syntax OK

Важно знать:

  • -pпереносит программу, указанную -eв цикле while/continue
  • BEGIN код будет выполнен перед (неявной) основной частью
  • Проверка файла -rтакже не выполняется, если файл не существует, !-eи по умолчанию используется проверка $_, неявно указанная вmap { ... } @ARGV
  • $. содержит текущий номер строки
  • отдых должен быть самоочевидным;)

Отличный ответ, и добро пожаловать в программирование головоломок и Code Golf! Возможно, вы могли бы отредактировать, чтобы добавить объяснение того, как работает ваш код.
wizzwizz4

1

питон 173

import os,sys
c=0
l=1
for f in sys.argv[1:]:
    if c>64:exit(2)
    if not os.path.isfile(f):exit(1)
    c+=1
    for x in open(f):
        if l>=10**6:exit(3)
        print '%6d\t%s'%(l,x),;l+=1

Я думаю, что ваш код в настоящее время отсутствует -для sys.stdin. Возможное решение может быть что-то вроде, fh=sys.stdin if f=='-' else open(f)а затем пойти с x=fh.readline()?! К сожалению, это не делает его немного короче, хотя. :)
Дэйв Дж

1

J (162)

exit(((2*64<#)[exit@3:`(stdout@(,&LF)@;@(,&TAB@(6&":)&.>@>:@i.@#,&.>]))@.(1e6>#)@(<;.2)@(1!:1)@(<`3:@.('-'-:]))&.>@;@{.@(_64&(<\))) ::1:)]`(]&<&'-')@.(0=#)2}.ARGV

Объяснение:

  • ]`(]&<&'-')@.(0=#)2}.ARGVПолучите аргументы командной строки и удалите первые два (потому что это интерпретатор и имя файла скрипта). Если полученный список пуст, вернуть ['-'](то есть, как если бы пользователь только прошел -), в противном случае вернуть список без изменений.
  • (... ::1:): если внутренняя функция завершается с ошибкой, вернуть 1, иначе вернуть то, что вернула внутренняя функция.
  • ((2*64<#)[... ): оцените внутреннюю функцию и отбросьте результат. Затем, если длина переданного списка не была больше 64, верните 0, в противном случае верните 2.
  • &.>@;@{.@(_64&(<\)): получить не более 64элементов из списка и для каждого из них запустить следующую функцию:
    • (1!:1)@(<`3:@.('-'-:])): если элемент был -, прочитайте содержимое дескриптора файла 3(stdin), в противном случае прочитайте содержимое файла, названного этим элементом. Если это не удается (т. Е. Файл не существует), приведенный выше код перехватит его и вернет 1.
    • exit@3:`(... )@.(1e6>#)@(<;.2): разбить строку по окончанию строки. Если есть 1.000.000 или более строк, выйдите со статусом 3. В противном случае:
      • ,&TAB@(6&":)&.>@>:@i.@#: сгенерируйте числа для каждой строки, отформатируйте их в 6-значном столбце и добавьте a TABв конец каждой строки,
      • ,&.>]: добавьте каждый номер в начале каждой строки.
      • stdout@(,&LF)@;: затем вывести все, а затем доп LF.
  • exit: выйти с возвращенным значением этой функции

1

Рубин, 76 байт

Один байт для pфлага. Беги с ruby -p nl.rb.

BEGIN{x=$*.size-65}
exit 2if$*.size==x
exit 3if$.>999999
$_="%6d"%$.+?\t+$_

Аргументы stdin или file обрабатываются автоматически Ruby. Он уже завершается с кодом 1, если аргумент файла не существует. $.это количество строк, которые были прочитаны. $*это аргументы командной строки, и файлы выталкиваются при чтении файлов. pФлаг выполняет BEGINблок и оборачивает остальную часть программы внутри цикла , а-получает-печать, используя в $_качестве ввода / вывода.


В спецификации сказано, что вы должны обрабатывать первые 64 входа, если дано более 64, а не просто сдаваться в начале.
Андерс Касеорг

@AndersKaseorg исправлено.
Даниеро

1

Perl, 125 122 байта

@a=@ARGV;for(@a){$i++>63&&exit 2;($_ eq '-'or-e$_)or next;@ARGV=$_;while(<>){$c>1E6-2&&exit 3;printf"%5d\t%s",++$c,$_}say}

Это не соответствует спецификации, касающейся максимума в 64 аргумента и статуса выхода.
Андерс Касеорг

@AndersKaseorg Исправлено!
Gowtham

0

С 362 359

Просто для удовольствия. ;-) Работает с переводами строк LF или CR / LF.

#include<stdio.h>
#define R return
#define P printf(
e,t,l;void*f;r(){P"% 6d\t",++l);for(;(t=fgetc(f))^-1&&l<1000000;){if(ferror(f))R 1;P"%c",t);if(t==10)P"% 6d\t",++l);}P"\n");R l<1000000?0:3;}main(int c,char**v){e=c>65?2:0;for(++v;*v||c<2;++v){t=c<2||!strcmp(*v,"-")?f=stdin,0:!(f=fopen(*v,"rb"));if(t||(t=r()))e=!e|(e>t)?t:e;if(f&&f!=stdin)fclose(f);}R e;}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.