Chúa ơi, nó đầy không gian!


42

Một số người khăng khăng sử dụng không gian để lập bảng và thụt lề.

Đối với lập bảng, đó là sai không thể chối cãi. Theo định nghĩa, lập bảng phải được sử dụng để lập bảng.

Ngay cả đối với thụt lề, lập bảng cũng vượt trội khách quan:

  • sự đồng thuận rõ ràng trong cộng đồng Stack Exchange.

  • Sử dụng một không gian duy nhất để thụt đầu dòng là khó chịu trực quan; sử dụng nhiều hơn một là lãng phí.

    Như tất cả những người chơi golf điện tử đều biết, các chương trình nên càng ngắn càng tốt. Không chỉ tiết kiệm dung lượng ổ cứng, thời gian biên dịch cũng giảm nếu phải xử lý ít byte hơn.

  • Bằng cách điều chỉnh độ rộng tab 1 , cùng một tệp trông khác nhau trên mỗi máy tính, vì vậy mọi người có thể sử dụng chiều rộng thụt lề yêu thích của mình mà không cần sửa đổi tệp thực tế.

  • Tất cả các trình soạn thảo văn bản tốt đều sử dụng trình lập bảng theo mặc định (và định nghĩa).

  • Tôi nói vậy và tôi luôn luôn đúng!

Đáng buồn thay, không phải ai cũng lắng nghe lý do. Ai đó đã gửi cho bạn một tệp đang thực hiện sai TM và bạn phải sửa nó. Bạn chỉ có thể làm nó bằng tay, nhưng sẽ có những người khác.

Nó đủ tệ đến mức các miếng đệm đang lãng phí thời gian quý báu của bạn, vì vậy bạn quyết định viết chương trình ngắn nhất có thể để giải quyết vấn đề.

Bài tập, nhiệm vụ

Viết chương trình hoặc hàm thực hiện như sau:

  1. Đọc một chuỗi đơn từ STDIN hoặc dưới dạng đối số dòng lệnh hoặc hàm.

  2. Xác định tất cả các vị trí nơi không gian đã được sử dụng để lập bảng hoặc thụt lề.

    Một khoảng trống được thụt lề nếu nó xuất hiện ở đầu dòng.

    Việc chạy hai hoặc nhiều khoảng trắng là lập bảng nếu nó không thụt lề.

    Một không gian duy nhất không thụt lề có thể hoặc không được sử dụng để lập bảng. Như mong đợi khi bạn sử dụng cùng một nhân vật cho các mục đích khác nhau, không có cách nào dễ dàng để nói. Do đó, chúng tôi sẽ nói rằng không gian đã được sử dụng cho sự nhầm lẫn .

  3. Xác định chiều rộng tab dài nhất có thể 1 mà tất cả các khoảng trắng được sử dụng để lập bảng hoặc thụt lề có thể được thay thế bằng các bảng, mà không làm thay đổi giao diện của tệp.

    Nếu đầu vào không chứa bảng, cũng không thụt lề, không thể xác định chiều rộng của tab. Trong trường hợp này, bỏ qua bước tiếp theo.

  4. Sử dụng chiều rộng tab được xác định trước đó, thay thế tất cả các khoảng trắng được sử dụng để lập bảng hoặc thụt lề bằng bảng.

    Ngoài ra, bất cứ khi nào có thể mà không làm thay đổi sự xuất hiện của tệp, hãy thay thế tất cả các khoảng trắng được sử dụng để gây nhầm lẫn với các bảng. (Nếu nghi ngờ, hãy loại bỏ khoảng trắng.)

  5. Trả về chuỗi đã sửa đổi từ chức năng của bạn hoặc in nó thành STDOUT.

Ví dụ

  • Tất cả không gian của

    a    bc   def  ghij
    

    được lập bảng.

    Mỗi lần chạy khoảng trắng sẽ tạo chuỗi ký tự không phải khoảng trắng trước cho chiều rộng là 5, vì vậy chiều rộng của tab chính xác là 5 và đầu ra đúng 2

    a--->bc-->def->ghij
    
  • Hai không gian đầu tiên của

    ab  cde f
    ghi jk lm
    

    Được lập bảng, những người khác nhầm lẫn.

    Độ rộng tab đúng là 4, vì vậy đầu ra đúng 2

    ab->cde>f
    ghi>jk lm
    

    Không gian cuối cùng vẫn còn chưa được xử lý, vì nó sẽ được hiển thị thành hai khoảng trắng nếu được thay thế bằng một trình lập bảng:

    ab->cde>f
    ghi>jk->lm
    
  • Tất cả trừ một không gian của

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

    là thụt, khác là nhầm lẫn.

    Các mức thụt lề là 0, 4 và 8 khoảng trắng, vì vậy độ rộng tab chính xác là 4 và đầu ra 2 chính xác là

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

    Không gian trong ( )sẽ được hiển thị dưới dạng ba khoảng trắng nếu được thay thế bằng bảng, vì vậy nó vẫn còn nguyên.

  • Hai không gian đầu tiên của

      x yz w
    

    là thụt, những người khác nhầm lẫn.

    Độ rộng tab thích hợp là 2 và đầu ra đúng 2

    ->x>yz w
    

    Không gian cuối cùng sẽ được hiển thị dưới dạng hai khoảng trắng nếu được thay thế bằng bảng, vì vậy nó vẫn còn nguyên.

  • Hai không gian đầu tiên của

      xy   zw
    

    là thụt, ba cái còn lại là bảng.

    Chỉ có chiều rộng tab là 1 cho phép loại bỏ tất cả các khoảng trắng, vì vậy đầu ra 2 chính xác là

    >>xy>>>zw
    
  • Tất cả không gian của

    a b c d
    

    là sự nhầm lẫn.

    Không có chiều rộng tab dài nhất có thể, vì vậy đầu ra 2 chính xác là

    a b c d
    

Quy tắc bổ sung

  • Đầu vào sẽ bao gồm toàn bộ các ký tự và nguồn cấp dữ liệu ASCII có thể in được.

  • Bạn có thể cho rằng có tối đa 100 dòng văn bản và tối đa 100 ký tự trên mỗi dòng.

  • Nếu bạn chọn STDOUT cho đầu ra, bạn có thể in một dòng cấp dữ liệu duy nhất.

  • Luật tiêu chuẩn được áp dụng.


1 Độ rộng của tab được định nghĩa là khoảng cách tính theo ký tự giữa hai lần dừng tab liên tiếp , sử dụng phông chữ đơn cách.
2 Mũi tên nghệ thuật ASCII đại diện cho các trình lập bảng Stack Exchange từ chối hiển thị đúng, mà tôi đã gửi báo cáo lỗi. Đầu ra thực tế phải chứa các tab thực tế.


9
+1 để cuối cùng đặt vấn đề không gian / tab vô nghĩa này vào phần còn lại: D
Geobits

2
programs should be as short as possibleTôi tin rằng tôi đã tìm thấy người anh trai đã mất từ ​​lâu của Arthur Whitney !!
kirbyfan64sos


13
Các tab là demonspawn không đáng tin cậy mà bị xé toạc và mã ASCII của chúng bị thất sủng cho đến khi sự thiếu linh hồn bất tài của chúng bị nghiền nát hoàn toàn. Errr, ý tôi là, +1, thử thách tốt đẹp, mặc dù nó mang lại sự báng bổ. ;)
Doorknob

1
Tôi đã khóc mỗi khi một đồng nghiệp thêm một tab vào mã thụt vào không gian đẹp của tôi. Sau đó, tôi phát hiện ra CTRL + K + F trong Visual Studio. Tôi làm điều đó mỗi lần tôi mở một tập tin sửa đổi. Cuộc sống của tôi bây giờ tốt hơn
Michael M.

Câu trả lời:


5

Bình thường, 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

Dùng thử trực tuyến

Ý tưởng thú vị, nhưng vì các tab trong đầu vào phá vỡ khái niệm, không thể sử dụng được.

Chỉnh sửa: Đã sửa lỗi. cảm ơn rất nhiều


Nó gặp sự cố trên "abc d"
aditsu

@aditsu tào lao! Thanx cho người đứng đầu. Tôi cần các trường hợp kiểm tra tốt hơn: 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"

Tôi đã đi trước và sử dụng các dòng mới thay vì ;nơi có thể để hiển thị dễ dàng hơn. Tôi đang sử dụng các kết thúc dòng unix để nó không ảnh hưởng đến số byte.

Cách thực hiện

Sao chép mã vào SpaceMadness.ps1tập tin, sau đó chuyển đầu vào vào tập lệnh. Tôi sẽ giả sử tập tin cần chuyển đổi được gọi là taboo.txt:

Từ PowerShell:

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

Từ dấu nhắc lệnh:

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

Tôi đã thử nghiệm nó với PowerShell 5, nhưng nó sẽ hoạt động trên 3 hoặc cao hơn.

Kiểm tra

Đây là đoạn mã PowerShell nhanh, hữu ích để kiểm tra phần trên:

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

Đặt cái này trong cùng thư mục với SpaceMadness.ps1, tôi gọi cái này tester.ps1, gọi nó như vậy:

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

Bạn có được ý tưởng. Nó phun ra nội dung của mỗi tệp sau khi chuyển đổi, chạy qua [RegEx]::Escape()đó xảy ra để thoát cả khoảng trắng và tab để thật sự thuận tiện để xem những gì thực sự đã được thay đổi.

Đầu ra trông như thế này (nhưng có màu sắc):

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

Giải trình

Dòng đầu tiên xác định hàm nhân tố / ước số chung lớn nhất gngắn gọn nhất mà tôi có thể quản lý, lấy một mảng (số lượng tùy ý) và tính toán đệ quy GCD bằng thuật toán Euclide .

Mục đích của việc này là tìm ra "chiều rộng tab dài nhất có thể" bằng cách lấy chỉ số + độ dài của mỗi lần thụtlập bảng như được định nghĩa trong câu hỏi, sau đó đưa nó vào hàm này để lấy GCD mà tôi nghĩ là tốt nhất chúng ta có thể làm cho chiều rộng tab. Độ dài của một sự nhầm lẫn sẽ luôn là 1 vì vậy nó không đóng góp gì cho phép tính này.

$bđịnh nghĩa một scriptblock bởi vì thật khó chịu tôi cần phải gọi đoạn mã đó hai lần, vì vậy tôi lưu một số byte theo cách đó. Khối này lấy chuỗi (hoặc mảng chuỗi) $nvà chạy regex trên nó ( slshoặc Select-String), trả về các đối tượng khớp. Tôi thực sự nhận được cả hai vết lõm và bảng trong một ở đây, điều này thực sự giúp tôi tiết kiệm thêm bằng cách chụp riêng chúng.

$nđược sử dụng cho những thứ khác nhau bên trong và bên ngoài vòng lặp chính (thực sự xấu, nhưng cần thiết ở đây để tôi có thể nhúng nó vào $bscriptblock và sử dụng cả bên trong và bên ngoài vòng lặp mà không cần param()khai báo dài và truyền đối số.

$sđược gán chiều rộng của tab, bằng cách gọi $bkhối trên mảng các dòng trong tệp đầu vào, sau đó tính tổng chỉ số và độ dài của mỗi trận đấu, trả về mảng tổng như một đối số vào hàm GCD. Vì vậy, $scó kích thước của tab của chúng tôi dừng lại bây giờ.

Sau đó vòng lặp bắt đầu. Chúng tôi lặp lại qua từng dòng trong mảng các dòng đầu vào $n. Điều đầu tiên tôi làm trong vòng lặp là gán $n(phạm vi cục bộ) giá trị của dòng hiện tại vì lý do trên.

$w chỉ nhận giá trị của lệnh gọi scriptblock cho dòng hiện tại (các vết lõm và bảng cho dòng hiện tại).

$cnhận được một giá trị tương tự, nhưng thay vào đó chúng tôi tìm thấy tất cả những nhầm lẫn .

Tôi thêm vào $w$cđó là các mảng, cung cấp cho tôi một mảng với tất cả các kết quả không gian tôi cần, sortnó theo thứ tự giảm dần theo chỉ mục và bắt đầu lặp lại qua từng trận đấu cho dòng hiện tại.

Việc sắp xếp là quan trọng. Ngay từ đầu tôi đã phát hiện ra một cách khó khăn là việc thay thế các phần của chuỗi dựa trên các giá trị chỉ mục là một ý tưởng tồi khi chuỗi thay thế nhỏ hơn và thay đổi độ dài của chuỗi! Các chỉ số khác bị vô hiệu. Vì vậy, bằng cách bắt đầu với các chỉ mục cao nhất trên mỗi dòng, tôi đảm bảo rằng tôi chỉ làm cho chuỗi ngắn hơn từ cuối và di chuyển về phía sau để các chỉ mục luôn hoạt động.

Trong vòng lặp này, $xnằm trong chỉ mục của trận đấu hiện tại và $llà độ dài của trận đấu hiện tại. $strên thực tế có thể 0và điều đó gây ra sự phân chia đáng tiếc bằng sai số 0 vì vậy tôi đang kiểm tra tính hợp lệ của nó sau đó thực hiện phép toán.

Các !(($x+$l)%$s)chút đó là điểm duy nhất nơi tôi kiểm tra xem nếu một sự nhầm lẫn nên được thay thế bằng một tab hay không. Nếu chỉ số cộng với chiều dài chia cho chiều rộng của tab không còn lại, thì chúng ta nên thay thế khớp này bằng một tab (toán học đó sẽ luôn hoạt động trên các vết lõmbảng , bởi vì kích thước của chúng là yếu tố quyết định độ rộng của tab đầu tiên là).

Để thay thế, mỗi lần lặp của vòng lặp khớp hoạt động trên dòng hiện tại của đầu vào, do đó, nó là một tập hợp thay thế tích lũy. Regex chỉ tìm kiếm các $lkhoảng trắng có trước $xbất kỳ ký tự nào. Chúng tôi thay thế nó bằng các $l/$ský tự tab (hoặc 1 nếu số đó dưới 0).

Phần này (($l/$s),1-ge1)[0]là một cách nói phức tạp lạ mắt if (($l/$s) -lt 0) { 1 } else { $l/$s }hoặc cách khác [Math]::Max(1,($l/$s)). Nó tạo ra một mảng $l/$s1sau đó sử dụng -ge 1để trả về một mảng chỉ chứa các phần tử lớn hơn hoặc bằng một, sau đó lấy phần tử đầu tiên. Nó có một vài byte ngắn hơn [Math]::Maxphiên bản.

Vì vậy, khi tất cả các thay thế được thực hiện, dòng hiện tại được trả về từ lần lặp ForEach-Object( %) và khi tất cả chúng được trả về (một mảng các dòng cố định), nó sẽ -joinphù hợp với dòng mới (vì chúng tôi đã chia ra dòng mới ở đầu).

Tôi cảm thấy như có chỗ để cải thiện ở đây mà tôi đã quá kiệt sức để nắm bắt ngay bây giờ, nhưng có lẽ tôi sẽ thấy một cái gì đó sau này.

Tab 4 lyfe


4

PHP - 278 210 byte

Hàm hoạt động bằng cách kiểm tra từng chiều rộng của tab, bắt đầu bằng giá trị 100, chiều dài tối đa của một dòng và do đó chiều rộng của tab tối đa.

Đối với mỗi chiều rộng tab, chúng tôi chia mỗi dòng thành "khối" có độ dài đó. Đối với mỗi khối này:

  • Nếu, bằng cách ghép ký tự cuối cùng của khối trước với khối này, chúng ta tìm thấy hai khoảng trắng liên tiếp trước một ký tự, chúng ta có một vết lõm hoặc một bảng không thể chuyển thành không gian mà không thay đổi diện mạo; chúng tôi thử chiều rộng tab tiếp theo.
  • Mặt khác, nếu ký tự cuối cùng là một khoảng trắng, chúng ta sẽ loại bỏ khoảng trắng ở cuối khối, thêm một trình lập bảng và ghi nhớ toàn bộ.
  • Nếu không, chúng tôi chỉ ghi nhớ khối.

Khi từng khối của một dòng đã được phân tích, chúng tôi ghi nhớ một nguồn cấp dữ liệu. Nếu tất cả các khối của tất cả các dòng được phân tích thành công, chúng tôi sẽ trả về chuỗi chúng tôi đã ghi nhớ. Mặt khác, nếu từng độ rộng tab tích cực nghiêm ngặt đã được thử, không có bảng, cũng không thụt lề và chúng tôi trả về chuỗi gốc.

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

Đây là phiên bản chưa được chỉnh sửa:

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

Đặc biệt cảm ơn DankMeme vì đã lưu 2 byte.


1
Bạn có thể lưu 2 byte bằng cách sử dụng for($t=101;--$t;)thay vìfor($t=100;$t;--$t)
DankMeme

4

CJam, 112

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

Dùng thử trực tuyến

Tôi đã phải trả lời thử thách này, vì tôi phải làm phần việc của mình để giúp thoát khỏi thế giới ghê tởm này. Tab rõ ràng là vượt trội, nhưng thật đáng buồn, một số người không thể lý luận được.

Giải trình:

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 byte

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

Hãy thử trực tuyến!

Ít chơi gôn hơn:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.