Ya Tuhan, penuh ruang!

42

Beberapa orang bersikeras menggunakan ruang untuk tabulasi dan indentasi.

Untuk tabulasi, itu tidak dapat disangkal salah. Menurut definisi, tabulator harus digunakan untuk tabulasi.

Bahkan untuk lekukan, tabulator secara obyektif lebih unggul:

  • Ada konsensus yang jelas di komunitas Stack Exchange.

  • Menggunakan satu ruang untuk lekukan secara visual tidak menyenangkan; menggunakan lebih dari satu itu boros.

    Seperti yang diketahui oleh semua pembuat kode golf , program harus sesingkat mungkin. Tidak hanya menghemat ruang hard disk, waktu kompilasi juga berkurang jika byte lebih sedikit harus diproses.

  • Dengan menyesuaikan lebar tab 1 , file yang sama terlihat berbeda di setiap komputer, sehingga semua orang dapat menggunakan lebar indentasi favoritnya tanpa mengubah file yang sebenarnya.

  • Semua editor teks yang baik menggunakan tabulator secara default (dan definisi).

  • Saya berkata begitu dan saya selalu benar!

Sayangnya, tidak semua orang mendengarkan alasan. Seseorang telah mengirimi Anda file yang melakukan kesalahan pada TM dan Anda harus memperbaikinya. Anda bisa melakukannya secara manual, tetapi akan ada yang lain.

Sudah cukup buruk bahwa spacer membuang-buang waktu berharga Anda, jadi Anda memutuskan untuk menulis program sesingkat mungkin untuk mengatasi masalah tersebut.

Tugas

Tulis program atau fungsi yang melakukan hal berikut:

  1. Baca satu string baik dari STDIN atau sebagai baris perintah atau argumen fungsi.

  2. Identifikasi semua lokasi di mana ruang telah digunakan untuk tabulasi atau indentasi.

    Jalankan spasi adalah lekukan jika terjadi di awal garis.

    Jalankan dua ruang atau lebih adalah tabulasi jika bukan lekukan.

    Sebuah tunggal ruang yang tidak lekukan mungkin atau mungkin tidak telah digunakan untuk tabulasi. Seperti yang diharapkan ketika Anda menggunakan karakter yang sama untuk tujuan yang berbeda, tidak ada cara mudah untuk mengatakannya. Karena itu, kami akan mengatakan bahwa ruang tersebut telah digunakan untuk kebingungan .

  3. Tentukan lebar tab 1 yang paling panjang memungkinkan semua ruang yang digunakan untuk tabulasi atau lekukan dapat diganti dengan tabulator, tanpa mengubah tampilan file.

    Jika input tidak mengandung tabulasi, atau lekukan, tidak mungkin untuk menentukan lebar tab. Dalam hal ini, lewati langkah selanjutnya.

  4. Dengan menggunakan lebar tab yang ditentukan sebelumnya, ganti semua ruang yang digunakan untuk tabulasi atau indentasi dengan tabulator.

    Juga, bila memungkinkan tanpa mengubah tampilan file, ganti semua ruang yang digunakan untuk kebingungan dengan tabulator. (Jika ragu, singkirkan ruang.)

  5. Kembalikan string yang dimodifikasi dari fungsi Anda atau cetak ke STDOUT.

Contohnya

  • Semua ruang

    a    bc   def  ghij
    

    adalah tabulasi.

    Setiap run of space mengisi string sebelumnya dari karakter non-space hingga lebar 5, sehingga lebar tab yang benar adalah 5 dan output yang benar 2 adalah

    a--->bc-->def->ghij
    
  • Dua ruang pertama dari

    ab  cde f
    ghi jk lm
    

    adalah tabulasi, yang lain kebingungan.

    Lebar tab yang benar adalah 4, jadi output yang benar adalah 2

    ab->cde>f
    ghi>jk lm
    

    Ruang terakhir tetap tidak tersentuh, karena akan diberikan sebagai dua ruang jika diganti oleh tabulator:

    ab->cde>f
    ghi>jk->lm
    
  • Semua kecuali satu ruang

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

    adalah lekukan, yang lainnya adalah kebingungan.

    Level indentasi adalah 0, 4 dan 8 spasi, sehingga lebar tab yang benar adalah 4 dan output yang benar adalah 2

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

    Ruang dalam ( )akan dirender sebagai tiga ruang jika diganti dengan tabulator, sehingga tetap tidak tersentuh.

  • Dua ruang pertama dari

      x yz w
    

    lekukan, yang lain kebingungan.

    Lebar tab yang tepat adalah 2 dan output yang benar 2 adalah

    ->x>yz w
    

    Ruang terakhir akan dirender sebagai dua ruang jika diganti dengan tabulator, sehingga tetap tidak tersentuh.

  • Dua ruang pertama dari

      xy   zw
    

    adalah lekukan, tiga lainnya adalah tabulasi.

    Hanya lebar tab 1 yang memungkinkan untuk menghilangkan semua spasi, sehingga output 2 yang benar adalah

    >>xy>>>zw
    
  • Semua ruang

    a b c d
    

    kebingungan.

    Tidak ada terpanjang mungkin lebar tab, sehingga benar keluaran 2 adalah

    a b c d
    

Aturan tambahan

  • Masukan akan seluruhnya terdiri dari karakter ASCII yang dapat dicetak dan umpan garis.

  • Anda dapat berasumsi bahwa terdapat paling banyak 100 baris teks dan paling banyak 100 karakter per baris.

  • Jika Anda memilih STDOUT untuk output, Anda dapat mencetak satu line linefeed tunggal.

  • Aturan standar berlaku.


1 Lebar tab didefinisikan sebagai jarak karakter antara dua penghentian tab berurutan , menggunakan font monospasi.
2 Panah seni ASCII mewakili tabulator Stack Exchange menolak untuk me-render dengan benar, di mana saya telah mengirimkan laporan bug. Output aktual harus mengandung tabulator aktual.

Dennis
sumber
9
+1 untuk akhirnya
menyelesaikan
2
programs should be as short as possibleSaya percaya saya telah menemukan saudara lelaki Arthur Whitney yang telah lama hilang !!
kirbyfan64sos
13
Tab adalah demonspawn tidak suci yang pantas untuk dirobek-robek dan kode ASCII mereka dipermalukan sampai ketiadaan jiwa yang tidak kompeten telah sepenuhnya ditumbuk menjadi bubur. Errr, maksud saya, +1, tantangan yang bagus, meskipun berbau penistaan. ;)
Gagang Pintu
1
Saya menangis setiap kali seorang rekan menambahkan tab di kode indentasi ruang indah saya. Kemudian saya menemukan CTRL + K + F di Visual Studio. Saya melakukannya setiap kali saya membuka file yang dimodifikasi. Hidup saya lebih baik sekarang.
Michael M.

Jawaban:

5

Pyth, 102 103 byte

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

Cobalah secara Online

Ide yang menarik, tetapi karena tab di input memecah konsep, tidak bisa digunakan.

Edit: Fixed bug. banyak terima kasih @aditsu

Brian Tuck
sumber
Ini crash pada "abc d"
aditsu
@aditsu omong kosong! Terima kasih untuk head-up. Saya perlu test case yang lebih baik: P
Brian Tuck
5

PowerShell, 414 409 byte

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"

Saya melanjutkan dan menggunakan baris baru alih-alih ;memungkinkan untuk membuat tampilan lebih mudah. Saya menggunakan akhiran baris unix sehingga seharusnya tidak mempengaruhi jumlah byte.

Cara Menjalankan

Salin kode ke SpaceMadness.ps1file, lalu masukkan input ke skrip. Saya akan menganggap file yang perlu dikonversi disebut taboo.txt:

Dari PowerShell:

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

Dari command prompt:

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

Saya mengujinya dengan PowerShell 5, tetapi harus bekerja pada 3 atau lebih tinggi.

Pengujian

Berikut ini adalah skrip PowerShell cepat yang berguna untuk menguji di atas:

[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"
    }
}

Letakkan ini di direktori yang sama dengan SpaceMadness.ps1, saya sebut ini tester.ps1, sebut seperti ini:

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

Anda mendapatkan idenya. Itu memuntahkan isi setiap file setelah konversi, dijalankan [RegEx]::Escape()yang terjadi untuk menghindari spasi dan tab sehingga sangat nyaman untuk melihat apa yang sebenarnya telah diubah.

Outputnya terlihat seperti ini (tetapi dengan warna):

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

Penjelasan

Baris pertama mendefinisikan faktor umum / fungsi pembagi terbesar gsejelas yang saya bisa mengelola, yang mengambil array (jumlah angka yang berubah-ubah) dan menghitung GCD secara rekursif menggunakan algoritma Euclidean .

Tujuan dari ini adalah untuk mengetahui "lebar tab paling panjang" dengan mengambil indeks + panjang setiap lekukan dan tabulasi seperti yang didefinisikan dalam pertanyaan, kemudian memasukkannya ke fungsi ini untuk mendapatkan GCD yang menurut saya adalah yang terbaik yang kami bisa lakukan untuk lebar tab. Panjang kebingungan akan selalu 1 sehingga tidak memberikan kontribusi apa pun untuk perhitungan ini.

$bmendefinisikan scriptblock karena mengganggu saya perlu memanggil potongan kode itu dua kali, jadi saya menyimpan beberapa byte dengan cara itu. Blok ini mengambil string (atau larik string) $ndan menjalankan regex di atasnya ( slsatau Select-String), mengembalikan objek yang cocok. Saya benar-benar mendapatkan lekukan dan tabulasi dalam satu di sini, yang benar-benar menyelamatkan saya pemrosesan ekstra dengan menangkapnya secara terpisah.

$ndigunakan untuk hal-hal yang berbeda di dalam dan di luar loop utama (benar-benar buruk, tetapi perlu di sini sehingga saya dapat menanamkannya $bdi scriptblock dan menggunakannya di dalam dan di luar loop tanpa param()deklarasi panjang dan argumen yang lewat.

$sditugaskan lebar tab, dengan memanggil $bblok pada array baris dalam file input, kemudian menjumlahkan indeks dan panjang setiap pertandingan, mengembalikan array jumlah sebagai argumen ke dalam fungsi GCD. Begitu $sjuga ukuran tab kita berhenti sekarang.

Kemudian loop dimulai. Kami mengulangi setiap baris dalam larik baris input $n. Hal pertama yang saya lakukan dalam loop adalah menetapkan $n(cakupan lokal) nilai baris saat ini karena alasan di atas.

$w mendapatkan nilai panggilan scriptblock hanya untuk baris saat ini (lekukan dan tabulasi untuk baris saat ini).

$cmendapatkan nilai yang sama, tetapi sebaliknya kami menemukan semua kebingungan .

Saya menjumlahkan $wdan $cyang merupakan array, memberi saya satu array dengan semua kecocokan ruang yang saya butuhkan, sortdalam urutan menurun dengan indeks, dan mulai mengulangi setiap pertandingan untuk baris saat ini.

Semacam itu penting. Awalnya saya menemukan cara sulit untuk mengganti bagian-bagian dari string berdasarkan nilai indeks adalah ide yang buruk ketika string pengganti lebih kecil dan mengubah panjang string! Indeks lainnya menjadi tidak valid. Jadi dengan memulai dengan indeks tertinggi di setiap baris, saya memastikan saya hanya membuat string lebih pendek dari ujung, dan bergerak mundur sehingga indeks selalu berfungsi.

Ke dalam loop ini, $xada dalam indeks pertandingan saat ini dan $lpanjang pertandingan saat ini. $ssebenarnya bisa 0dan itu menyebabkan sial sial oleh nol kesalahan jadi saya memeriksa validitasnya kemudian melakukan matematika.

The !(($x+$l)%$s)bit ada satu titik di mana saya memeriksa untuk melihat apakah sebuah kebingungan harus diganti dengan tab atau tidak. Jika indeks ditambah panjang dibagi dengan lebar tab tidak memiliki sisa, maka kami baik untuk mengganti pertandingan ini dengan tab (bahwa matematika akan selalu bekerja pada lekukan dan tabulasi , karena ukurannya adalah apa yang menentukan lebar tab memulai dengan).

Untuk penggantian, setiap iterasi loop cocok bekerja pada baris input saat ini, jadi itu adalah kumpulan pengganti kumulatif. Regex hanya mencari $lspasi yang didahului oleh $xkarakter apa pun. Kami menggantinya dengan $l/$skarakter tab (atau 1 jika angka itu di bawah nol).

Bagian ini (($l/$s),1-ge1)[0]adalah cara berbelit-belit yang mewah if (($l/$s) -lt 0) { 1 } else { $l/$s }atau sebagai alternatif [Math]::Max(1,($l/$s)). Itu membuat array $l/$sdan 1, kemudian menggunakan -ge 1untuk mengembalikan array yang hanya mengandung elemen yang lebih besar atau sama dengan satu, lalu mengambil elemen pertama. Muncul dalam beberapa byte lebih pendek dari [Math]::Maxversi.

Jadi setelah semua penggantian selesai, baris saat ini dikembalikan dari iterasi ForEach-Object( %), dan ketika semuanya dikembalikan (array garis tetap), itu -joindiedit dengan baris baru (karena kami membagi baris baru di awal).

Saya merasa seperti ada ruang untuk perbaikan di sini bahwa saya terlalu lelah untuk menangkap sekarang, tapi mungkin saya akan melihat sesuatu nanti.

Tab 4 lyfe

briantis
sumber
4

PHP - 278 210 byte

Fungsi ini bekerja dengan menguji setiap lebar tab, dimulai dengan nilai 100, panjang maksimal garis dan karenanya lebar tab maksimal.

Untuk setiap lebar tab, kami membagi setiap baris menjadi "blok" dengan panjang itu. Untuk masing-masing blok ini:

  • Jika, dengan menggabungkan karakter terakhir dari blok sebelumnya dengan blok ini, kami menemukan dua spasi berturut-turut di depan karakter, kami memiliki lekukan atau tabulasi yang tidak dapat diubah menjadi ruang tanpa mengubah tampilan; kami mencoba lebar tab berikutnya.
  • Kalau tidak, jika karakter terakhir adalah spasi, kita menghapus spasi di akhir blok, menambahkan tabulator dan menghafal semuanya.
  • Kalau tidak, kita hanya menghafal blok.

Setelah setiap blok garis dianalisis, kami menghafal umpan baris. Jika semua blok dari semua baris dianalisis dengan sukses, kami mengembalikan string yang telah kami hafal. Jika tidak, jika setiap lebar tab yang benar-benar positif telah dicoba, tidak ada tabulasi, atau lekukan, dan kami mengembalikan string asli.

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;}

Ini adalah versi yang tidak dikoleksi:

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;
}

Terima kasih khusus kepada DankMemes untuk menghemat 2 byte.

Lubang hitam
sumber
1
Anda dapat menyimpan 2 byte dengan menggunakan for($t=101;--$t;)alih-alihfor($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*

Cobalah online

Saya harus menjawab tantangan ini, karena saya harus melakukan bagian saya untuk membantu menyingkirkan dunia kekejian ini. Tab jelas lebih unggul, tetapi sayangnya, beberapa orang tidak bisa dibenarkan.

Penjelasan:

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
aditsu
sumber
1

PowerShell , 165 160 153 152 142 138 137 byte

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

Cobalah online!

Kurang bermain golf:

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
mazzy
sumber