天哪,到处都是空间!


42

有些人坚持使用空格进行制表和缩进。

对于列表,这无疑是错误的。根据定义,制表符必须用于制表。

即使是缩进,制表符在客观上也很出色:

  • 在Stack Exchange社区中有明确的共识

  • 使用单个空格进行缩进在视觉上是不愉快的;多使用一个是浪费的。

    正如所有编码高尔夫球手都知道的那样,程序应尽可能短。如果需要处理的字节数更少,那么它不仅可以节省硬盘空间,还可以减少编译时间。

  • 通过调整制表符宽度1,同一文件在每台计算机上看起来都不同,因此每个人都可以使用自己喜欢的缩进宽度,而无需修改实际文件。

  • 默认情况下,所有好的文本编辑器都使用制表符(和定义)。

  • 我这么说,我永远是对的!

可悲的是,并非每个人都在听理性。有人给您发送了一个文件,该文件做错了TM,您必须对其进行修复。您可以手动进行操作,但是还会有其他操作。

间隔器浪费您的宝贵时间已经很糟糕了,因此您决定编写最短的程序来解决该问题。

任务

编写执行以下操作的程序或函数:

  1. 从STDIN或作为命令行或函数参数读取单个字符串。

  2. 标识所有用于制表或缩进的空格。

    如果在行的开头出现空格,则表示缩进

    如果不是缩进,则两个或多个空格的行程制表

    单一可以或可以不被使用,是不是缩进空间制表。不出所料,当您将同一字符用于不同目的时,没有简单的方法可以分辨。因此,我们将说该空间已被用于混淆

  3. 确定可能的最长制表符宽度1,用于制表符或缩进的所有空格都可以用制表符替换,而无需更改文件的外观。

    如果输入既不包含制表也不包含缩进,则无法确定制表符宽度。在这种情况下,请跳过下一步。

  4. 使用先前确定的制表符宽度,用制表符替换用于制表或缩进的所有空格。

    另外,只要有可能,而不会改变文件的外观,请使用制表符替换所有用于混淆的空格。(如有疑问,请排除空格。)

  5. 从函数中返回修改后的字符串或将其打印到STDOUT。

例子

  • 的所有空格

    a    bc   def  ghij
    

    制表。

    每次运行空格都会将前面的非空格字符字符串填充为5的宽度,因此正确的制表符宽度为5,正确的输出2

    a--->bc-->def->ghij
    
  • 的前两个空格

    ab  cde f
    ghi jk lm
    

    都是制表的,其他的很混乱。

    正确的制表符宽度为4,因此正确的输出2

    ab->cde>f
    ghi>jk lm
    

    最后一个空格保持不变,因为如果由制表符代替,它将被呈现为两个空格:

    ab->cde>f
    ghi>jk->lm
    
  • 除一个空格外的所有空格

    int
        main( )
        {
            puts("TABS!");
        }
    

    是缩进,另一个是混乱。

    缩进级别为0、4和8个空格,因此正确的制表符宽度为4,正确的输出2

    int
    --->main( )
    --->{
    --->--->puts("TABS!");
    --->}
    

    ( )如果用制表符代替,则其中的空间将被渲染为三个空间,因此保持不变。

  • 的前两个空格

      x yz w
    

    是缩进,其他是混乱。

    正确的制表符宽度为2,正确的输出2

    ->x>yz w
    

    如果用制表符代替,则最后一个空格将被渲染为两个空格,因此它保持不变。

  • 的前两个空格

      xy   zw
    

    是缩进,其他三个是列表。

    只有制表符宽度为1才能消除所有空格,因此正确的输出2

    >>xy>>>zw
    
  • 的所有空格

    a b c d
    

    混乱。

    没有最长的制表符宽度,因此正确的输出2

    a b c d
    

附加规则

  • 输入将完全由可打印的ASCII字符和换行符组成。

  • 您可以假定最多有100行文本,每行最多100个字符。

  • 如果选择STDOUT作为输出,则可以打印单个尾随换行符。

  • 适用标准规则。


1 制表符宽度定义为使用等距字体的两个连续的制表位之间的字符距离。
2 ASCII艺术箭头表示制表符Stack Exchange拒绝正确呈现,我为此提交了一个错误报告。实际输出必须包含实际的制表符。


9
+1终于解决了这个荒谬的空格/制表符问题:D
Geobits,2015年

2
programs should be as short as possible我相信我已经找到了亚瑟·惠特尼(Arthur Whitney)失散多年的兄弟!
kirbyfan64sos


13
制表符是邪恶的示威者,应将其位撕开,并将其ASCII码删除,直到将其无能的缺少灵魂彻底磨成浆为止。Errr,我的意思是+1,这是个不错的挑战,尽管这有点亵渎神明。;)
门把手

1
每当同事在我漂亮的空格缩进代码中添加一个标签时,我都会哭泣。然后,我在Visual Studio中发现了CTRL + K + F。每次打开修改后的文件时,我都会这样做。我的生活现在更好了。
Michael M.

Answers:


5

Pyth,102个 103字节

=T|u?<1hHiGeHGsKmtu++J+hHhGlhtH+tG]+HJ.b,YN-dk<1u+G?H1+1.)Gd]0]0cR\ .zZ8VKVNp?%eNT*hNd*/+tThNTC9p@N1)pb

在线尝试

有趣的主意,但是由于输入中的制表符破坏了该概念,因此不太实用。

编辑:修复了错误。非常感谢@aditsu


它在“ abc d”上崩溃
aditsu

@aditsu废话!感谢单挑。我需要更好的测试用例:P
Brian Tuck

5

PowerShell中,414个 409字节

function g($a){if($a.length-gt2){g $a[0],(g $a[1..100])}else{if(!$a[1]){$a[0]}else{g $a[1],($a[0]%$a[1])}}}{$a[0]}else{g $a[1],($a[0]%$a[1])}}}
$b={($n|sls '^ +|(?<!^)  +' -a).Matches}
$n=$input-split"`n"
$s=g(&$b|%{$_.Index+$_.Length})
($n|%{$n=$_
$w=@(&$b)
$c=($n|sls '(?<!^| ) (?! )'-a).Matches
$w+$c|sort index -d|%{$x=$_.Index
$l=$_.Length
if($s-and!(($x+$l)%$s)){$n=$n-replace"(?<=^.{$x}) {$l}",("`t"*(($l/$s),1-ge1)[0])}}
$n})-join"`n"

我继续使用换行符,而不是;尽可能地简化显示。我使用的是Unix行尾,因此它不应影响字节数。

如何执行

将代码复制到SpaceMadness.ps1文件中,然后将输入通过管道传递到脚本中。我将需要转换的文件称为taboo.txt

从PowerShell:

cat .\taboo.txt | .\SpaceMadness.ps1

在命令提示符下:

type .\taboo.txt | powershell.exe -File .\SpaceMadness.txt

我使用PowerShell 5对其进行了测试,但是它应该可以在3或更高版本上运行。

测试中

这是一个快速的PowerShell脚本,对于测试以上内容非常有用:

[CmdletBinding()]
param(
    [Parameter(
        Mandatory=$true,
        ValueFromPipeline=$true
    )]
    [System.IO.FileInfo[]]
    $File
)

Begin {
    $spaces = Join-Path $PSScriptRoot SpaceMadness.ps1
}

Process {
     $File | ForEach-Object {
        $ex = Join-Path $PSScriptRoot $_.Name 
        Write-Host $ex -ForegroundColor Green
        Write-Host ('='*40) -ForegroundColor Green
        (gc $ex -Raw | & $spaces)-split'\r?\n'|%{[regex]::Escape($_)} | Write-Host -ForegroundColor White -BackgroundColor Black
        Write-Host "`n"
    }
}

将其放在与相同的目录中SpaceMadness.ps1,我称之为tester.ps1,如下所示:

"C:\Source\SomeFileWithSpaces.cpp" | .\tester.ps1
.\tester.ps1 C:\file1.txt,C:\file2.txt
dir C:\Source\*.rb -Recurse | .\tester.ps1

你明白了。转换后,它吐出每个文件的内容,运行[RegEx]::Escape()时碰巧会转义空格和制表符,因此非常方便地查看实际更改的内容。

输出看起来像这样(但带有颜色):

C:\Scripts\Powershell\Golf\ex3.txt
========================================
int
\tmain\(\ \)
\t\{
\t\tputs\("TABS!"\);
\t}

说明

在第一行中g,我尽可能简洁地定义了最大的公因数/除数函数,该函数采用一个数组(任意数量的数字)并使用欧几里得算法递归计算GCD 。

这样做的目的是通过考虑问题中定义的每个缩进制表的索引+长度来找出“最大可能的制表符宽度” ,然后将其馈入该函数以获得GCD,我认为这是我们能做到的最好为制表符宽度做。混乱的长度将始终为1,因此对此计算没有任何帮助。

$b定义一个脚本块,因为烦人的我需要两次调用那段代码,所以我以这种方式节省了一些字节。该块获取字符串(或字符串数​​组)$n并对其(slsSelect-String)运行一个正则表达式,返回匹配对象。实际上,我在这里同时获得了缩进和制表,通过分别捕获它们,确实为我节省了额外的处理。

$n用于主循环内部和外部的不同事物(确实很糟糕,但是在这里很有必要,这样我就可以将其嵌入$b的脚本块中,并在循环内部和外部使用它而无需冗长的param()声明和传递参数。

$s通过$b在输入文件中的行数组上调用该块,然后对每个匹配项的索引和长度求和,然后将总和数组作为自变量返回到GCD函数中,从而获得制表符宽度。所以$s有我们的标签的大小,现在停止。

然后循环开始。我们遍历输入线数组中的每一行$n。由于$n上述原因,我在循环中要做的第一件事是分配(本地作用域)当前行的值。

$w 仅获取当前行的scriptblock调用的值(当前行的缩进和制表)。

$c得到类似的值,但是相反,我们发现了所有的困惑

我加起来$w$c它们的阵列,给我一个数组,我需要的空间匹配sort它由指数降序排列,并开始循环访问每一场比赛对于当前行。

排序很重要。早些时候,我发现了一种很难的方法,即当替换字符串较小并更改字符串的长度时,根据索引值替换字符串的部分是个坏主意!其他索引无效。因此,从每行的最高索引开始,我确保只使字符串从末尾变短,然后向后移动,以便索引始终有效。

进入此循环的$x是当前匹配项的索引,它是当前匹配项$l的长度。$s实际上可以是0,并且会导致讨厌的除零错误,因此我正在检查其有效性,然后进行数学计算。

!(($x+$l)%$s)位存在单点,我检查,看是否有混淆应该有标签或不可替代的。如果索引加上长度除以制表符宽度的余数没有余数,那么我们最好用制表符替换此匹配项(数学将始终适用于缩进制表符,因为它们的大小决定了制表符的宽度首先)。

对于替换,match循环的每个迭代都在输入的当前行上工作,因此它是一组替换的累积。正则表达式只查找以任何字符$l开头的空格$x。我们将其替换为$l/$s制表符(如果该数字小于零,则替换为1)。

这部分(($l/$s),1-ge1)[0]是一种复杂的说法if (($l/$s) -lt 0) { 1 } else { $l/$s }或另类的说法[Math]::Max(1,($l/$s))。它由$l/$s和组成一个数组1,然后用于-ge 1返回仅包含大于或等于1的元素的数组,然后获取第一个元素。它比[Math]::Max版本短了几个字节。

因此,所有替换操作完成后,当前行会从ForEach-Object%)迭代中返回,并且当所有替换项都返回(固定行数组)后,将-join使用换行符进行编辑(因为我们一开始就在换行符上进行了拆分)。

我觉得这里有待改进的地方,我现在已经精疲力尽,无法赶上,但也许以后再见。

Tabs 4 lyfe


4

PHP- 278210字节

该功能通过测试每个制表符的宽度来工作,该制表符的值从100开始,一行的最大长度以及最大制表符宽度开始。

对于每个制表符宽度,我们将每一行分成该长度的“块”。对于以下每个块:

  • 如果通过将前一个块的最后一个字符与此块连接起来,我们发现在一个字符之前有两个连续的空格,那么我们有一个缩进或制表符,不能改变其空格而不改变外观;我们尝试下一个制表符宽度。
  • 否则,如果最后一个字符是空格,我们将在块的末尾删除空格,添加一个制表符并记住整个内容。
  • 否则,我们只记住该块。

分析完一行的每个块后,我们便会记住一个换行。如果成功分析了所有行的所有块,我们将返回我们记住的字符串。否则,如果尝试了每个严格为正的制表符宽度,则既没有制表,也没有缩进,我们将返回原始字符串。

function($s){for($t=101;--$t;){$c='';foreach(split('
',$s)as$l){$e='';foreach(str_split($l,$t)as$b){if(ereg('  [^ ]',$e.$b))continue 3;$c.=($e=substr($b,-1))==' '?rtrim($b).'   ':$b;}$c.='
';}return$c;}return$s;}

这是非高尔夫版本:

function convertSpacesToTabs($string)
{
    for ($tabWidth = 100; $tabWidth > 0; --$tabWidth)
    {
        $convertedString = '';
        foreach (explode("\n", $string) as $line)
        {
            $lastCharacter = '';
            foreach (str_split($line, $tabWidth) as $block)
            {
                if (preg_match('#  [^ ]#', $lastCharacter.$block))
                {
                    continue 3;
                }

                $lastCharacter = substr($block, -1);
                if ($lastCharacter == ' ')
                {
                    $convertedString .= rtrim($block) ."\t";
                }
                else
                {
                    $convertedString .= $block;
                }
            }

            $convertedString .= "\n";
        }

        return $convertedString;
    }

    return $string;
}

特别感谢DankMemes节省了2个字节。


1
您可以使用for($t=101;--$t;)而不是for($t=100;$t;--$t)
DankMemes,2015年

4

果酱,112

qN/_' ff=:e`{0:X;{_0=X+:X+}%}%_:+{~;\(*},2f=0\+{{_@\%}h;}*:T;\.f{\~\{@;1$({;(T/)9c*}{\;T{T%}&S9c?}?}{1$-@><}?}N*

在线尝试

我必须应对这一挑战,因为我必须尽自己的力量帮助消除这种可恶的世界。制表符显然是优越的,但可悲的是,有些人是无法被推理的。

说明:

qN/          read input and split into lines
_            duplicate the array (saving one copy for later)
' ff=        replace each character in each line with 0/1 for non-space/space
:e`          RLE-encode each line (obtaining chunks of spaces/non-spaces)
{…}%         transform each line
  0:X;       set X=0
  {…}%       transform each chunk, which is a [length, 0/1] array
    _0=      copy the first element (the length)
    X+:X     increment X by it
    +        and append to the array; this is the end position for the chunk
_            duplicate the array (saving one copy for later)
:+           join the lines (putting all the chunks together in one array)
{…},         filter the array using the block to test each chunk
  ~          dump the chunk (length, 0/1, end) on the stack
  ;          discard the end position
  \(         bring the length to the top and decrement it
  *          multiply the 2 values (0/1 for non-space/space, and length-1)
              the result is non-zero (true) iff it's a chunk of at least 2 spaces
2f=          get all the end positions of the multiple-space chunks
0\+          prepend a 0 to deal with the empty array case
{…}*         fold the array using the block
  {_@\%}h;   calculate gcd of 2 numbers
:T;          save the resulting value (gcd of all numbers) in variable T
\            swap the 2 arrays we saved earlier (input lines and chunks)
.f{…}        for each chunk and its corresponding line
  \~         bring the chunk to the top and dump it on the stack
              (length, 0/1, end position)
  \          swap the end position with the 0/1 space indicator
  {…}        if 1 (space)
    @;       discard the line text
    1$(      copy the chunk length and decrement it
    {…}      if non-zero (multiple spaces)
      ;      discard the end position
      (T/)   divide the length by T, rounding up
      9c*    repeat a tab character that many times
    {…}      else (single space)
      \;     discard the length
      T{…}&  if T != 0
        T%   calculate the end position mod T
      S9c?   if non-zero, use a space, else use a tab
    ?        end if
  {…}        else (non-space)
    1$-      copy the length and subtract it from the end position
              to get the start position of the chunk
    @>       slice the line text beginning at the start position
    <        slice the result ending at the chunk length
              (this is the original chunk text)
  ?          end if
N*           join the processed lines using a newline separator

1

PowerShell中165个 160 153 152 142 138 137字节

param($s)@((0..99|%{$s-split"(
|..{0,$_})"-ne''-replace(' '*!$_*($s[0]-ne32)+' +$'),"`t"-join''})-notmatch'(?m)^ |\t '|sort{$_|% Le*})[0]

在线尝试!

少打高尔夫球:

param($spacedString)

$tabed = 0..99|%{
    $spacedString `
        -split "(\n|..{0,$_})" -ne '' `
        -replace (' '*!$_*($spacedString[0]-ne32)+' +$'),"`t" `
        -join ''
}

$validated = $tabed -notmatch '(?m)^ |\t '

$sorted = $validated|sort{$_|% Length}    # sort by a Length property

@($sorted)[0]  # $shortestProgram is an element with minimal length
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.