行号-实现nl


13

您的任务是实现一个类似于nlGNU核心实用程序中的命令行工具的程序。

禁止出现标准漏洞

您不得使用任何内置或外部函数,程序或实用程序来对文件或字符串的行进行编号,例如文件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退出。

如果给出的文件过多(超过64个),则以状态2退出。

如果输入太长(超过999999行),则以状态3退出。\

计分

这是代码高尔夫球-最短的程序胜出!

稍后我可能会为实施某些选项而增加奖金nl。目前没有奖金。


行号是连续的还是短的,它会为每个文件“重置”自身?
britishtea 2014年

@britishtea它是连续的

1
因此,如果我们想在js中提交某些内容,是否有必要使用node?还是可以使用函数args或prompt()模拟程序args和stdin?
DankMemes

1
二进制文件?编码?Unicode标记?
edc65

Answers:


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我学到了东西!
Sammitch 2014年

1
您可以用替换s=0;(($#>64))&&s=2s=$[2*($#>64)](($s==0))||使用((s))&&和替换为的if语句[ -f "$f" ]||s=1
丹尼斯2014年


2
awk如果传递了多个文件,也将串联在一起,因此,这正式算作cat ;-) 的无用用法。相反,我认为这会起作用:awk '...' $@
Digital Trauma 2014年

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是别名$<
Martin Ender 2014年

这是的别名ARGF,该别名也会从作为参数给出的其余文件中读取。我认为可以使用ARGF某种方式进一步降低它的性能(甚至可以认为"-"它是标准输入)。
britishtea

britishteanl:4:in在block in <main>': undefined method []'中来自britishteanl:2:in在each' from britishteanl:2:in <main>中的#<Enumerator:0x000006002980c8>(NoMethodError)-是什么问题?我将其运行为ruby britishteanl folder/filename

我怀疑这与Ruby版本有所不同。我已经在Ruby 2.0.0和Ruby 2.1.2上运行了该示例,而没有出现问题。您使用的是哪个版本?
britishtea 2014年

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包装-ewhile/ continue循环中给定的程序
  • BEGIN 代码将在(隐式)主要部分之前执行
  • -r如果文件不存在!-e,文件测试也会失败,并且默认为testing $_,在map { ... } @ARGV
  • $. 保留当前行号
  • 休息应该是不言自明的;)

很好的答案,欢迎使用编程难题和Code Golf!也许您可以进行编辑以添加有关代码工作方式的说明。
wizzwizz4 2015年

1

Python 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

我认为您的代码当前缺少-for sys.stdin。可能的解决方案可能是类似的fh=sys.stdin if f=='-' else open(f),然后再使用x=fh.readline()?!。不幸的是,它并没有使其更短。:)
Dave 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以上,则以status退出3。除此以外:
      • ,&TAB@(6&":)&.>@>:@i.@#:为每一行生成数字,在6位数的列中设置其格式,然后在TAB每个字符串的末尾添加a ,
      • ,&.>]:将每个数字添加到每行的开头。
      • stdout@(,&LF)@;:然后输出整个内容,然后输出多余的内容LF
  • exit:以该函数的返回值退出

1

Ruby,76个字节

p标志的一个字节。用运行ruby -p nl.rb

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

Ruby自动处理stdin或文件参数。如果文件参数不存在,它已经以代码1退出。$.是已读取的行数。$*是命令行参数,并且在读取文件时会弹出文件。该p标志执行该BEGIN块,并将程序的其余部分包装在while-gets-print循环内,$_用作输入/输出。


规范说,如果给出的输入数大于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个参数和退出状态的规范。
安德斯·卡塞格

@AndersKaseorg固定!
哥谭2015年

0

C,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;}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.