Напишіть програму, яка замінює пробіли дужки у випадках, коли дужки в місцях викликають застій


17

Ви керівник проекту. Одного разу один з ваших програмістів з’їхав з розуму ( не з вашої вини ) і взяв усі вирази в кодовій базі і додав до них випадкові дужки, перш ніж виходити на місці, реверуючи про вашу некомпетентність ( також не з вашої вини ). Це було б легко виправити, однак, чомусь ви не використовуєте контроль редагування ( абсолютно не з вашої вини ). І чомусь ніхто з інших програмістів не хоче пройти кожен вираз, щоб виправити невідповідні дужки ( до речі, це не ваша вина ). Програмісти в ці дні, ви думаєте самі. Вам доведеться зробити це самостійно. Жах! Такі завдання повинні були бути під вами ...

Вхід буде одним рядком, який буде містити ряд лівих дужок ( ( [ {) і правих дужок ( ) ] }). Він також може, але не завжди, містити коментарі ( /* */) та рядкові літерали ( " "або ' ') та різні цифри, літери чи символи.

Буде щонайменше одна дужка (поза коментуванням або рядковим літералом), яка не має протилежної корпоспондизації (поза коментуванням чи рядком). Наприклад, обман }без {попереднього. Інший приклад: a, (який не має )згодом. Ваша програма замінить на пробіл мінімальну кількість дужок, необхідних для узгодження дужок.

Приклади:

(4 + (2 + 3))]==> (4 + (2 + 3)) (квадратна дужка в кінці)
][][[]]==> [][[]](квадратна дужка на початку)
("Hel(o!"))==> ("Hel(o!") (дужка в кінці)
( /* )]*/==> /* )]*/ (дужки на початку)
{()]==> () (фігурна дужка і квадратний кронштейн)

  • Введення даних може бути здійснено будь-яким зручним способом (STDIN, аргумент командного рядка, зчитування з файлу тощо)
  • Якщо існує декілька способів вирішити невідповідність з однаковою кількістю видалень, прийнятний або один.
  • У дужках будуть лише невідповідності. Рядок літератури та коментарі завжди будуть правильно сформовані.
  • Заголовок походить із цього потоку SO
  • Ніколи не буде жодних цитат у коментарях, цитат у цитатах, коментарів у коментарях чи коментарів у цитатах.

Це кодовий гольф, тому мінімальна кількість байтів виграє. Задавайте питання в коментарях, якщо специфікація не є чіткою.


На жаль, наші зміни там зіткнулися. : P Зараз все слід виправити.
Doorknob

@Doorknob Дякую за це, до речі. Не знаю , як зупинити SE від протирання простору.
абсент

Чи маємо ми обробляти вхідні речі в рядкових літералах (наприклад ("foo (\") bar"))?
Дверна ручка

1
Я заперечую, що правильний вихід для {{(})повинен бути { } або еквівалентним, оскільки сценарій відкриття передбачає, що код працював для початку, і {(})вважається невідповідними дужками в кожній мові програмування, яку я знаю (тобто "викликає застій" ??). Але, тоді я вже написав відповідь, тож я упереджений.
DLosc

3
Я бачу. Гадаю, я просто недостатньо некомпетентний. ;)
DLosc

Відповіді:


6

Рубі, 223 символи

Цей вийшов трохи довгим.

u,b,i=[],[[],[],[]],-1
s=gets.gsub(/(\/\*|"|').*?(\*\/|"|')|~/){|m|u+=[m];?~}
s.chars{|c|i+=1
(t='{[('.index(c))?b[t].push(i):((t='}])'.index(c))&&(b[t].pop||s[i]=' '))}
b.flatten.map{|l|s[l]=' '}
puts s.gsub(/~/){u.shift}

Що це робиться, це вийняти рядки та коментарі спочатку, щоб їх не рахувати (і повертає їх згодом).

Потім він проходить через рядок за символом. Коли він знаходить вступну дужку, вона зберігає своє положення. Коли він знаходить закриває дужку, він вискакує із відповідного відкритого масиву зберігання дужок.

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

В кінці програми вона повертає всі рядки та коментарі назад та виводить їх.

Безголовки:

in_str = gets

# grab strings and comments before doing the replacements
i, unparsed = 0, []
in_str.gsub!(/(\/\*|"|').*?(\*\/|"|')|\d/){|match| unparsed.push match; i += 1 }

# replaces with spaces the braces in cases where braces in places cause stasis
brace_locations = [[], [], []]
in_str.each_char.with_index do |chr, idx|
    if brace_type = '{[('.index(chr)
        brace_locations[brace_type].push idx
    elsif brace_type = '}])'.index(chr)
        if brace_locations[brace_type].length == 0
            in_str[idx] = ' '
        else
            brace_locations[brace_type].pop
        end
    end
end
brace_locations.flatten.each{|brace_location| in_str[brace_location] = ' ' }

# put the strings and comments back and print
in_str.gsub!(/\d+/){|num| unparsed[num.to_i - 1] }
puts in_str

Це серйозно вражає. Хоча одне запитання: чи все одно це буде працювати на вклад (("string"/*comment*/)"string"? Якщо я читаю правильно (версія, яка не використовується), ви замінюєте рядки та коментарі їх індексом у unparsedмасиві, що призведе до заміни, ((12)3а потім шукає неіснуючий індекс 12(або 11). Я бачу, що версія для гольфу просто використовується shift, але хіба вона все ще не має подібної проблеми?
DLosc

4

Пітон 3, 410 322 317

import re;a='([{';z=')]}';q=[re.findall('".*?"|/\*.*?\*/|.',input())]
while q:
 t=q.pop(0);s=[];i=0
 for x in t:
  if x in a:s+=[x]
  try:x in z and 1/(a[z.find(x)]==s.pop())
  except:s=0;break
 if[]==s:print(''.join(t));break
 while 1:
  try:
   while t[i]not in a+z:i+=1
  except:break
  u=t[:];u[i]=' ';q+=[u];i+=1

Пробує будь-який можливий набір видалень, починаючи з менших, до тих пір, поки він не знайде той, де брекети врівноважуються. (Під яким я маю на увазі повністю правильно збалансований: {{(})виробляє( ) , а не {(}))

У першій версії була використана рекурсивна функція генератора, яка була дійсно крутою, але також дуже довгою. Ця версія виконує простий пошук у ширину за допомогою черги. (Так, це алгоритм факторіального часу. У чому проблема?: ^ D)


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

2

С - 406

Спроба на C без використання регулярних виразів.

#define A if((d==125||d==93||d==41)
char*s;t[256];f(i,m,n,p){while(s[i]!=0){int c=s[i],k=s[i+1],v=1,d;if((c==42&&k==47)||(c==m&&i>n))return i;if(!p||p==2){if((c==39||c==34)||(c==47&&k==42)){i=f(i,c*(c!=47),i,p+1);
c=c==47?42:c;}d=c+1+1*(c>50);A){v=f(i+1,d,i,2);if(!p&&v)t[d]++;if(p==2&&v)i=v;}}d=c;A&&!p){v=!!t[c];t[c]-=v;}if(p<2)putchar(c*!!v+32*!v);i++;}return 0;}main(int c,char*v[]){s=v[1];f(0,0,0,0);}

Для компіляції та запуску (на машині Linux):
gcc -o дужки brackets.c
brackets.c ./brackets "[(])"

У невизначених випадках, як [(]), він повертає останню дійсну пару дужок ()


2

Пітон 3, 320

import re
O=dict(zip('([{',')]}'))
def o(s,r,m=0,t=[]):m+=re.match(r'([^][)({}/"]|/(?!\*)|/\*.*?\*/|".*?")*',s[m:]).end();return r and o(s[:m]+' '+s[m+1:],r-1,m+1,t)or(o(s,r,m+1,t+[O[s[m]]])if s[m]in O else[s[m]]==t[-1:]and o(s,r,m+1,t[:-1]))if s[m:]else not t and s
s=input();i=0;a=0
while not a:a=o(s,i);i+=1
print(a)

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


Добре зіграний, добре зіграний. Мені вдалося зійти до 317, але я думаю, ви повинні пройти це досить легко. (Тим часом, моя програма все ще вибивається на ваш приклад прикладу ...)
DLosc

@DLosc: Не затримуй дихання :). Моїй машині знадобилося 58 хвилин, щоб зробити версію цього малюнка з 6 відкритими паролями. Щоб вирішити застій до того, як Всесвіт досягне теплової смерті, вам потрібно буде запам'ятати чергу; інакше ви закінчуєте O(n!!)рішення, а не O(n!). (Мій гольф O(n*2^n)замість цього O(2^n), тому що oнасправді виробляє всі шаблони з rвилученнями, а не точно rвидаленнями. Легко виправити, але це коштуватиме декількох символів.)
rici
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.