С Новым годом! Форум программистов, компьютерный форум, киберфорум
Haskell
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.76/21: Рейтинг темы: голосов - 21, средняя оценка - 4.76
2 / 2 / 0
Регистрация: 10.08.2013
Сообщений: 73

Проверка правильности расстановки скобок в строке

23.11.2014, 04:24. Показов 4141. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет, с программированием пока еще далеко не на "ты". Не пойму как определить функции, которые проверяют правильность расстановки скобок в строке, т.е если есть открывающая, то должна быть и закрывающая. Функция принимает строку и выдает булево значение. Помогите пожалуйста с кодом или хотя бы подскажите, в какую сторону писать программу.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.11.2014, 04:24
Ответы с готовыми решениями:

Предикат, проверяющий правильность расстановки скобок в исходной строке
Создайте предикат, проверяющий правильность расстановки скобок в исходной строке.

Проверка правильности расстановки скобок в строке
Проверка строки на правильность написания То есть (5-6)*(5-6) правильно )5-6(*(5-6) неправильно

Проверка правильности расстановки скобок в строке (рекурсия)
Помогите написать рекурсивную функцию, проверяющую правильность расстановки скобок в строке. Правильные скобочные структуры: () ({}) ...

24
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
23.11.2014, 10:13
Используешь счётчик уровней вложенности. Вначале он ноль.
Идёшь по символам строки. Если встретилась открывающая скобка - увеличиваешь счётчик, если встретилась закрывающая - то, если счётчик равен нулю - возвращаешь False, иначе уменьшаешь счётчик. В конце строки он должен быть ноль.
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
23.11.2014, 12:02
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Используешь счётчик уровней вложенности.
лучше список. можно будет разные скобки отлавливать типа [)
0
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
23.11.2014, 12:51
Цитата Сообщение от pycture
лучше список. можно будет разные скобки отлавливать
В смысле, список использовать как стек. Уху.
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38167 / 21102 / 4307
Регистрация: 12.02.2012
Сообщений: 34,690
Записей в блоге: 14
23.11.2014, 13:27
Вот вариант контроля скобок одного вида:

Haskell
1
2
3
4
5
6
7
8
9
pCheck' :: String -> Int -> Bool
pCheck' "" n = (n==0)
pCheck' (s:ss) n | (s == '(') = pCheck' ss (n+1)
                 | (s == ')') && (n==0) = False
                 | (s == ')') = pCheck' ss (n-1)
                 | otherwise = pCheck' ss n
                 
pCheck :: String -> Bool
pCheck s = pCheck' s 0
1
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
23.11.2014, 13:41
Haskell
1
2
3
4
5
6
7
8
bracketsCheck:: String -> Bool
bracketsCheck = go 0
  where go i [] = i == 0
        go i ('(':xs) = go (i+1) xs
        go i (')':xs)
            | i == 0 = False
            | otherwise = go (i-1) xs
        go i (_:xs) = go i xs
Добавлено через 2 минуты
Можно и так
Haskell
1
2
3
4
5
6
7
bracketsCheck:: String -> Bool
bracketsCheck = go 0
  where go i [] = i == 0
        go i ('(':xs) = go (i+1) xs
        go 0 (')':xs) = False
        go i (')':xs) = go (i-1) xs
        go i (_:xs) = go i xs
1
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,989
Записей в блоге: 32
23.11.2014, 17:17
Мои мозги с таким треском и скрипом осваивают технологии Haskell, но в данном случае я бы сделал так:
Haskell
1
test = 0==sum $ map (\x -> (if x=='(' then 1 else if x==')' then (-1) else 0))
Пишу с другого компа, интерпретатора нет, проверить синтаксис не могу, но суть думаю понятна.

Добавлено через 5 минут
ЗЫ но да, вот такие строки ")))a+b(((" тогда будут считаться корректными. Но корректность скобок это вообще отдельная тема, я как-то закидывал этот провокационный тезис, что главное - однозначно задать приоритет операций, а там хоть как извращаться можно, и в этом смысле последняя запись тоже является корректной.

Вот попробовал непроверенные фантазии через свертку:
Добавлено через 3 минуты
Haskell
1
test s = 0==foldl (\a x -> if a<0 then minBound::Int else if x=='(' then a+1 else if x==')' then a-1 else a) 0
1
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
23.11.2014, 17:17
Haskell
1
2
3
4
Prelude> let test s = 0==sum (map (\x -> (if x=='(' then 1 else if x==')' then (-1) else 0)) s)
Prelude> test ")("
True
Prelude>
Берегите мозги - это весч!
1
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38167 / 21102 / 4307
Регистрация: 12.02.2012
Сообщений: 34,690
Записей в блоге: 14
23.11.2014, 17:44
Постное, но, кажется, вполне рабочее решение:

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pCheck'' :: String -> String -> Bool
pCheck'' "" [] = True
pCheck'' "" _  = False
pCheck'' (s:ss) q | (s == '(') = pCheck'' ss ('(' : q)
                  | (s == '[') = pCheck'' ss ('[' : q)
                  | (s == '{') = pCheck'' ss ('{' : q)
                  | (s == ')') && (q == []) = False
                  | (s == ']') && (q == []) = False
                  | (s == '}') && (q == []) = False
                  | (s == ')') = if (head q)=='(' then pCheck'' ss $ tail q else False
                  | (s == ']') = if (head q)=='[' then pCheck'' ss $ tail q else False
                  | (s == '}') = if (head q)=='{' then pCheck'' ss $ tail q else False
                  | otherwise = pCheck'' ss q
                  
pCheck :: String -> Bool
pCheck s = pCheck'' s ""
1
165 / 164 / 23
Регистрация: 23.02.2011
Сообщений: 347
25.11.2014, 12:48
Haskell
1
2
3
4
5
6
7
8
9
10
forward  = [('(',')'),('[',']'),('{','}')]
backward = map (\(a,b) -> (b,a)) forward 
loop acc [] = null acc
loop acc (sym:tail)
    | Just _ <- lookup sym forward = loop (sym:acc) tail
    | (Just c, c':acc') <- (lookup sym backward, acc) = (c == c') && loop acc' tail
    | Just c <- lookup sym backward = False
    | otherwise = loop acc tail
 
check = loop []
Добавлено через 9 минут
или еще короче на свертках
Haskell
1
2
3
4
5
6
7
8
9
forward  = [('(',')'),('[',']'),('{','}')]
backward = map (\(a,b) -> (b,a)) forward 
loop sym stack
    | Just _ <- lookup sym forward = Just (sym:stack)
    | (Just c, c':stack') <- (lookup sym backward, stack), c == c' = Just stack'
    | Just c <- lookup sym backward = Nothing
    | otherwise = Just stack
 
check line = foldl (\a s -> a >>= (loop s)) (Just []) line == Just []
3
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,989
Записей в блоге: 32
25.11.2014, 14:07
По-кустарному, из градусников:
Haskell
1
2
3
4
5
6
7
8
9
import Data.Text as T
 
test s = txr $ T.filter (flip elem "()[]{}").T.pack $ s where
    txr t = let re sr = T.replace (T.pack sr) (T.pack "")
                t' = re "()".re "[]".re "{}" $ t
                lt' = T.length t' in case lt' of
        0 -> True
        _|(lt' == T.length t) -> False
        _ -> txr t'
1
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
25.11.2014, 14:24
Без списка-стека
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Data.Maybe(isJust)
 
bracketsCheck:: String -> Bool
bracketsCheck = isJust . (go Nothing)
  where go Nothing [] = Just []
        go _       [] = Nothing 
        go c ('(':sx) = br c (Just ')') sx
        go c ('[':sx) = br c (Just ']') sx
        go c ('{':sx) = br c (Just '}') sx
        go c (s:sx) 
            | c == (Just s) = Just sx
            | s `elem` ")]}" = Nothing
            | otherwise = go c sx
        br o n sx = case go n sx of
                      (Just s) -> go o s
                      Nothing  -> Nothing
1
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,989
Записей в блоге: 32
25.11.2014, 16:52
Те же стринг-реплейсы, но без библиотек, с самодельными кустарными градусниками
Haskell
1
2
3
4
5
6
7
8
9
10
test s = txr $ filter (flip elem "()[]{}") s where
    txr s = let re _ []  = []
                re _ [c] = [c]
                re r (c1:c2:cs) = if [c1,c2]==r then re r cs else (c1:(re r (c2:cs)))
                s' = re "()".re "[]".re "{}" $ s
                ls' = length s'
        in case ls' of
            0 -> True
            _|(ls' == length s) -> False
            _ -> txr s'
2
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
25.11.2014, 19:48
Цитата Сообщение от _Ivana Посмотреть сообщение
По-кустарному, из градусников
это не из градусников. градусник вот где http://hackage.haskell.org/package/parsec
0
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
25.11.2014, 20:13
Цитата Сообщение от pycture
это не из градусников. градусник вот где http://hackage.haskell.org/package/parsec
Дык, мне этот градусник показался через чур тяжёлым. Сможете эту задачу (с разными видами скобок) им решить, так, чтобы короче получилось?
По скорости, кстати, он тоже тормоз. В реальной задаче пришлось от него отказаться, в более ручном режиме распарсить. Может я его готовить не умею. Хотя Real World Haskell, 16-ую главу читывал.
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
26.11.2014, 09:11

Не по теме:

Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Сможете эту задачу (с разными видами скобок) им решить, так, чтобы короче получилось?
на хаскеле врядли - ставить лень. мож потом на f# попоробую, там порт fparsec есть, долно не сильно отличаться



Добавлено через 10 часов 5 минут
ну как то так (f#)
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
open FParsec
 
let body, bodyImpl = createParserForwardedToRef ()
let innerbody = many1 (noneOf "([{)]}")
let bracker (b : string) = pchar b.[0] >>. (body |>> (List.collect id)) .>> pchar b.[1]
let brack     = bracker "()" <|> bracker "[]" <|> bracker "{}"
do bodyImpl  := many (brack <|> innerbody)
 
do
    let test x = 
        match run (body .>> eof) x with
        | Success (r,_,_) -> printfn "%A\t%A" x r
        | Failure (a,b,c) -> printfn "%A\t--- > Fail at %A" x b.Position
    test "()"       // "()"    [[]]
    test "a(a)a"    // "a(a)a" [['a']; ['a']; ['a']]
    test "a(a]a"    // "a(a]a" --- > Fail at (Ln: 1, Col: 4)
    test "(o)"      // "(o)"   [['o']]
    test "(("       // "(("    --- > Fail at (Ln: 1, Col: 3)
    test "))"       // "))"    --- > Fail at (Ln: 1, Col: 1)
    test "a)a(a"    // "a)a(a" --- > Fail at (Ln: 1, Col: 2)
Добавлено через 6 минут
на хаскеле должно еще проще записаться, там заморочек с createParserForwardedToRef скорее всего нету
2
Модератор
 Аватар для Curry
5153 / 3465 / 536
Регистрация: 01.06.2013
Сообщений: 7,527
Записей в блоге: 9
26.11.2014, 12:49
pycture, переписал Ваш код на Хаскелл. Довольно компактно. Беру свои слова взад, насчёт тяжёловесности parsec-а. Просто я не умею его готовить.
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
import Text.ParserCombinators.Parsec
import Data.Either(isRight)
 
innerbody = many1 (noneOf "([{)]}") 
 
bracker [l,r] = char l >> bodyImpl >> char r >> return ""
 
brack = bracker "()" <|> bracker "[]" <|> bracker "{}"
 
bodyImpl  = many (brack <|> innerbody)
 
test:: String -> Bool  
test = isRight . parse (bodyImpl >> eof) ""
2
2 / 2 / 0
Регистрация: 10.08.2013
Сообщений: 73
27.11.2014, 23:15  [ТС]
Цитата Сообщение от Catstail Посмотреть сообщение
Вот вариант контроля скобок одного вида:
Haskell
1
2
3
4
5
6
7
8
pCheck' :: String -> Int -> Bool   -- определяем вспомогательную функцию
pCheck' "" n = (n==0)                 -- передаем в параметр строку из первой функции и счетчик (почему ему отдельно еще значение присвоено)?
pCheck' (s:ss) n | (s == '(') = pCheck' ss (n+1) -- разбиваем строку на голову и остальную часть, проверяем рекурсивно всю строку по символу 
                       | (s == ')') && (n==0) = False -- тут ясно всё
                       | (s == ')') = pCheck' ss (n-1) -- тут тоже частично ясно
                       | otherwise = pCheck' ss n     -- в остальных случаях оставляем всё как есть? так читается эта строка? почему тогда не s а ss?
pCheck :: String -> Bool -- основная функция
pCheck s = pCheck' s 0  -- вызываем вспомогательную функцию
я правильно понял программу?
0
4949 / 2289 / 287
Регистрация: 01.03.2013
Сообщений: 5,989
Записей в блоге: 32
28.11.2014, 00:06
Имхо, нет.
Haskell
1
2
3
4
5
6
7
8
9
10
pCheck' :: String -> Int -> Bool   --  задаем тип вспомогательной функции
pCheck' "" n = (n==0)                 -- определяем ее значение при первом параметре, равном ""
-- определяем ее значение или параметры (! если осуществляем рекурсивный вызов)
-- в остальных случаях по условиям
pCheck' (s:ss) n | (s == '(') = pCheck' ss (n+1) -- рекурсивный вызов с хвостом строки и измененным параметром
                       | (s == ')') && (n==0) = False -- сразу возвращаем фалс не разбирая дальше строку
                       | (s == ')') = pCheck' ss (n-1) -- рекурсивный вызов с хвостом строки и измененным параметром
                       | otherwise = pCheck' ss n -- рекурсивный вызов с хвостом строки и неизмененным параметром
pCheck :: String -> Bool -- задаем тип основной функции
pCheck s = pCheck' s 0  -- вызываем вспомогательную функцию
Добавлено через 11 минут
ЗЫ в императивном стиле это можно переписать примерно так
Haskell
1
2
3
4
5
6
7
8
9
10
11
pCheck' :: String -> Int -> Bool
pCheck' str n = if str == "" then (n == 0) else
    if s == '(' then pCheck' ss (n+1) else
    if s == ')' && (n==0) then False else
    if s == ')' then pCheck' ss (n-1)
    else pCheck' ss n
    where
        ss = tail str
        s = head str
pCheck :: String -> Bool -- задаем тип основной функции
pCheck s = pCheck' s 0  -- вызываем вспомогательную функцию
Если окружить скобками вызовы внутри if|else, то это и скомпилируется и даже будет работать (попробуйте добиться этого), точно так же, как и исходная функция, записанная в декларативной манере. Но вам вариант с явно написанными условиями может показаться понятнее, как и мне.

Добавлено через 22 минуты
Собственно, перевод на императивный С:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
Bool pCheck (char * s, int n)
{
    if (*s == 0) return (n == 0) else
    if (*s == '(') return pCheck (s+1, n+1) else
    if (*s == ')' && n == 0) return False else
    if (*s == ')') return pCheck (s+1, n-1)
    else return pCheck (s+1, n);
}
 
Bool pCheckFinal (char * s)
{
    return pCheck (s, 0);
}
2
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38167 / 21102 / 4307
Регистрация: 12.02.2012
Сообщений: 34,690
Записей в блоге: 14
28.11.2014, 11:41
snzh, "в остальных случаях" не оставляем все как есть, а применяем функцию к остатку строки.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.11.2014, 11:41
Помогаю со студенческими работами здесь

Проверка правильности расстановки скобок
Задача Bracket. В сложных математических выражениях приходится иногда ставить много скобок. Часто бывает трудно посчитать, сколько скобок...

Проверка правильности расстановки скобок
Преподаватель поставила сегодня в тупик вопросом. Как с помощью оператора выбора Case проверить правильность расстановки скобок ? ...

Проверка правильности расстановки скобок
#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include&lt;locale.h&gt; struct stack { int size;//размер стека char * st;//добавляем...

Проверка правильности расстановки скобок
Помогите с заданием Строка содержит арифметическое выражение, в котором используются круглые скобки, в том числе вложенные. Проверить,...

Проверка правильности расстановки скобок
В арифметическом выражении, записанном в одну строку, есть круглые, квадратные и фигурные скобки. Верно записано выражение?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru