Боже мій, це повно просторів!


42

Деякі люди наполягають на використанні пробілів для підрахунку та відступу.

Для табуляції це безперечно неправильно. За визначенням для складання табуляції потрібно використовувати табулятори.

Навіть для відступу табличні пристрої об'єктивно переважають:

  • У спільноті Stack Exchange чіткий консенсус .

  • Використання єдиного простору для відступу візуально неприємно; використання декількох є марним.

    Оскільки весь тріск х гольф ERS знати, програми повинні бути якомога коротше. Це не тільки економить простір на жорсткому диску, але й час компіляції скорочується, якщо потрібно обробити менше байтів.

  • Регулюючи ширину вкладки 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, нарешті,
перестаньте

2
programs should be as short as possibleЯ вірю, що знайшов давно загубленого брата Артура Вітні !!
kirbyfan64sos


13
Вкладки є нечестивими демонами, які заслуговують на те, щоб розрізати їхні шматочки і зневажити код ASCII, поки їх некомпетентна нестача душі не буде повністю сформована в пульпу. Errr, я маю на увазі +1, приємний виклик, навіть якщо це богохульство. ;)
Дверна ручка

1
Я плакала щоразу, коли колега додав вкладку в мій прекрасний простір з відступом коду. Потім я виявив CTRL + K + F у Visual Studio. Я роблю це кожен раз, коли відкриваю модифікований файл. Моє життя зараз краще.
Майкл М.

Відповіді:


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
Брайан Тук

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і виконує на ньому регулярний вираз ( slsабо Select-String), повертаючи відповідні об'єкти. Я фактично отримую як відступи, так і таблиці в одному тут, що насправді врятувало мені додаткову обробку, захоплюючи їх окремо.

$nвикористовується для різних речей, що знаходяться всередині та зовні основного циклу (дуже погано, але тут необхідно, щоб я міг вбудовувати його у $bблоці сценаріїв і використовувати це як у циклі, так і зовні, без тривалого param()оголошення та передачі аргументів.

$sотримує присвоєну ширину вкладки, викликаючи $bблок на масиві рядків у вхідному файлі, потім підсумовуючи індекс і довжину кожного відповідності, повертаючи масив сум як аргумент у функцію GCD. Так само $sрозмір нашої вкладки зараз зупиняється.

Потім починається цикл. Ми повторюємо кожен рядок у масиві вхідних рядків $n. Перше, що я роблю в циклі, - це присвоїти $n(локальній області) значення поточного рядка з вищевказаної причини.

$w отримує значення виклику блоку скриптів лише для поточного рядка (відступи та таблички для поточного рядка).

$cотримує аналогічне значення, але натомість ми знаходимо всі плутанини .

Я додаю $wі $cякі є масивами, даючи мені один масив з усіма потрібними мені просторами, 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/$sа 1потім використовує -ge 1для повернення масиву, що містить лише елементи, які більше або дорівнюють одиниці, і приймає перший елемент. Він поставляється на кілька байт коротше, ніж [Math]::Maxверсія.

Отже, як тільки всі заміни виконані, поточний рядок повертається з ітерації ForEach-Object( %), і коли всі вони повертаються (масив фіксованих ліній), він -joinредагується новими рядками (оскільки ми розділилися на нові рядки на початку).

Я відчуваю, що тут є місце для вдосконалення, що я занадто згорілий, щоб зловити його зараз, але, можливо, побачу щось пізніше.

Вкладки 4 lyfe


4

PHP - 278 210 байт

Функція працює, протестуючи кожну ширину вкладки, починаючи зі значення 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
Ви можете зберегти 2 байти, скориставшись for($t=101;--$t;)замість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 138 байт

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.