私の神、それはスペースでいっぱいです!


42

一部の人々は、タブとインデントにスペースを使用することを主張します。

集計については、それは間違いなく間違っています。定義により、集計にはタブレータを使用する必要があります。

インデントの場合でも、タブレーターは客観的に優れています。

  • Stack Exchangeコミュニティには明確なコンセンサスがあります。

  • インデントに単一のスペースを使用することは視覚的に不快です。複数を使用するのは無駄です。

    すべてのゴルファーが知っているように、プログラムはできるだけ短くする必要があります。ハードディスクのスペースを節約するだけでなく、処理するバイト数が少ない場合はコンパイル時間も短縮されます。

  • タブ幅1を調整することにより、同じファイルが各コンピューターで異なるように見えるため、誰もが実際のファイルを変更せずに好みのインデント幅を使用できます。

  • すべての優れたテキストエディターは、デフォルトで(および定義)タブレータを使用します。

  • 私はそう言います、私はいつも正しいです!

悲しいことに、誰もが理性に耳を傾けるわけではありません。誰かがあなたに間違ったTMをしているファイルを送ってきたので、あなたはそれを修正しなければなりません。手動で行うこともできますが、他にもあります。

スペーサーが貴重な時間を浪費するのは十分に悪いので、問題を処理するために可能な限り短いプログラムを書くことにします。

仕事

次のことを行うプログラムまたは関数を作成します。

  1. STDINから、またはコマンドラインまたは関数の引数として単一の文字列を読み取ります。

  2. 集計またはインデントにスペースが使用されているすべての場所を特定します。

    行の先頭にある場合、スペースの実行はインデントです。

    インデントでない場合、2つ以上のスペースの実行は集計です。

    単一インデントではありませんスペースはや集計のために使用されていない可能性があります。同じキャラクターを異なる目的に使用する場合、予想通り、簡単に伝える方法はありません。したがって、混乱のためにスペースが使用されたと言います。

  3. ファイルの外観を変更せずに、タブまたはインデントに使用されるすべてのスペースをタブレータで置き換えることができる、可能な限り長いタブ幅1を決定します。

    入力に表もインデントも含まれていない場合、タブ幅を決定することは不可能です。この場合、次の手順をスキップします。

  4. 以前に決定されたタブ幅を使用して、タブまたはインデントに使用されるすべてのスペースをタブレータに置き換えます。

    また、ファイルの外観を変更せずに可能な限り、混乱に使用されるすべてのスペースをタブレータに置き換えます。(疑わしい場合は、スペースを取り除きます。)

  5. 変更した文字列を関数から返すか、STDOUTに出力します。

  • すべてのスペース

    a    bc   def  ghij
    

    集計です。

    スペースを実行するたびに、前のスペース以外の文字列が5の幅になるまでパディングされるため、正しいタブ幅は5で、正しい出力2

    a--->bc-->def->ghij
    
  • 最初の2つのスペース

    ab  cde f
    ghi jk lm
    

    集計、その他の混乱です。

    正しいタブ幅は4なので、正しい出力2

    ab->cde>f
    ghi>jk lm
    

    最後のスペースは、タビュレーターで置き換えられると2つのスペースとしてレンダリングされるため、変更されません。

    ab->cde>f
    ghi>jk->lm
    
  • 1つを除くすべてのスペース

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

    インデント、他は混乱です。

    インデントレベルは0、4、および8スペースであるため、正しいタブ幅は4で、正しい出力2

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

    のスペースは( )、タビュレーターに置き換えると3つのスペースとしてレンダリングされるため、そのまま残ります。

  • 最初の2つのスペース

      x yz w
    

    インデント、他の混乱です。

    適切なタブ幅は2で、正しい出力2

    ->x>yz w
    

    最後のスペースは、タビュレーターに置き換えると2つのスペースとしてレンダリングされるため、そのまま残ります。

  • 最初の2つのスペース

      xy   zw
    

    インデント、他の3つは表です。

    タブ幅1のみですべてのスペースを削除できるため、正しい出力2

    >>xy>>>zw
    
  • すべてのスペース

    a b c d
    

    混乱しています。

    可能な限り長いタブ幅はないため、正しい出力2

    a b c d
    

追加のルール

  • 入力は、印刷可能なASCII文字と改行のみで構成されます。

  • 最大100行のテキストと、1行に最大100文字あると想定できます。

  • 出力にSTDOUTを選択した場合、単一の後続改行を印刷できます。

  • 標準の規則が適用されます。


1 タブの幅は、等幅フォントを使用して、2つの連続するタブストップ間の文字の距離として定義されます
2 ASCIIアートの矢印は、Stack Exchangeが適切にレンダリングすることを拒否するタブレータを表します。これについては、バグレポートを提出しました。実際の出力には、実際のタブレータが含まれている必要があります。


9
最後にこの無意味なスペース/タブの問題を休めるための+1:D
Geobits

2
programs should be as short as possibleアーサー・ホイットニーの長い間行方不明の兄弟を見つけたと思う!
kirbyfan64sos


13
タブは神聖な悪魔の出現であり、それらのビットがばらばらに裂かれ、ASCIIコードが無能な魂の欠如が徹底的にパルプになるまで汚されるに値します。Errr、つまり、+ 1、いい加減な挑戦、それは冒blの悪臭を放ちます。;)
ドアノブ

1
同僚が私のインデントされた美しいコードにタブを追加するたびに泣いていた。次に、Visual StudioでCtrl + K + Fを発見しました。変更したファイルを開くたびに実行します。私の人生は今では良くなっています。
マイケルM.

回答:


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 crap!ヘッズアップに感謝します。私はより良いテストケースを必要とする:P
ブライアン・タック

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迷惑なことに、そのコードを2回呼び出す必要があるため、スクリプトブロックを定義しています。このブロックは、文字列(または文字列の配列)$nを受け取り、その上で正規表現(slsまたはSelect-String)を実行して、一致オブジェクトを返します。私は実際にここでインデントと表の両方を取得していますが、それらを別々にキャプチャすることで余分な処理を本当に節約しました。

$nはメインループの内側と外側のさまざまなものに使用されます(本当に悪いですが、ここでは$bスクリプトブロックに埋め込み、長いparam()宣言と引数を渡すことなくループの内側と外側の両方で使用できるようにするために必要です。

$s$b入力ファイルの行の配列でブロックを呼び出し、次に各一致のインデックスと長さを合計し、合計の配列を引数としてGCD関数に返すことにより、タブ幅を割り当てます。だから、$s私たちのタブのサイズは、現在停止しています。

その後、ループが開始されます。入力行の配列の各行を反復処理します$n。ループで最初に行うことは$n、上記の理由で現在の行の値を(ローカルスコープに)割り当てることです。

$w 現在の行(現在の行のインデントと表)のみのscriptblock呼び出しの値を取得します。

$c同様の値を取得しますが、代わりにすべての混乱を見つけます。

合計し$w$cこれは配列です。必要なすべてのスペースの一致を持つ1つの配列をsortインデックスごとに降順で指定し、現在の行の各一致に対して反復を開始します。

ソートは重要です。置換文字列が小さく、文字列の長さが変わる場合、インデックス値に基づいて文字列の一部を置換することは悪い考えであるという難しい方法を早くから見つけました!他のインデックスは無効になります。そのため、各行の最高のインデックスから開始することで、文字列を最後から短くするだけにし、インデックスが常に機能するように後方に移動するようにします。

このループで$xは、は現在の一致のインデックスにあり、現在の一致$lの長さです。$s実際にはそうで0あり、それは厄介なゼロ除算エラーを引き起こすので、その妥当性をチェックしてから数学をしています

!(($x+$l)%$s)ビットは、私がどうかを確認し、単一の点があり、混乱がタブまたはないで交換する必要があります。タブでこの試合を置き換えるに行くための指標プラスタブ幅で割った長さは何の残りを持っていないなら、私たちはしている良い(数学を常にオンに動作することをくぼみ作表、その大きさは、タブの幅を決定するものであるため、で始まる)。

置換の場合、一致ループの各反復は入力の現在の行で機能するため、累積的な置換セットになります。正規表現は、任意の文字$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/$sand の配列を作成してから1-ge 11以上の要素のみを含む配列を返し、最初の要素を取得します。[Math]::Maxバージョンよりも数バイト短いです。

したがって、すべての置換が完了すると、現在の行がForEach-Object%)反復から返され、すべてが返されると(固定行の配列)、-join改行で編集されます(最初に改行で分割するため)。

ここには改善の余地があり、燃え尽きて今すぐに捕まえられない気がしますが、後で何かを見るかもしれません。

タブ4 lyfe


4

PHP- 278210バイト

この関数は、100の値、行の最大長、したがって最大タブ幅で始まる各タブ幅をテストすることにより機能します。

各タブ幅について、各行をその長さの「ブロック」に分割します。このブロックごとに:

  • 前のブロックの最後の文字とこのブロックを連結することにより、文字の前に2つの連続するスペースが見つかった場合、外観を変更せずにスペースに変換できないインデントまたは集計があります。次のタブ幅を試します。
  • それ以外の場合、最後の文字がスペースの場合、ブロックの最後のスペースを削除し、タブレータを追加して、すべてを記憶します。
  • それ以外の場合は、ブロックを記憶するだけです。

行の各ブロックが分析されると、改行を記憶します。すべての行のすべてのブロックが正常に分析された場合、記憶した文字列を返します。それ以外の場合、厳密に正のタブ幅がそれぞれ試行された場合、タブ付けもインデントも行われず、元の文字列が返されます。

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;)代わりに使用して2バイトを保存できますfor($t=100;$t;--$t)
DankMemes

4

CJam、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.