Удаление скобок из строки

25

Если в качестве входных данных правильно задана строка в скобках, выведите список всех непустых подстрок в соответствующих скобках (или за пределами всех скобок) с удалением вложенных скобок. Каждая подстрока должна быть последовательностью символов в одинаковых совпадающих скобках. Подстроки должны быть перечислены в порядке глубины, а подстроки той же глубины должны быть перечислены в порядке их появления в строке. Предположим, что входные данные всегда правильно заключены в скобки.

Вы можете предположить, что ввод содержит только строчные буквы ASCII и круглые скобки.

Ваш ответ должен быть функцией, которая при задании строки возвращает список строк.

Примеры:

                   'a(b)c(d)e' -> ['ace', 'b', 'd']
                   'a(b(c)d)e' -> ['ae', 'bd', 'c']
                  'a((((b))))' -> ['a', 'b']
                        'a()b' -> ['ab']
                            '' -> []
                           'a' -> ['a']
          '(((a(b)c(d)e)f)g)h' -> ['h', 'g', 'f', 'ace', 'b', 'd']
'ab(c(((d)ef()g)h()(i)j)kl)()' -> ['ab', 'ckl', 'hj', 'efg', 'i', 'd']

Побеждает несколько байтов.

redstonerodent
источник
Находятся ли 'i'и 'd'в правильном порядке в последнем тесте?
PurkkaKoodari
@ Pietu1998 iменее глубоко вложен, чем d.
feersum
@feersum Да, верно.
PurkkaKoodari
1
Не могли бы вы разрешить и другие стандартные типы представления, в частности полные программы? Не все языки имеют понятие функций. Консенсус по умолчанию см. В meta.codegolf.stackexchange.com/a/2422/8478 и meta.codegolf.stackexchange.com/questions/2447/… .
Мартин Эндер
2
@redstonerodent Формулировка, которую я обычно использую: «Вы можете написать программу или функцию, используя ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции и выводя результат через STDOUT (или ближайшую альтернативу), возвращаемое значение функции или функциональный (выходной) параметр. " и в вашем случае «Вывод может быть в любом удобном, однозначном, плоском формате списка».
Мартин Эндер

Ответы:

11

JavaScript ES6, 91 93 104 133 148

Edit2 2 байта сохранено thx user81655

Редактировать, используя больше строк и меньше массивов

Протестируйте приведенный ниже фрагмент в браузере, совместимом с EcmaScript 6

f=s=>[...s].map(c=>l+=c<')'||-(o[l]=(o[l]||'')+c,c<'a'),o=[],l=0)&&(o+'').match(/\w+/g)||[]

// Less golfed

u=s=>{
  o=[]; l=0;
  [...s].map(c=>{
    if (c>'(') // letters or close bracket
      o[l]=(o[l]||'')+c, // add letter or close bracket to current level string
      l-=c<'a' // if close bracket, decrement level
    else
      ++l // open bracket, increment level
  })
  o = o+'' // collapse array to comma separated string
  return o.match(/\w+/g)||[] // fetch non empty strings into an array
}

// TEST
console.log=x=>O.innerHTML+=x+'\n'

;[ 'a(b)c(d)e'                    // ['ace', 'b', 'd']
 , 'a(b(c)d)e'                    // ['ae', 'bd', 'c']
 , 'a((((b))))'                   // ['a', 'b']
 , 'a()b'                         // ['ab']
 , ''                             // []
 , 'a'                            // ['a']
 , '(((a(b)c(d)e)f)g)h'           // ['h', 'g', 'f', 'ace', 'b', 'd']
 , 'ab(c(((d)ef()g)h()(i)j)kl)()' // ['ab', 'ckl', 'hj', 'efg', 'i', 'd']
].forEach(t=>console.log(t +" -> " + f(t)))
<pre id=O></pre>

edc65
источник
Сохранить 2 байта с c=>l+=c<')'||-(o[l]=(o[l]||'')+c,c<'a'),.
user81655
@ user81655 здорово, спасибо
edc65
8

Юлия, 117 86 83 байта

v->(while v!=(v=replace(v,r"(\(((?>\w|(?1))*)\))(.*)",s"\g<3> \g<2>"))end;split(v))

Это регулярное решение.

Ungolfed:

function f(v)
  w=""
  while v!=w
    w=v
    v=replace(v,r"(\(((?>\w|(?1))*)\))(.*)",s"\g<3> \g<2>"))
  end
  split(v)
end

r"(\(((?>\w|(?1))*)\))(.*)"является рекурсивным (?1)регулярным выражением ( группа рекурсивов 1), которое будет соответствовать первым наиболее сбалансированным круглым скобкам (которые не содержат несбалансированные / обращенные круглые скобки), причем вторая группа содержит все внутри скобок (не включая сами скобки), а третья группа содержит все после скобок (до конца строки).

replace(v,r"...",s"\g<3> \g<2>")затем переместит вторую группу в конец строки (после пробела, чтобы действовать как разделитель), с удалением соответствующих скобок. Итерируя до v == w, гарантируется, что замена повторяется до тех пор, пока не останется скобок. Поскольку совпадения перемещаются в конец, а затем следующее совпадение идет для первой круглой скобки, результатом будет строка, разбитая в порядке глубины.

Затем splitвозвращает все непробельные компоненты строки в виде массива строк (которые не имеют пробелов).

Обратите внимание, что w=""он используется в коде ungolfed, чтобы убедиться, что цикл while выполняется хотя бы один раз (за исключением, разумеется, если строка ввода пустая) и не требуется в форме для игры в гольф.

Спасибо Мартину Бюттнеру за помощь в сохранении 3 байтов.

Глен О
источник
Аккуратно, я пришел к тому же решению независимо от Retina. Там 44 байта, но полнопрограммные решения не допускаются. : /
Мартин Эндер
Вы можете сохранить три байта, используя \wвместо [^()].
Мартин Эндер
@ MartinBüttner - спасибо. Я действительно подумал об этом, но я волновался, что что-то упустил из виду и что это потерпит неудачу в каком-то крайнем случае. Если вы говорите, что это хорошо, тогда это нормально.
Глен О
6

Python, 147 байт

def f(s):
 d=0;r=[['']for c in s]
 for c in s:
  if c=='(':d+=1;r[d]+=['']
  elif c==')':d-=1
  else:r[d][-1]+=c
 return[i for i in sum(r,[])if i]

Модульные тесты:

assert f('a(b)c(d)e') == ['ace', 'b', 'd']
assert f('a(b(c)d)e') == ['ae', 'bd', 'c']
assert f('a((((b))))') == ['a', 'b']
assert f('a()b') == ['ab']
assert f('') == []
assert f('a') == ['a']
assert f('(((a(b)c(d)e)f)g)h') == ['h', 'g', 'f', 'ace', 'b', 'd']
assert f('ab(c(((d)ef()g)h()(i)j)kl)()') == ['ab', 'ckl', 'hj', 'efg', 'i', 'd']

Мне нравится эта головоломка; это очень мило!

Quuxplusone
источник
4

Pyth, 32 байта

fTscR)uX0.<GJ-FqLH`()@[Hdk)Jzmkz

Тестирование

Свободно основанный на подходе @ Quuxplusone. Создает разделенные пробелами списки символов на каждой глубине, затем разбивает их и отфильтровывает пустые группы. Рабочий список вращается, чтобы сохранить список текущей глубины всегда впереди.

isaacg
источник
4

Retina , 44 41 байт

+`\(((\w|(\()|(?<-3>.))*).(.*)
$4 $1
S_` 

Беги с -sфлагом. Обратите внимание на пробел в конце последней строки.

Я придумал это решение независимо от Глена О, но оно оказалось идентичным. Идея состоит в том, чтобы сопоставить первую пару скобок, удалить ее и вставить ее содержимое в конец вывода (повторно). Из-за отсутствия рекурсии в .NET мне пришлось использовать группы балансировки, которые на четыре байта длиннее.

Если вы не понимаете первое регулярное выражение, позвольте мне направить вас к моему SO-ответу о балансировке групп . Так как вход гарантированно будет правильно круглыми скобками, мы можем сохранить два байт путем сопоставления )с .вместо \). Затем мы просто сопоставляем остальную часть строки с (.*). $4 $1сначала записывает указанную оставшуюся часть строки (без скобок и их содержимого), а затем содержимое скобок после пробела. +`Говорит Retina повторить этот шаг , пока строка не перестает меняться (что случается только один раз все скобки были удалены).

Пустые скобки приведут к двум последовательным пробелам, поэтому, наконец, мы разбиваем всю строку на пробелы ( S`активирует режим разделения, а регулярное выражение представляет собой один пробел). _Опция указывает Retina пропустить пустые части раскола, поэтому мы не включаем в пустые результаты в выходном сигнале.

Мартин Эндер
источник
3

Common Lisp, 160

(lambda(x)(labels((g(l)(cons(#1=format()"~(~{~A~}~)"(#2=remove-if'listp l))(mapcan #'g(#2#'atom l)))))(remove""(g(read-from-string(#1#()"(~A)"x))):test'equal))))

Это может быть на четыре байта меньше, если преобразование регистра не требуется. Идея состоит в том, чтобы добавить левую и правую круглые скобки к каждой стороне входной строки, обработать ее как список, записать элементы верхнего уровня списка в строку, а затем обработать подсписки таким же образом.

Джошуа Тейлор
источник
2

Haskell, 114 112 111 байтов

')'%(h:i:t)=("":i):t++[h]
'('%l=last l:init l
c%((h:i):t)=((c:h):i):t
g x=[a|a<-id=<<foldr(%)(x>>[[""]])x,a>""]

Пример использования: g "ab(c(((d)ef()g)h()(i)j)kl)()"-> ["ab","ckl","hj","efg","i","d"].

Я иду назад через строку ввода. Промежуточная структура данных представляет собой список строк. Внешний список для уровня и внутренний список для группы в пределах уровня, например [["ab"],["ckl"],["hj"],["efg","i"],["d"]](примечание: реальный список содержит много пустых промежуточных строк). Все начинается с количества пустых строк, равного длине ввода - более чем достаточно, но пустые списки все равно отфильтровываются. Внешние списки либо поворачивается на (/ )или добавляет характер к переднему элементу. )также начинает новую группу.

Редактировать: @Zgarb нашел байт для сохранения.

Ними
источник
1

Sed, 90 байт

:
s/^(\w*)\((.*)\n?(.*)/\1\n\3_\2/M
s/(\n\w*_)(\w*)\)(.*)/\3\1\2/M
t
s/[_\n]+/,/g
s/,$//

Использует расширенные регулярные выражения ( -rфлаг), на которые приходится +1 байт. Также для этого используется расширение GNU ( Mфлаг в sкоманде).

Пример использования:

$ echo 'ab(c(((d)ef()g)h()(i)j)kl)()' | sed -r -f deparenthesize.sed
ab,ckl,hj,efg,i,d

Объяснение: Поскольку sed не поддерживает такие вещи, как рекурсивные регулярные выражения, требуется ручная работа. Выражение разбито на несколько строк, каждая из которых представляет уровень глубины вложения. Отдельные выражения на одной и той же глубине (и, следовательно, на одной и той же строке) разделяются знаком _. Скрипт обрабатывает входную строку по одной скобке за раз. Остальные входные данные всегда сохраняются в конце строки, которая соответствует текущему уровню вложенности.

Мац
источник
0

Python, 161 байт

Вот то, что я придумал, однострочное функциональное решение Python:

p=lambda s:filter(None,sum([''.join([s[i]for i in range(len(s))if s[:i+1].count('(')-s[:i+1].count(')')==d and s[i]!=')']).split('(')for d in range(len(s))],[]))

Эта проблема была вдохновлена https://github.com/samcoppini/Definition-book , которая выводит длинную строку со словом, определенным в скобках. Я хотел написать код, который давал бы мне каждое предложение со снятыми скобками. Функциональное решение слишком медленное, чтобы быть эффективным на длинных строках, но императивные решения (такие как решение @ Quuxplusone) намного быстрее.

redstonerodent
источник