Tanrım, boşluklarla dolu!


42

Bazı insanlar, tablo ve girinti için boşluk kullanmakta ısrar ediyor.

Tablolama için bu tartışmasız yanlıştır. Tanım olarak, çizelgeleme çizelgeleme için kullanılmalıdır.

Girinti için bile, tabülatörler nesnel olarak üstündür:

  • Stack Exchange topluluğunda açık bir fikir birliği var .

  • Girinti için tek bir boşluk kullanmak görsel olarak rahatsız edicidir; birden fazla kullanmak israftır.

    Tüm golf oyuncularının bildiği gibi, programlar mümkün olduğu kadar kısa olmalıdır. Yalnızca sabit disk alanı kazanmakla kalmaz, daha az bayt işlenmesi gerektiğinde derleme süreleri de kısalır.

  • Sekme genişliğini 1 ayarlayarak, aynı dosya her bilgisayarda farklı görünür, böylece herkes asıl dosyayı değiştirmeden en sevdiği girinti genişliğini kullanabilir.

  • Tüm iyi metin düzenleyicileri, varsayılan olarak (ve tanım) tabulatörler kullanır.

  • Öyle söylüyorum ve her zaman haklıyım!

Ne yazık ki, herkes mantıklı değil. Birisi size yanlış yapan bir dosya gönderdi, TM ve onu düzeltmelisiniz. Sadece manuel olarak yapabilirsin, ama başkaları da olacak.

Ara parçaların değerli zamanınızı boşa harcayacağı kadar kötü, bu nedenle sorunu çözmek için mümkün olan en kısa programı yazmaya karar veriyorsunuz.

Görev

Aşağıdakileri yapan bir program veya işlev yazın:

  1. Tek bir dize STDIN'den veya komut satırı veya işlev argümanı olarak okuyun.

  2. Boşlukların tablo veya girinti için kullanıldığı tüm konumları belirleyin.

    Bir satırın başlangıcında gerçekleşirse, boşluklar girintisidir .

    İki veya daha fazla boşluğun çalışması, girintisiz değilse , tablolamadır .

    Girintisiz tek bir boşluk, tablolama için kullanılmış olabilir veya olmayabilir. Aynı karakteri farklı amaçlar için kullandığınızda beklendiği gibi, söylemesi kolay bir yol yoktur. Bu nedenle, alanın karışıklık için kullanıldığını söyleyeceğiz .

  3. Tablolama veya girinti için kullanılan tüm alanların, dosya görünümünü değiştirmeden tablolayıcılarla değiştirilebileceği mümkün olan en uzun sekme genişliğini 1 belirleyin .

    Girdide ne tablo ne de girintiler varsa, sekme genişliğini belirlemek mümkün değildir. Bu durumda, bir sonraki adımı atlayın.

  4. Önceden belirlenmiş sekme genişliğini kullanarak, çizelgeleme veya girintiler için kullanılan tüm boşlukları çizelgeleyicilerle değiştirin.

    Ayrıca, mümkün olduğunda dosyanın görünümünü değiştirmeden, tabloları karıştırmak için kullanılan tüm boşlukları değiştirin. (Şüpheniz varsa, boşluklardan kurtulun.)

  5. Değiştirilen dizgiyi fonksiyonunuzdan döndürün veya STDOUT'a yazdırın.

Örnekler

  • Tüm alanları

    a    bc   def  ghij
    

    tablo vardır.

    Alanlarda pedlerin her çalışma 5 bir genişliğe boşluk olmayan karakter önceki dizi, doğru sekme genişliği 5 ve böylece doğru çıkış 2 olduğu

    a--->bc-->def->ghij
    
  • İlk iki alanı

    ab  cde f
    ghi jk lm
    

    tabülasyon, diğerleri karışıklıktır.

    Doğru çıkış, böylece doğru sekme genişliği 4 olduğu 2 olduğu

    ab->cde>f
    ghi>jk lm
    

    Son boşluğa dokunulmaz, çünkü bir tabülatör tarafından değiştirilirse iki boşluğa dönüşür:

    ab->cde>f
    ghi>jk->lm
    
  • Hepsi bir boşluk hariç

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

    girinti, diğeri karışıklık.

    Doğru sekme genişliği 4 ve doğru çıkış böylece girinti seviyeleri 0 ila 4 ve 8 boşluklar vardır 2 olduğu

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

    Boşluk içinde ( )bir tabulator ile ikame eğer dokunulmaz, böylece üç boşluk olarak giderek azalacaktır.

  • İlk iki alanı

      x yz w
    

    girinti, diğerleri karışıklık.

    Uygun sekme genişliği 2'dir ve doğru çıkış 2 olduğu

    ->x>yz w
    

    Son tablo, bir tabülatör tarafından değiştirilirse iki alan olarak gösterilecektir, bu yüzden dokunulmadan kalır.

  • İlk iki alanı

      xy   zw
    

    girinti, diğer üç tablolama.

    Doğru çıkış, böylece sadece 1 izinlerin bir sekme genişliği, tüm boşlukları ortadan kaldırmak için 2 olduğu

    >>xy>>>zw
    
  • Tüm alanları

    a b c d
    

    kafa karışıklığı vardır.

    Doğru çıktı hiçbir olası en uzun sekme genişliği vardır 2 olduğu

    a b c d
    

Ek kurallar

  • Girdi tamamen yazdırılabilir ASCII karakterlerinden ve satır beslemelerinden oluşacaktır.

  • Satır başına en fazla 100 satır ve en fazla 100 karakter olduğunu varsayabilirsiniz.

  • Çıktı için STDOUT seçtiyseniz, tek bir izleyen satır besleme yazdırabilirsiniz.

  • Standart kuralları geçerlidir.


1 Sekme genişliği, monospaced bir font kullanarak, art arda iki sekme durağı arasındaki karakter cinsinden mesafe olarak tanımlanır .
2 ASCII resim okları, Stack Exchange'in düzgün bir şekilde oluşturmayı reddettiği tabulatörleri temsil eder ve bunun için bir hata raporu gönderdim. Gerçek çıktı gerçek tabloları içermelidir.


9
Sonunda bu saçma sapan boşluk / sekme sorununu koymak için +1: D
Geobits

2
programs should be as short as possibleArthur Whitney'in uzun zamandır kayıp olan kardeşini bulduğuma inanıyorum !!
kirbyfan64sos


13
Bitleri parçalara ayırmayı hak eden kutsal göstergeler ve ASCII kodları, yetersiz ruh eksikliği iyice küspe olana kadar bozulmuştur. Errr, demek istediğim, +1, küfür korkusu olsa da iyi bir meydan okuma. ;)
Doorknob

1
Her zaman bir meslektaşım güzel mekan girintili koduma bir sekme eklediğinde ağlıyordum. Sonra Visual Studio'da CTRL + K + F'yi keşfettim. Her değiştirdiğim dosyayı açtığımda yapıyorum. Hayatım şimdi daha iyi.
Michael M.

Yanıtlar:


5

Pyth, 102 103 bayt

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

Çevrimiçi Deneyin

İlginç bir fikir, ancak girdideki sekmeler kavramı kırdığı için çok kullanışlı değil.

Düzenleme: Sabit hata. çok teşekkürler @aditsu


"Abc d" çöküyor
aditsu 08:15

@aditsu boku! Heads-up için teşekkürler. Daha iyi test durumlarına ihtiyacım var: P
Brian Tuck

5

PowerShell, 414 409 bayt

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"

İleriye çıktım ve ;gösterimi kolaylaştırmak için mümkün olduğunca yeni çizgiler kullandım . Unix satır sonlarını kullanıyorum, bu yüzden bayt sayısını etkilememelidir.

Nasıl Yürütülür

Kodu SpaceMadness.ps1dosyaya kopyalayın , ardından girişi komut dosyasına aktarın. Dönüştürülmesi gereken dosyanın çağrıldığını varsayacağım taboo.txt:

PowerShell'den:

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

Komut isteminden:

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

PowerShell 5 ile test ettim, ancak 3 veya daha yüksek sürümlerde çalışmalıdır.

Test yapmak

İşte yukarıdakileri test etmek için yararlı olan hızlı bir PowerShell betiği:

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

Şunu da aynı dizine koyun SpaceMadness.ps1, buna ben diyorum, şöyle diyorum tester.ps1:

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

Kaptın bu işi. Dönüştürme işleminden sonra her bir dosyanın içeriğini yayar, bu [RegEx]::Escape()sayede hem boşluktan hem de sekmelerden kaçınır, bu yüzden gerçekte neyin değiştirildiğini görmek gerçekten uygun olur.

Çıktı şöyle görünür (ancak renklerle):

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

açıklama

İlk satır, en büyük ortak faktör / bölen işlevini g, yönetebildiğim kadar kısa sürede, bir dizi (rastgele sayı sayısı) alan ve Öklid algoritmasını kullanarak tekrarlayan bir şekilde GCD'yi hesaplayan en büyük faktör / bölen işlevini tanımlar .

Bunun amacı, her girintinin ve çizelgenin indeks + uzunluğunu , soruda tanımlandığı gibi indeks + uzunluğunu alarak "mümkün olan en uzun çıkıntı genişliğini" bulmak , sonra en iyi olanı düşündüğüm GCD'yi elde etmek için bu işleve beslemektir. sekme genişliği için yapın. Bir kargaşanın uzunluğu her zaman 1 olacak, bu yüzden bu hesaplamaya hiçbir şey katkısı olmayacak.

$bBir scriptblock'u tanımlar, çünkü can sıkıcı bir şekilde bu kod parçasını iki kez çağırmam gerekir, bu yüzden bazı baytları bu şekilde kaydederim. Bu blok, dizeyi (veya dizeleri dizisini) alır $nve eşleme nesnelerini döndürerek üzerinde bir regex ( slsveya Select-String) kullanır. Aslında burada hem girintileri hem de tabloları alıyorum, bu da onları ayrı ayrı yakalayarak ekstra işlem yapmamı sağladı.

$nAna döngünün içindeki ve dışındaki farklı şeyler için kullanılır (gerçekten kötü, ama burada gerekli, böylece onu $bkomut dosyası bloğunun içine gömebilirim ve bunu uzun bir param()bildirimde bulunmadan ve tartışmalar olmadan döngü içinde ve dışında kullanabilirim) .

$s$bgiriş dosyasındaki satır dizisindeki bloğu çağırarak , ardından her eşleşmenin indeksini ve uzunluğunu toplayarak, toplamların dizisini GCD işlevine argüman olarak döndürerek , sekme genişliği atanır . Şimdi $ssekmemizin büyüklüğü durdu.

Sonra döngü başlar. Giriş çizgileri dizisindeki her satırın üzerinde yineliyoruz $n. Döngü içinde yaptığım ilk şey $n, yukarıdaki nedenden dolayı geçerli çizginin değerini atamaktır (yerel kapsam).

$w yalnızca geçerli satır için scriptblock çağrısının değerini alır (geçerli satırın girintileri ve tabloları).

$cbenzer bir değer alır, ancak bunun yerine tüm kafa karışıklıklarını buluruz .

Ben kadar ekleyin $wve $cbana, gerek uzay maçları tüm bir dizi vererek, diziler hangi sortdizine göre azalan sırada onu ve mevcut hat için her maçın üzerinde iterating başlar.

Sıralama önemlidir. Önceleri, bir dizgenin bölümlerini indeks değerlerine göre değiştirmenin, yeni dizgenin daha küçük olması ve dizenin uzunluğunu değiştirmesinin kötü bir fikir olduğunu öğrendim! Diğer endeksler geçersiz hale gelir. Bu yüzden, her satırdaki en yüksek dizinlerden başlayarak, dizgiyi yalnızca en baştan daha kısa yaptığımdan ve geriye doğru hareket ettiğimden emin olarak dizinler daima çalışır.

Bu döngünün içine $x, geçerli eşleşmenin dizininde ve geçerli eşleşmenin $luzunluğundadır. $saslında olabilir 0ve bu sinir bozucu bir bölünmeye neden olarak sıfır hataya neden olur, bu yüzden geçerliliğini kontrol edip matematik işlemlerini yapıyorum.

Buradaki !(($x+$l)%$s)bit, karışıklığın sekmeyle değiştirilip değiştirilmeyeceğini görmek için kontrol ettiğim tek nokta . İndeks artı sekme genişliğinin bölünmüş uzunluğu kalanı yoksa, bu eşleşmeyi bir sekmeyle değiştirmeye devam edeceğiz (bu matematik her zaman girintilerde ve çizelgelerde çalışacaktır , çünkü boyutları sekme genişliğini belirleyen boyuttur. ile başlamak için).

Değiştirme için, eşleştirme döngüsünün her yinelemesi girişin geçerli satırında çalışır, bu nedenle kümülatif bir değiştirme kümesidir. Düzenli ifade sadece herhangi bir karakterden $lönce gelen boşlukları arar $x. $l/$sSekme karakterleriyle değiştiririz (veya bu sayı sıfırın altındaysa 1).

Bu kısım (($l/$s),1-ge1)[0], süslü if (($l/$s) -lt 0) { 1 } else { $l/$s }ya da alternatif bir şekilde söylenmiş bir yöntemdir [Math]::Max(1,($l/$s)). Bir dizi yapar $l/$sve 1sonra -ge 1yalnızca bir öğeye eşit veya daha büyük olan öğeleri içeren bir dizi döndürmek için kullanır , ardından ilk öğeyi alır. [Math]::MaxSürümünden daha kısa bir kaç bayt gelir .

Bu nedenle, tüm değiştirmeler yapıldıktan sonra, geçerli satır ForEach-Object( %) yinelemesinden döndürülür ve tümü döndürüldüğünde (bir sabit satır dizisi), -joinyeni satırlarla (başlangıçta yeni satırlara bölündüğümüzden) ediniyor.

Burada iyileştirme için bir oda olduğunu hissediyorum, şu anda yakalayamayacağım kadar yaktım, ama belki daha sonra bir şeyler göreceğim.

Sekmeler 4 lyfe


4

PHP - 278 210 bayt

İşlev, her sekme genişliğini test ederek çalışır; 100 değeri, satırın maksimum uzunluğu ve bu nedenle maksimum sekme genişliği.

Her sekme genişliği için, her satırı bu uzunluktaki "bloklara" böleriz. Bu blokların her biri için:

  • Önceki bloğun son karakterini bu blokla birleştirerek, bir karakterden önce ardışık iki boşluk bulursak, görünüşü değiştirmeden uzaya dönüştürülemeyen bir girintiye veya tabloya sahip oluruz; sonraki sekme genişliğini denedik.
  • Aksi takdirde, son karakter bir boşluksa, bloğun sonundaki boşlukları sıyırır, bir tabülatör ekler ve her şeyi ezberleriz.
  • Aksi takdirde, sadece bloğu ezberleriz.

Bir satırın her bir bloğu analiz edildikten sonra bir satır beslemeyi ezberleriz. Tüm satırların tüm blokları başarı ile analiz edildi ise, ezberlediğimiz dizgeyi geri döndürürüz. Aksi takdirde, her bir pozitif pozitif genişlik genişliği denenirse, ne tablo, ne de girinti vardı ve orijinal dizgiyi döndürürüz.

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

İşte ungolfed versiyonu:

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

2 byte tasarruf için DankMemes'e özel teşekkürler .


1
Bunun for($t=101;--$t;)yerine 2 bayttan tasarruf edebilirsinizfor($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*

Çevrimiçi deneyin

Bu zorluğa cevap vermek zorundaydım, çünkü bu uyuşmazlığın dünyasını kurtarmaya yardım etmek için üzerime düşeni yapmalıyım. Sekmeler açıkça üstün, ama ne yazık ki, bazı insanlar sadece mantıklı olamaz.

Açıklama:

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 bayt

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

Çevrimiçi deneyin!

Daha az golf oynadı:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.