Нумерація рядків - реалізуйте 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

@britishtea Це безперервно

1
Тож чи потрібно використовувати вузол, якщо ми хочемо щось подати в js? Або ми можемо використовувати аргументи функцій або prompt()для емуляції програмних аргументів і stdin?
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також об'єднається у випадку передачі декількох файлів, тому це офіційно вважається марним використанням кішки ;-). Натомість я думаю, що це спрацює: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якось (це навіть здається, що воно визнає "-"як stdin).
britishtea

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

Я підозрюю, що це різниця у версії Ruby. Я без проблем запускав зразок як на Ruby 2.0.0, так і на Ruby 2.1.2. Яку версію ви використовуєте?
britishtea

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",$.,$_'

Відійшов:

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()?! На жаль, це не робить його більш коротким. :)
Дейв J

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.@#: генеруйте числа для кожного рядка, відформатуйте їх у шестизначному стовпці та додайте а 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 або файлів обробляються автоматично Ruby. Він вже виходить із кодом 1, якщо аргумент файлу не існує. $.- кількість прочитаних рядків. $*- це аргументи командного рядка, і вони вискакують під час читання файлів. pПрапор виконує BEGINблок і обертає іншу частину програми всередині циклу , а-отримує-друк, використовуючи в $_якості введення / виведення.


Спеціалізація говорить, що вам слід обробити перші 64 входи, якщо їх дано більше 64, а не просто здавати на початку.
Anders Kaseorg

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

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 та стану виходу.
Anders Kaseorg

@AndersKaseorg Виправлено!
Gowtham

0

C, 362 359

Просто заради задоволення. ;-) Працює з LF або CR / LF linefeeds.

#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.