Видаліть загальні провідні місця


19

Коли кодується в Python, іноді потрібно багаторядковий рядок у межах функції, наприклад

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

(Косою рисою слід видалити провідний новий рядок)

Якщо ви спробуєте насправді роздрукувати s, ви отримаєте

    Line 1
    Line 2
    Line 3

Це зовсім не те, чого ми хочемо! Тут занадто багато провідних пробілів!

Змагання

Враховуючи багаторядковий рядок, що складається лише з буквено-цифрових символів, пробілів та нових рядків, видаліть усі загальні пробіли з початку кожного рядка. Кожен рядок гарантовано матиме щонайменше один непробільний символ і не матиме пробілів. Вихід може не мати сторонні пробіли, будь то до або після всього виводу або окремого рядка (за винятком одного необов'язкового кінцевого нового рядка).

Введення може бути через аргумент STDIN або аргумент функції, а вихід може бути через STDOUT або повернути функцію функції. Ви не можете використовувати будь-які вбудовані елементи, призначені для виділення багаторядкових рядків або виконання цього точного завдання, наприклад, Python's 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

Піт, 19 18 17 14 байт

jbu>R!rhCG6G.z

Реалізація досить класна.

  1. u .z захоплює всі рядки stdin в масив, поміщує його G . Потім він оцінює внутрішнє тіло, ставить результат Gі продовжує робити це до тих пір, поки воно більше не зміниться (фіксована точка).

  2. !rhCG6 переносить G , отримує перший елемент транспонованого масиву (перший стовпець), позбавляє його від будь-якого пробілу та перевіряє, чи не залишилося жодних символів пробілу.

  3. Значення від 2 - булеве значення, яке можна розглядати як int 0 або 1. >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прапор.
Toby Speight

Ви можете :;/^\S/M!s/^ //mg;t-r
Крітіксі Літос

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.


5

Джулія, 93 92 81 байт

Збережено 10 байт завдяки Глен О.

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

Це створює неназвану функцію, яка приймає рядок і друкує до stdout.

Недоліки + пояснення:

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)
Glen O

Вибачте помилку вище - мабуть, я використав свої зміни - це не 9 байт, а 6, тому що я не зазначив, що ви використовували = у формі для гольфу. У будь-якому випадку, я можу зберегти ще два символи, визначивши p при запуску циклу for:s->for i=(p=split(s,"\n")) println(i[minimum([search(j,r"[^ ]")[1]for j=p]):end])end
Glen O

Гаразд, ось ще один, щоб поголити трохи більше - замість того, щоб використовувати, minimum(x)коли xце масив, використовувати min(x...)для додаткового збереженого байта (я збираюсь додати цей список до мого списку порад щодо гольфу в Джулії).
Глен О

@GlenO Приємно, дякую за пропозиції. Крім того, оскільки Джулія використовує PCRE, символи, що не містять пробілів, можуть відповідати, \Sа не [^ ], що економить байт.
Алекс А.

Гей, дякую, що згадуєте про це - я не дуже хороший з регексом, але виявилося, що \Sце корисно і для мого рішення.
Глен О

4

Ява, 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

Перл, 47 33

Дякуємо @ThisSuitIsBlackNot за пропозицію використовувати неявний цикл Perl

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

Вищезазначене оцінюється як 30 байт для рядка коду + 3 для 00pпрапорів.

Оригінальна версія як функція:

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
Toby Speight

3

Пітон 2, 86 79 75 байт

Це майже точно можна скоротити ще трохи, але зараз це непогано.

Завдяки xnor за збереження 4 байтів!

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
Каде

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 Я не бачив вашого рішення, поки не оновив сторінку btw: o)
Sok


1

JavaScript, ES6, 89 86 байт

Цей повністю використовує лише відповідність RegEx та підстановки.

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>

Як завжди, лише Firefox, починаючи з ES6. Додано версію ES5 пізніше.


1
Здається, було б коротше написати
буквар

@ vihan1086 ти можеш мати рацію. Дозвольте спробувати.
Оптимізатор

1

К, 31 байт

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

Вводить список рядків і друкує результат у stdout.


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

Пітона, 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, 74 , 56 , 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"
Digital Trauma

1
@DigitalTrauma: Приємно, я забув про $[]арифметику. Використовувати cutдля вибору стовпців набагато краще. Я ніколи не бачив sed qяк альтернативу head -n1, це хороший трюк з гольфу. Спасибі!
Тор

2
Щодо head -n1vs sed q, то lineу пакеті util-linux є інструмент.
манатура

@manatwork: Це зберігає один символ, я буду його використовувати. Зауважте, що воно застаріле і може зникнути в майбутньому, це з deprecated.txt у вихідному дереві util-linux: "Чому: марно, ніхто не використовує цю команду, голова (1) краще".
Тор

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
> 

Здрастуйте, привітайте 3кр!
Олексій А.

@AlexA. Ура, не думав, що це для мене важливо ... але :)
MickyT

Ви маєте на увазі, що ваше життя не обертається навколо підроблених інтернет-точок? : P
Алекс А.

@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ð*Ûζ»

Спробуйте в Інтернеті!


Зачекайте, *повторює рядок б в кількість разів? .. Не знав про цю особливість *. Я, як правило, роблю s∍(поміняю і подовжую), коли хочу повторити певний символ.
Кевін Круїссен

Так, це дійсно працює для рядків, головним чином тому, що векторизація не зовсім має сенс у разі рядків і идає список символів.
Містер Xcoder

0

Гаук, 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".)
манатура

0

C GCC, 74 байт

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

Видаляє лише весь пробіл, не пов'язаний з попередніми рядками, з проханням допомогти закінчити. ТАКОЖ, з точки зору загальних пробілів, чи означає ОП те, що в рядку є найменше провідних пробілів, тобто кількість пробілів, які потрібно видалити з кожного рядка?


Так, правильно використовувати рядок з найменшими провідними пробілами.
Sp3000

0

Складене , неконкурентне, 43 байти

:lines'^ +'match$#'"!MIN' '*0# '^'\+''mrepl

Спробуйте в Інтернеті!

Це спрацьовує, знаходячи кількість пробілів на початку кожного рядка ( '^ +'match$#'"!), отримуючи мінімум, повторюючи пробіл стільки разів та замінюючи його нічим у кожному рядку.




-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
Було б чудово, якби низовик міг би пояснити…
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

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

Випробуйте запуск фрагмента нижче - це лише 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>

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