结束标签与太空战争


24

结束标签与太空战争

因此,关于是否使用制表符或空格来缩进/格式化代码存在很多争论。您可以通过采用一种极为疯狂的独特格式化方法来帮助大学解决争议。


您的工作是编写一个完整的程序或函数,以将所有选项卡扩展为四个空格。然后用“ /(n-这里有两颗星)/”替换n个前导空格。您将以任何合理的格式接收多行输入(每行新字符串的单个字符串数组,列数组等)。

样品输入被偷偷地偷了。请注意,由于制表符在SE上会自动扩展为四个空格,因此我将其表示为“ ^”字符,但您也必须处理制表符(代码点0x09)。所有的“ ^”字符都代表一个列表。

Calculate the value 256 and test if it's zero
If the interpreter errors on overflow this is where it'll happen
++++++++[>++++++++<-]>[<++++>-]
+<[>-<
    Not zero so multiply by 256 again to get 65536
    [>++++<-]>[<++++++++>-]<[>++++++++<-]
    +>[>
        # Print "32"
        ++++++++++[>+++++<-]>+.-.[-]<
    <[-]<->] <[>>
        # Print "16"
        +++++++[>+++++++<-]>.+++++.[-]<
<<-]] >[>
    # Print "8"
    ++++++++[>+++++++<-]>.[-]<
<-]<
# Print " bit cells\n"
+++++++++++[>+++>+++++++++>+++++++++>+<<<<-]>-.>-.+++++++.+++++++++++.<.
>>.++.+++++++..<-.>>-
Clean up used cells.
[[-]<]l
^this is preceded by a tab
^^two tabs
^^^three tabs etcetera! 

样品输出

Calculate the value 256 and test if it's zero
If the interpreter errors on overflow this is where it'll happen
++++++++[>++++++++<-]>[<++++>-]
+<[>-<
/**/Not zero so multiply by 256 again to get 65536
/**/[>++++<-]>[<++++++++>-]<[>++++++++<-]
/**/+>[>
/******/# Print "32"
/******/++++++++++[>+++++<-]>+.-.[-]<
/**/<[-]<->] <[>>
/******/# Print "16"
/******/+++++++[>+++++++<-]>.+++++.[-]<
<<-]] >[>
/**/# Print "8"
/**/++++++++[>+++++++<-]>.[-]<
<-]<
# Print " bit cells\n"
+++++++++++[>+++>+++++++++>+++++++++>+<<<<-]>-.>-.+++++++.+++++++++++.<.
>>.++.+++++++..<-.>>-
Clean up used cells.
[[-]<]l
/**/this is preceded by a tab
/******/two tabs
/**********/three tabs etcetera! 

因为大学需要空间来下载Vim和Emacs,所以只允许很少的代码存储空间。因此,这是,最短的代码获胜。您可能会假设输入格式正确,并且少于四个空格的行(替换制表符后)可能会导致行为不确定。

免责声明

这种“出色”的格式化策略是由Geobits提供的,并且在他的允许下得以复制。在产生此挑战期间,没有程序员受到伤害。


1
制表符只会出现在行的开头(即缩进)吗?行可以有混合缩进(制表符+空格)吗?
林恩

20
有人请提交用空白写的答案。
GuitarPicker

2
我们应该考虑以开头的行/*,还是可以将其假定为不是“格式正确的输入”?C ++源文件将是一个更好的测试,因为它的多行注释/* */可能会破坏一些答案,这些答案用an替换开头和结尾的前导空格/,然后用填充空格*
seshoumara '16

1
战争已经结束:medium.com/@hoffa/…(除非您显然使用C语言编程。)
烧杯

1
@RohanJhunjhunwala现在,我再次问我的第一个问题,因为它与可编译代码无关。想象一下相同的/* */C ++代码,但是这次是在行的开头。根据您的规范,应保留原样。这里的陷阱是,并且已经发现了错误的答案,正则表达式(比如说)/\** /用星号填充//之间的空格会使该行变为/***/。我也看到了这种转换/*//*/。我认为两者都不正确。
seshoumara

Answers:


2

V21,20字节

Íô/    
Î^hr/hv0r*r/

在线尝试!

从字面上看,这只是我的vim答案的直接移植。显着差异:

  • Í命令(全局替换)自动填充该/g标志,该标志节省了两个字节

  • ô 等同于 \t

  • Î是的助记符:%norm,它也填充:%norm按键之间的必要空间。

  • 末尾的回车符被隐式添加。


27

Vim,37,34,33,32字节

:%s/\t/    /g|%norm ^hr/hv0r*r/

在线尝试!

注意,这要求在vim中有一个尾随回车符(输入),尽管在线解释器中不需要。

之所以使用V解释器,是因为它向后兼容。一个非常简单的解决方案。

这是一个gif,可让您实时查看解决方案。这使用的是一个稍旧的版本,我添加了一些额外的击键来使其运行缓慢,因此您可以看到会发生什么:

在此处输入图片说明

这是它如何工作的解释:

:%s/\t/    /g           "Replace every tab with 4 spaces
|                       "AND
%norm                   "On every line:
      ^                 "  Move to the first non-whitespace char
       h                "  Move one character to the left. If there is none, the command will end here.
         r/             "  Replace it with a slash
           h            "  Move to the left
            v0          "  Visually select everything until the first column
              r*        "  Replace this selection with asterisks
                r/      "  Replace the first character with a slash

我本来要+1的,g但后来您编辑为不使用g:/ +1:D
Downgoat

@downgoat哈哈,谢谢!实际上,我为该版本感到骄傲,:g因为它没有使用一个鲜为人知的功能:norm如果^F<space>失败,该命令将被取消。因此:%norm ^F<space>foo,本质上与:g/^ /norm foo有趣的Vim骇客相同。:D
DJMcMayhem

呵呵,我以为^ F是用来给屏幕加上位置的。里面有不同的行为norm吗?
Downgoat

1
@downgoat哈哈,不^F,不是<C-f>傻Vim按键符号。在这种情况下,它是^,跳到第一个非空白char,然后F<space>找到光标后面的第一个空格。
DJMcMayhem

哦,那现在变得更加有意义> _>
Downgoat '16

11

Perl,41个字节

s,␉,    ,g;s,^  ( +),/@{[$1=~y| |*|r]}/,

使用-p标志运行,如下所示:

perl -pe 's,␉,    ,g;s,^  ( +),/@{[$1=~y| |*|r]}/,'
#     ↑   └───────────────────┬───────────────────┘
#     1 byte               40 bytes

标签替换(在Bash中,尝试键入Control-V Tab。)


1
的方式perl取代当场即反向引用,我想sed了这一点。
seshoumara '16

7

Cheddar60 57 56字节

@Conor O'Brien节省了3个字节

@.sub(/\t/g," "*4).sub(/^ +/gm,i->"/"+"*"*(i.len-2)+"/")

我希望Cheddar具有更好的字符串格式。

在线尝试!

说明

这是一个功能。@是一个表示功能的属性(例如ruby的&:),可让您执行以下操作:`ar.map(@。head(-1))

@                      // Input
 .sub( /\t/g, " "*4)   // Replace tabs with four spaces
 .sub(
   /^ +/gm,            // Regex matches leading spaces
   i ->                // i is the matched leading spaces
     "/"+              // The / at the beginning
     "*"*(i.len-2)+    // Repeat *s i-2 times
     "/"                // The / at the end
 )

如果您不熟悉regex,则:

/^ +/gm

这基本上在每()行()的开始()处匹配一个或多个(+)空格()。^gm


文字标签在切达正则表达式中工作吗?同样,/^ +/作为正则表达式就足够了,因为我们可以假定前导空格的长度至少为4。
科纳·奥布莱恩

@ ConorO'Brien我相信他们可以,但是我还没有测试过
Downgoat

应该在转换之前替换这些选项卡。
Conor O'Brien

@ ConorO'Brien哦> _>我原来是这样的,然后我更改了
Downgoat

6

Mathematica,97个字节

a=StringReplace;a[a[#,"\t"->"    "],StartOfLine~~b:" "..:>"/"<>Table["*",StringLength@b-2]<>"/"]&

匿名函数。将字符串作为输入并返回字符串作为输出。


5

Python 3,124个字节

使用良好的正则表达式。

import re
lambda I:re.sub('^\s*(?m)',lambda m:'/'+'*'*len(m.group()[:-2])+'/',re.sub('\t+',lambda g:' '*4*len(g.group()),I))

伊迪恩!


4

Java的 210 207个字节

这是天真的实现的参考解决方案。

void a(String[]a){for(String s:a){s=s.replaceAll("\t", "    ");String x,y="";int j,i=s.length()-(x=s.replaceAll("^\\s+", "")).length();if(i>3){y="/";for(j=0;j++<i-1;)y+="*";y+="/";}System.out.println(y+x);}}

6
Vim:37个字节,Cheddar:65个字节,JavaScript:75个字节,然后Java在210个字节:P为什么我不感到惊讶
Downgoat

1
Java中非常简洁的代码:P
Rohan Jhunjhunwala

您可以更改最后一个for循环以保存1个字节:for(int j=0;++j<i-1;)。此外,您可以删除int before j,然后将其放在已经存在的int之后:int i=s.length()-(x=s.replaceAll("^\\s+", "")).length(),j;
Kevin Cruijssen 2016年

使用(a)-> {...}来剃除字节不是lambda吗?
bunyaCloven

至少它仍然是可读的,不需要进一步的评论:O)
勒内·

3

JavaScript ES6,75个字节

s=>s.replace(/\t/g,"    ").replace(/^ +/gm,k=>`/${"*".repeat(k.length-2)}/`)

\t代码中的文字标签替换。


3

Java中,185个 184 167 152字节

S->S.map(s->{s=s.replace("\t","    ");String t=s.replaceAll("^ +","");int n=s.length()-t.length();if(n>3){s="/";for(;n-->2;)s+="*";s+="/"+t;}return s;})

鉴于在最初的文章中给出的字符串数组定义非常松散,我使用Stream<String>它可以节省一些后续的字节。

我使用了与RI不同的技术来实现相同的目标。算法本身相当相同。

测试和取消高尔夫

import java.util.Arrays;
import java.util.stream.Stream;

public class Main {

  public static void main(String[] args) {
    StringStreamTransformer sst = lines -> lines.map(line -> {
      line = line.replace("\t","    ");
      String trimmed = line.replaceAll("^ +", "");
      int startingSpaces = line.length() - trimmed.length();
      if (startingSpaces > 3) {
        line = "/";
        for(;startingSpaces > 2; startingSpaces--) {
          line += "*";
        }
        line += "/" + trimmed;
      }
      return line;
    });


    Stream<String> lines = Arrays.stream(new String[]{
      "lots of spaces and tabs after\t\t    \t\t         \t\t\t\t\t",
      "no space",
      " 1 space",
      "  2 spaces",
      "   3 spaces",
      "    4 spaces",
      "     5 spaces",
      "      6 spaces",
      "       7 spaces",
      "        8 spaces",
      "\t1 tab",
      "\t\t2 tabs",
      "\t\t\t3 tabs"
    });
    sst.map(lines).map(s -> s.replace(" ", ".").replace("\t","-")).forEach(System.out::println);


  }
}

2

视网膜,25字节

\t应与实际的制表符(0×09)来代替。

\t
4$* 
%`^  ( +)
/$.1$**/

在线尝试!

说明

\t
4$* 

用四个空格替换每个选项卡。

%`^  ( +)
/$.1$**/

分别变换每一行(%)通过匹配2+N在该行的开头的空间,并用替换它/.../,其中...N的副本*



2

SED(56 + 1 for -r)57

s/⇥/    /g;tr;:r;s,^ ( *) ,/\1/,;T;:l;s,^(/\**) ,\1*,;tl

选项卡在哪里
1.用空格替换选项卡。
2.用替换第一个和最后一个前导空格/
3.将0 /*+ 之后的第一个空格替换为a,*直到没有匹配项为止。


由于已指定sed,因此代码周围不需要单引号,就像从其他sed答案中删除-r''一样,因为您可以将脚本视为存储在运行的源文件中-f。像n或r这样使用的任何额外标志都应计为一个字节。因此,这里节省了2个字节。
seshoumara'9

这就是我的想法,但我想确定。谢谢。
莱利2016年

;t命令后要么是没有必要的。至于代码本身,您需要在第三个s命令的开头加上一个^ ,否则将类似“ 3/5”的输入转换为“ 3 / * 5”。在第一个s命令中,您实际上在那里有一个选项卡,但是没有正确显示该选项卡并且具有误导性,因此请使用\ t或在其后指定char是一个选项卡。
seshoumara'9

@seshoumara谢谢,我正尝试通过手机发布信息……这不是最简单的事情。
莱利

我认为我花了更多的时间来编辑这个答案,而不是其他所有答案的总和。谢谢您的帮助!
莱利

1

大学应该考虑允许在的Emacs Lisp程序多一点空间(或默认为tabifyuntabify单独的),因为他们得到更详细的比Java。它还应密切注意标识大小小于4或碰巧以某种非C语言编写代码的学生(或教师)。

以下解决方案有206个字节

(lambda (b e)(let((tab-width 4))(untabify b e)(goto-char b)(while(re-search-forward"^ +"e t)(replace-match(format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2)))))))))

假设tab-width不需要明确设置,我们可以保存其中的20个。

(lambda(b e)(untabify b e)(goto-char b)(while(re-search-forward"^ +"e t)(replace-match(format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2))))))))

非高尔夫版本看起来像这样

(defun end-tab-war (beg end)
  (let ((tab-width 4))
    (untabify beg end)
    (goto-char beg)
    (while (re-search-forward "^ +" end t)
      (replace-match
       (format
        "/%s/"
        (apply 'concat
               (mapcar (lambda(x) "*")
                       (number-sequence 1
                                        (- (length (match-string 0))
                                           2)))))))))

我们首先untabify进入该地区,然后再跳到起点。然后,虽然我们在行的开头看到空白,但是我们将其替换为与该空白一样长的注释。确切地说,要插入的注释是由

 (format"/%s/"(apply'concat(mapcar(lambda(x)"*")(number-sequence 1(-(length(match-string 0))2)))))

它本身占用97个字节。高度赞赏一种较短的解决方案,它可以复制一些字符串n次。


1

Ruby,52 47 +1(p标志)= 48字节

编辑:节省了整个5个字节,这要归功于Value Ink

ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'

1
您可以使用该p标志来利用(g)sub修改$_并因此更改打印值的事实吗?ruby -pe 'gsub ?\t," "*4;sub(/^ +/){?/+?**($&.size-2)+?/}'
Value Ink

谢谢,我不知道(g)sub没有爆炸声可以$_在这里修改。
michau '16

1

GNU sed,66 64 +1(r标志)= 65字节

编辑:感谢赖利的建议少1个字节。

s/\t/    /g
s,^ ( *) ,/\1\n,
:
s,^(/\**) ( *\n),\1*\2,
t
s,\n,/,

执行: sed -rf formatter.sed input_file

之所以要用\n该行的其余文本与前导空格分隔开来,是因为否则,以这样的注释开头的C ++行将被更简单的第4行(甚至)/* */变成。由于sed为每个输入行执行脚本,因此读取时不会在模式空间中引入任何内容。/*****/s,^(/\**) ,\1*,s,^(/\**) ( */),\1*\2,\n


您可以节省一个字节,/直到替换\n。这省去了您在第4行中匹配的
Riley

@Riley好收获。更新了代码。
seshoumara

您可以通过\t使用制表符替换来保存另一个。
莱利2016年

@Riley是的,但是由于它不会在此处打印为选项卡,因此我对此表示怀疑。对于将来的sed答案(字节数更具竞争力),我会牢记这一点。
seshoumara
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.