一般的な先行スペースを削除する


19

Pythonでコーディングする場合、関数内に複数行の文字列が必要になることがあります。たとえば、

def f():
    s = """\
    Line 1
    Line 2
    Line 3"""

(バックスラッシュは、先頭の改行を削除することです)

sただし、実際に印刷しようとすると、

    Line 1
    Line 2
    Line 3

それは私たちが望むものではありません!先頭の空白が多すぎます!

チャレンジ

英数字、スペース、および改行のみで構成される複数行の文字列が指定されている場合、各行の先頭からすべての一般的なスペースを削除します。各行には、少なくとも1つの非スペース文字が含まれることが保証されており、末尾のスペースはありません。出力には、出力全体または個々の行の前後に関係なく、余分な空白がない場合があります(1つのオプションの末尾の改行を除く)。

入力はSTDINまたは関数の引数を介して行われ、出力はSTDOUTまたは関数の戻り値を介して行われます。複数行の文字列を字下げしたり、Pythonのようなこの正確なタスクを実行するように設計された組み込み関数を使用することはできませんtextwrap.dedent

これはであるため、最小バイト数のソリューションが優先されます。標準の抜け穴が適用されます。

テストケース

"a"                                  ->   "a"
"   abc"                             ->   "abc"
"   abc\n def\n  ghi"                ->   "  abc\ndef\n ghi"
"    a\n    b\n    c"                ->   "a\nb\nc"
"    a\n    b\n    c\nd"             ->   "    a\n    b\n    c\nd"
"   a   b\n     c     d\n    e f"    ->   "a   b\n  c     d\n e f"

たとえば、最後のテストケースは

   a   b
     c     d
    e f

先頭のスペースを削除すると、次のようになります。

a   b
  c     d
 e f

出力に末尾の空白が含まれることがありますか?
orlp

@orlpいいえ、明確ではありません。
Sp3000

回答:


12

CJam、20 14バイト

qN/_z{S-}#f>N*

アルゴリズム

  • 最初に入力を改行で分割し、コピーを取得します(qN/_
  • 次に、改行文字で区切られた配列を転置し、最初にすべての非空白行(z{S-}#)のインデックスを検索することにより、非空白文字を含む最小の列が計算されます
  • 次に、各行から多くの文字を削除します(f>
  • 最後に、再び改行で参加します(N*

コード拡張

qN/               e# Read the entire input and split it on newline
   _z             e# Take a copy and transpose rows with columns.
                  e# Now we would have a bunch of all space rows. These rows are the ones
                  e# we want to remove (in form of columns) 
     {  }#        e# Get the index of the first item from the transposed array that returns
                  e# true for this block
      S-          e# From each part, remove spaces. If the part is all-space, it will return
                  e# an empty string, which is false in CJam. We finally will get the index
                  e# of the first non-all-space row (or column)
          f>      e# We take that index and remove that many characters from starting of each
                  e# row of the initial newline separated input
            N*    e# Join the array back using newlines and automatically print the result

こちらからオンラインでお試しください


8

Pyth、19 18 17 14バイト

jbu>R!rhCG6G.z

実装はかなりクールです。

  1. u .z配列内の標準入力のすべての行を取得し、それをに入れGます。次に、内側のボディを評価し、結果をに入れて、G変化しなくなるまでこれを繰り返します(固定小数点)。

  2. !rhCG6transposes Gは、転置された配列の最初の要素(最初の列)を取得し、空白を取り除き、空白以外の文字が残っているかどうかを確認します。

  3. 2の値はブール値であり、0または1のintと見なすことができます。>R Gこの数値を取得し、の各行の左側にある多くの文字を切り出しGます。ステップ1、2、3の組み合わせは、基本的に、純粋な空白の列がなくなるまで空白の列を除去し続けることを意味します。

  4. jb 行の配列を改行で結合して出力します。


2
これについて簡単に説明してもらえますか?これは私にとって非常に奇妙です!
ボベル

2
@bobbel説明が追加されました。
orlp

本当に素晴らしい、ありがとう!それについて聞いたことがない!このオンライン私を試してみた:pyth.herokuapp.com/...
bobbel

8

sed-26バイト

:;/(^|\n)\S/q;s/^ //mg;b

と走る -rz

とても簡単です:

  /(^|\n)\S/q;           - quit if there is a line that starts with non-space
              s/^ //mg;  - remove exactly one space in each line
:;                     b - repeat

-rオプションは拡張正規表現を有効にし、-z入力全体を単一の文字列として読み取ります(実際には行区切り文字としてNULバイトを使用します)


:;N;$!b入力行を単一のパターンスペースにまとめるために、そもそも必要ではないでしょうか。編集:いいえ。それが-zフラグの目的です。
トビースパイト

これをゴルフすることができます:;/^\S/M!s/^ //mg;t、今は必要ありません-r
Kritixi Lithos

7

SWI-Prolog、233 223 217バイト

a(A):-b(A,0,0,0,N),w(A,N,0).
b([A|T],P,K,M,N):-P=1,(A=10,b(T,0,0,M,N);b(T,1,0,M,N));A\=32,(M=0;K<M),b(T,1,0,K,N);I=K+1,b(T,0,I,M,N).
b(_,_,_,N,N).
w([A|T],N,P):-P<N,A=32,Q=P+1,w(T,N,Q);put(A),A=10,w(T,N,0);w(T,N,P);!.

編集:私の答えを完全に変更しました。文字列の代わりに文字コードを使用するようになりました。

これを呼び出す例はa(` a b\n c d\n e f`).、逆引用符付きのです。"古いSWI-Prolog distribがある場合は、代わりに二重引用符を使用する必要があります。


5

ジュリア、93 92 81バイト

Glen Oのおかげで10バイト節約されました。

s->for i=(p=split(s,"\n")) println(i[min([search(j,r"\S")[1]for j=p]...):end])end

これにより、文字列を受け入れて標準出力に出力する名前のない関数が作成されます。

Ungolfed +説明:

function f(s)
    # Split s into an array on newlines
    p = split(s, "\n")

    # Get the smallest amount of leading space by finding the
    # position of the first non-space character on each line
    # and taking the minimum
    m = min([search(j, r"\S")[1] for j in p]...)

    # Print each line starting after m
    for i in p
        println(i[m:end])
    end
end

スペースの数をカウントするのではなく、最初の非スペースを探すことで、スペースを節約できます。ではなくminimum([length(search(j, r"^ +")) for j in p])+1、を使用しますminimum([search(j,r"[^ ]")[1]for j=p])。チャレンジではすべての行にスペース以外のテキストが含まれることが示されているため、安全で、9バイト(3を含めて=`in ). Still looking to see if more can be saved. (I wish I could drop the [1]`の代わりに使用して保存されますが、検索ではAnyタイプの列挙子配列が生成されますが、 Int型)
グレンO

上記の間違い-すみません、編集内容を使い果たしたようです-それは9バイトではありませんが、ゴルフフォームで=を使用したことに気付かなかったため、6バイトです。とにかく、私はループの開始のpを定義することにより、2つの以上の文字を保存することができます:s->for i=(p=split(s,"\n")) println(i[minimum([search(j,r"[^ ]")[1]for j=p]):end])end
グレンO

OK、もう1つもう少し削ります- 配列のminimum(x)場合を使用するのでxはなく、min(x...)余分な1バイトを節約するためにを使用します(これをJuliaゴルフのヒントのリストに追加します)。
グレンO

@GlenOナイス、提案ありがとう。また、ジュリアはPCREを使用しているため、スペース以外の文字をで\Sなくに一致させることができ[^ ]、バイトを節約できます。
アレックスA.

ねえ、それについて言及してくれてありがとう-私は正規表現が得意ではありませんが、それは\S私のソリューションにも役立つことが判明しました。
グレンO

4

Java、159

Javaが目立って不足しているため...

void f(String...a){int s=1<<30,b;a=a[0].split("\n");for(String x:a)s=(b=x.length()-x.trim().length())<s?b:s;for(String x:a)System.out.println(x.substring(s));}

長さをトリミングした長さと比較し、部分文字列を吐き出すだけのループです。派手なものは何もありません。スクロールバーに障害がある場合:

void f(String...a){
    int s=1<<30,b;
    a=a[0].split("\n");
    for(String x:a)
        s=(b=x.length()-x.trim().length())<s?b:s;       
    for(String x:a)
        System.out.println(x.substring(s));
}

4

Perl、47 33

@ThisSuitIsBlackNotに、Perlの暗黙ループの使用を提案してくれてありがとう

#!/usr/bin/perl -00p
/^( +).*(\n\1.*)*$/&&s/^$1//mg

上記は、コード行の30バイト+ 00pフラグの3としてスコア付けされます。

関数としての元のバージョン:

sub f{$_=@_[0];/^( +).*(\n\1.*)*$/&&s/^$1//mgr}

これは引数を$_に入れてから、すべての行に存在する空白に貪欲に一致しようとします/^( +).*(\n\1.*)*$/-成功した場合$1、最長の共通プレフィックスが含まれるようになり、置換を実行してs/^$1//mgrすべての行の先頭から削除し、結果の文字列を返します。

テスト

$ cat 53219.data
   a   b
     c     d
    e f
$ ./53219.pl <53219.data 
a   b
  c     d
 e f

とてもかっこいい。コマンドラインで実行することにより、いくつかのバイトを削ることができます:perl -00pe '/^( +).*(\n\1.*)*$/&&s/^$1//mg'(30バイト+ 3の場合00p)。
ThisSuitIsBlackNot

/me見上げるために-00p出発する; おかげ@ThisSuit
トビーSpeight

3

パイソン2、86 79の 75バイト

これはほぼ確実にさらに短くすることができますが、現時点では悪くはありません。

4バイトを節約してくれたxnorに感謝します!

s=input().split('\n')
for k in s:print k[min(x.find(x.strip())for x in s):]

1
先頭のスペースを数える少し短い方法はx.find(x.strip())です。
xnor

@xnor良い電話、ありがとう!私は一日中あなたから60バイトの解決策を待っていました; P
Kade

input()Python 2では、このデータが詰まってしまいます。
スティーブンランバルスキー

@StevenRumbalski、入力は引用符で囲まれていると思います。私はこれを説明するためにバイトカウントに2を追加していましたが、複数の人が私がする必要がないと言っていました。
カデ

1
このプログラムは悲しい:):
HyperNeutrino

3

ルビー:77 73 70 66 65 58 57 40文字

f=->t{t.gsub /^#{t.scan(/^ */).min}/,""}

サンプル実行:

irb(main):001:0> f=->t{t.gsub /^#{t.scan(/^ */).min}/,""}
=> #<Proc:0x00000001855948@(irb):1 (lambda)>

irb(main):002:0> puts f["   a   b\n     c     d\n    e f"]
a   b
  c     d
 e f
=> nil

irb(main):003:0> f["   a   b\n     c     d\n    e f"] == "a   b\n  c     d\n e f"
=> true

2
どうf=->t{t.gsub /^#{t.scan(/^ */).min}/,""}
ヴェンテロ

素晴らしいですね、@ Ventero。ありがとうございました。
マナトワーク

2

C#、18 + 145 = 163バイト

必要(18バイト):

using System.Linq;

メソッド(145バイト):

string R(string s){var l=s.Split('\n');return string.Join("\n",l.Select(x=>string.Concat(x.Skip(l.Select(z=>z.Length-z.Trim().Length).Min()))));}

このメソッドは、行の先頭のスペースの最小量を計算し、N個の文字をスキップして、すべての行で構成される新しい文字列を作成します(Nは以前に計算された数です)。


1

C#、合計149バイト

ProgramFOXとほぼ同じソリューションですが、トリミングする文字数は手動で計算されます。

using System.Linq;

そして、関数自体:

string D(string s){var l=s.Split('\n');int i=0;while(l.All(a=>a[i]==' '))i++;return string.Join("\n",l.Select(b=>b.Substring(i)));}

@ProgramFOXページを更新した後まで解決策を見ていませんでした:o)
Sok

1

Python 3、100

def f(s):t=s.split("\n");return"\n".join([c[min([len(c)-len(c.lstrip(" "))for c in t]):]for c in t])

1

JavaScriptを、ES6、89の 86バイト

これは完全に正規表現のマッチングと置換のみを使用しています。

f=x=>eval(`x.replace(/(^|\\n) {${--`
${x}`.match(/\n */g).sort()[0].length}}/g,"$1")`)

// Snippet related stuff
B.onclick=x=>P.innerHTML=f(T.value)
<textarea id=T></textarea><br>
<button id=B>Trim</button>
<pre id=P></pre>

いつものように、ES6以降のFirefoxのみ。ES5バージョンは後で追加されます。


1
正規表現リテラルを文字列として記述してから評価する方が短いようです
-Downgoat

@ vihan1086あなたは正しいかもしれません。試してみましょう。
オプティマイザー

1

K、31バイト

{`0:(&/{(0;#*=x)@*x}'" "=x)_'x}

文字列のリストを入力し、結果を標準出力に出力します。


1

Haskell、52バイト

unlines.until(any(/=' ').map head)(map tail).lines

使用例:unlines.until(any(/=' ').map head)(map tail).lines $ " abc\n def\n ghi"->" abc\ndef\n ghi\n"

使い方:

                                           lines    -- split the input at newlines into a list of lines
        until                                       -- repeat the 2nd argument, i.e.
                                 map tails          -- cut off the heads of all lines
                                                    -- until the the first argument returns "True", i.e.
             any(/=' ').map head                    -- the list of heads contains at least one non-space
unlines                                             -- transform back to a single string with newlines in-between

1

Python、94/95

ラムダ(94バイト):

f=lambda s:'\n'.join(l[min(l.find(l.strip()) for l in s.split('\n')):] for l in s.split('\n'))

def(95バイト)

def f(s):l=s.split('\n');m=min(i.find(i.strip())for i in l);return '\n'.join(i[m:] for i in l);

1

bashの+ SED + coreutilsの、7456、55

テストデータ

s="\
   a   b
     c     d
    e f"

回答

cut -c$[`grep -o '^ *'<<<"$s"|sort|line|wc -c`]-<<<"$s"

出力

a   b
  c     d
 e f

2
いくつかの簡単なゴルフの変更私の数が56に、このダウンをもたらします:cut -c$[`grep -o '^ *'<<<"$s"|sort|sed q|wc -c`]-<<<"$s"
デジタルトラウマ

1
@DigitalTrauma:いいですね、私は$[]算数を忘れていました。cut列の選択に使用する方がはるかに優れています。のsed q代替として見たことがないhead -n1、それは良いゴルフのトリックです。ありがとう!
トール

2
head -n1sed q、そこにあるlineのutil-linuxパッケージでツール。
マナトワーク

@manatwork:それは1文字を節約します、私はそれを使います。これは非推奨であり、将来廃止される可能性があることに注意してください。これは、util-linuxのソースツリーのdeprecated.txtからのものです
トール

1

R、118 111バイト

Rのすばらしい文字列関数を使用する:)これは、すでに投稿されている他のソリューションと同様/同じです。入力はSTDINを介して行われ、STDOUTに送られます。

cat(substring(a<-scan(,'',sep='|'),Reduce(min,lapply(strsplit(a,' '),function(x)min(which(x>''))-1))),sep='\n')

テストと説明

> cat(substring(a<-scan(,'',sep='|'),Reduce(min,lapply(strsplit(a,' '),function(x)min(which(x>''))-1))),sep='\n')
1:                  a<-scan(,'',sep='|') # get the input lines
2:                                                         strsplit(a,' ') # split lines on spaces
3:                                                  lapply(                ,function(x)min(which(x>''))-1) # get min index - 1 for non space of each line
4:                                      ,Reduce(min,                                                      ) # get the min of those
5:        substring(                                                                                       ) # trim it off
6:    cat(                                                                                                  ,sep='\n') # output each line
7:
Read 6 items
              a<-scan(,'',sep='|') # get the input lines
                                                     strsplit(a,' ') # split lines on spaces
                                              lapply(                ,function(x)min(which(x>''))-1) # get min index - 1 for non space of each line
                                  ,Reduce(min,                                                      ) # get the min of those
    substring(                                                                                       ) # trim it off
cat(                                                                                                  ,sep='\n') # output each line
> 

こんにちは、3kの担当者おめでとうございます!
アレックスA.

@AlexA。乾杯、それは私にとって重要だとは思わなかった...しかし:)
MickyT

あなたはあなたの人生偽のインターネットポイントを中心に展開していないということですか?:P
アレックスA.

@AlexA。うまくいかないことを願っています:) 6k
MickyT

1

ジュリア、72 62 61 57 54 49バイト

g=s->ismatch(r"^\S"m,s)?s:g(replace(s,r"^ "m,""))

ゴルフをしていない:

g(s)=
if ismatch(r"^\S"m,s)       # Determines if there's a newline followed by something other than a space
                            # Note: the m in r"^ "m says to work in multiline mode.
    s                       # If there is, return the string as the final result.
else                        # otherwise...
    m=replace(s,r"^ "m,"")  # Remove first space after each newline, and space at start of string.
    g(m)                    # Feed back into the function for recursion
end

古いソリューション(57バイト):

g(s)=ismatch(r"
\S","
"s)?s:g(replace(s,"
 ","
")[2:end])

元のソリューション(72バイト):

g(s)=all([i[1]<33for i=split(s,"\n")])?g(replace(s,"\n ","\n")[2:end]):s

1

k(24バイト)

引数として文字列を取り、文字列を返します(末尾の改行を使用)。

{`/:(&//&:'~^s)_'s:`\:x}

例:

k) f:{`/:(&//&:'~^s)_'s:`\:x};
k) f"   a   b\n     c     d\n    e f"
"a   b\n  c     d\n e f\n

1

05AB1E、10バイト

|©ζ®gð*Ûζ»

オンラインでお試しください!


待ち時間は、*文字列を繰り返しbの 倍の量?...のような特徴を知っていたしませんでした。私は通常、特定のキャラクターを繰り返したいときに行います(スワップして長くします)。*s∍
ケビンクルーッセン

はい、確かに、文字列の場合はベクトル化が意味を成さず、文字иのリストを生成するため、主に文字列に対して機能します。
Mr Xcoder

0

gawkは、101 100

{match($0,/^( +)/,t);if(t[1]<s||s==""){s=t[1]};z[NR]=$0;}END{for(r in z){sub(s,"",z[r]);print z[r]}}

例えば...

cat input.txt | gawk '{match($0,/^( +)/,t);if(t[1]<s||s==""){s=t[1]};z[NR]=$0;}END{for(r in z){sub(s,"",z[r]);print z[r]}}'

出力...

a   b
  c     d
 e f

かろうじてテストされたヒント:キャプチャしない/^( +)//^ +/(必要な値はのt[0]代わりにありますt[1]); 変更s==""!s; 削除{}後のコードの周りif;前を削除し}ます。Gawk固有の関数を使用{}て、次のコードを削除できますfor{sub(s,"",z[r]);print z[r]}print gensub(s,"",1,z[r])
マナトワーク

申し訳ありませんが、元のコードとサイズを最適化したコードの両方が、最後の行以外のインデントされていない行の入力に失敗します。(たとえば、「␠one\ nzero \n␠one\n␠␠two」。)
manatwork

0

C GCC、74バイト

main(_,z){z=1;while(-~(_=getchar()))putchar(_==32&&z?0:(z=_==10?1:0,_));}

前の行に関係しないすべての空白のみを削除し、終了するためのヘルプを要求します。また、一般的な空白に関して、OPはどの行の先頭のスペースが最も少ないか、つまり各行から削除されるスペースの数を意味しますか?


はい、先頭のスペースが最も少ない行を使用するのが正しいです。
Sp3000




-1

CoffeeScript、112バイト

f=(x)->(a=x.split "\n").map((v)->v[Math.min.apply(null,a.map((v)->(r=/^ +/.exec v)&&r[0].length))...]).join "\n"

-1

JavaScript(ES6)、106 98バイト

改行が必要であり、それぞれ1バイトとしてカウントされます。

f=x=>(a=x.split`
`).map(v=>v.slice(Math.min(...a.map(v=>(r=/^ +/.exec(v))&&r[0].length)))).join`
`

デモ

他のES6回答と同様に、現時点ではFirefoxでのみ機能します。

f=x=>(a=x.split`
`).map(v=>v.slice(Math.min(...a.map(v=>(r=/^ +/.exec(v))&&r[0].length)))).join`
`

// For demonstration purposes
console.log = x => X.innerHTML += x + `\n<hr>`;

console.log(f("a"));
console.log(f("   abc"));
console.log(f("   abc\n def\n  ghi"));
console.log(f("    a\n    b\n    c"));
console.log(f("    a\n    b\n    c\nd"));
console.log(f("   a   b\n     c     d\n    e f"));
<pre id=X></pre>


11
downvoterが説明できれば素晴らしいことです…
rink.attendant.6

-1

JavaScript ES6、85バイト

s=>s.split`
`.map(z=>z.slice(Math.min(...s.match(/^ */gm).map(l=>l.length)))).join`
`

新しい行は重要です

ES5デモ:

function t(s) {
  return s.split("\n").map(function(z) {
    return z.slice(Math.min.apply(0, s.match(/^ */gm).map(function(l) {
      return l.length;
    })));
  }).join('');
}

// Demo
document.getElementById('go').onclick = function() {
  document.getElementById('r').innerHTML = t(document.getElementById('t').value)
};
Input:
<br>
<textarea id="t"></textarea>
<br>
<button id="go">Run</button>
<br>Output:
<br>
<pre style="background-color:#DDD;" id="r"></pre>


-1

JavaScript(ES6)56

再帰的。非行が見つかるまで各行から一度に1つのスペースを削除しようとします。

以下のスニペットを実行してテストします-ES6、Firefoxのみ

f=s=>(r=s.replace(/^./gm,x=>(k|=x>' ',''),k=0),k?s:f(r))

// Test
test=
[[ "a", "a" ]
,["   abc", "abc" ]
,["   abc\n def\n  ghi", "  abc\ndef\n ghi" ]
,["    a\n    b\n    c", "a\nb\nc" ]
,["    a\n    b\n    c\nd", "    a\n    b\n    c\nd" ]
,["   a   b\n     c     d\n    e f","a   b\n  c     d\n e f" ]]

var tb=''
test.forEach(t=>{
  t[2]=f(t[0])
  t[3]=t[2]==t[1]?'OK':'FAIL'
  tb+='<tr><td>'+t.join('</td><td>')+'</td></tr>'
})
B.innerHTML=tb
td { white-space: pre; font-family: monospace; border: 1px solid#444; vertical-align:top}
#I,#O { height:100px; width: 200px }
<b>Your test:</b>
<table><tr><td><textarea id=I></textarea></td>
<th><button onclick='O.innerHTML=f(I.value)'>-></button></th>
<td id=O></td></tr></table>
<b>Test cases:</b><br>
<table ><tr><th>Input</th><th>Expected</th><th>Output</th><th>Result</th></tr>
<tbody id=B></tbody></table>

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