Вы можете использовать функцию, которая просто проходит по строке, отслеживая стек индексов открывающих скобок. Всякий раз, когда вы сталкиваетесь с закрывающей скобкой, вы знаете, что она соответствует индексу на вершине стека.
Например:
parenPairs :: String -> [(Int, Int)]
parenPairs = go 0 []
where
go _ _ [] = []
go j acc ('(' : cs) = go (j + 1) (j : acc) cs
go j [] (')' : cs) = go (j + 1) [] cs -- unbalanced parentheses!
go j (i : is) (')' : cs) = (i, j) : go (j + 1) is cs
go j acc (c : cs) = go (j + 1) acc cs
Эта функция возвращает список всех пар индексов, принадлежащих парам совпадающих скобок.
Применение функции к вашей строке примера дает:
> parenPairs "abc(def(gh)il(mn(01))afg)lmno(sdfg*)"
[(7,10),(16,19),(13,20),(3,24),(29,35)]
Интересующая вас открывающая скобка отображается в индексе 3. Возвращаемый список показывает, что соответствующая закрывающая скобка находится в индексе 24.
Следующие функции дают вам все правильно заключенные в скобки сегменты строки:
parenSegs :: String -> [String]
parenSegs s = map (f s) (parenPairs s)
where
f s (i, j) = take (j - i + 1) (drop i s)
Например:
> parenSegs "abc(def(gh)il(mn(01))afg)lmno(sdfg*)"
["(gh)","(01)","(mn(01))","(def(gh)il(mn(01))afg)","(sdfg*)"]
Следуя предложению Фрериха Раабе, теперь мы также можем написать функцию, которая возвращает только крайний левый сегмент:
firstParenSeg :: String -> String
firstParenSeg s = f s (minimum (parenPairs s))
where
f s (i, j) = take (j - i + 1) (drop i s)
Например:
> firstParenSeg "abc(def(gh)il(mn(01))afg)lmno(sdfg*)"
"(def(gh)il(mn(01))afg)"
Обратите внимание, что firstParenSeg
завершится ошибкой, если входная строка не содержит хотя бы одной пары совпадающих скобок.
Наконец, небольшая адаптация функции parenPairs
позволяет ей не работать с несбалансированными скобками:
parenPairs' :: String -> [(Int, Int)]
parenPairs' = go 0 []
where
go _ [] [] = []
go _ (_ : _ ) [] = error "unbalanced parentheses!"
go j acc ('(' : cs) = go (j + 1) (j : acc) cs
go j [] (')' : cs) = error "unbalanced parentheses!"
go j (i : is) (')' : cs) = (i, j) : go (j + 1) is cs
go j acc (c : cs) = go (j + 1) acc cs
person
Stefan Holdermans
schedule
20.04.2012