Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Microsoft Office (Word, Excel, Outlook и т.д.) (http://forum.oszone.net/forumdisplay.php?f=115)
-   -   Проверка на правильность написанных данных (http://forum.oszone.net/showthread.php?t=321690)

Invincible 13-12-2016 17:55 2695405

Проверка на правильность написанных данных
 
Всем привет. Можете помочь с макросом, который будет проверять каждую ячейку столбца и в том случае, если в тексте ячейки присутствует ошибка в проставлении скобок, останавливать работу макроса и выводить сообщение, в каком месте листа макрос обнаружил ошибку. Например, запись «Текст(текст)» будет правильно, а такая – «Текст)текст(» или «((( )) () ))» будут неправильными и для них следует вывести сообщение об ошибке.

Iska 13-12-2016 19:16 2695429

1. В тексте или в формуле?
2. А такая: «(())(())»?
3. Образец документа/рабочей книги на «поиграться» в студию!

Invincible, вот примерная болванка кода, рассчитана на один тип скобок, функция проверки согласованности скобок возвращает булево значение:
Код:

Option Explicit

Sub Sample()
    Debug.Print CheckBrackets("Текст(текст)")
    Debug.Print CheckBrackets("Текст)текст(")
    Debug.Print CheckBrackets("((( )) () ))")
   
    Debug.Print CheckBrackets("((( )( ))( ))")
    Debug.Print CheckBrackets("(()(((()))")
End Sub

Function CheckBrackets(strString As String) As Boolean
    Dim i As Integer
    Dim currLevel As Integer
   

    currLevel = 0

    For i = 1 To Len(strString)
        Select Case Mid(strString, i, 1)
            Case "("
                currLevel = currLevel + 1
            Case ")"
                currLevel = currLevel - 1
            Case Else
                ' Nothing to do
        End Select
   
        If currLevel < 0 Then
            CheckBrackets = False
           
            Exit Function
        End If
    Next
   
    CheckBrackets = currLevel = 0
End Function

Всё прочее:
Цитата:

Цитата Invincible
проверять каждую ячейку столбца »

Цитата:

Цитата Invincible
останавливать работу макроса и выводить сообщение, в каком месте листа макрос обнаружил ошибку. »

— после предоставления образца документа/Рабочей книги.

Invincible 14-12-2016 23:11 2695800

Вложений: 1
Цитата:

Цитата Iska
В тексте или в формуле? »

В тексте.
Цитата:

Цитата Iska
А такая: «(())(())»? »

Подходит, нужно чтобы на каждую открывающуюся скобку была закрывающая. Если какой-то скобки не хватает выдавать ошибку или на несоответствующую скобку.
Цитата:

Цитата Iska
3. Образец документа/рабочей книги на «поиграться» в студию! »

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

Iska 15-12-2016 00:07 2695814

Вложений: 1
Цитата:

Цитата Invincible
Если какой-то скобки не хватает выдавать ошибку или на несоответствующую скобку. »

Я бы лучше выдавал сообщение Хорошо/Плохо и помечал бы ячейки с ошибкой.

Цитата:

Цитата Invincible
Тут лучше представить если значения вводятся в ячейку столбца, если ввели данные верно продолжается работа, если нет, то выводится ошибка. »

Ну, честно говоря, не хочется привязываться к функции OnChange. Не очень Excel приспособлен для таких вещей. Как по мне, так проще «ручками» вызвать макрос по кнопке/горячей клавише. Или хотя бы по кнопке на самом Рабочем листе [Проверить согласованность введённых данных!] (саму кнопку можно исключить из вывода на печать).

Примерно такой код:
Скрытый текст
Код:

Option Explicit

Sub CheckRangeInColumnH()
    Dim objErrorsRange As Range
    Dim objRange As Range
   
    Set objErrorsRange = Nothing
   
    With ThisWorkbook.Worksheets.Item("Лист1")
        For Each objRange In Intersect(.UsedRange, .Columns.Item("H"))
            Select Case LCase(TypeName(objRange.Value))
                Case "string"
                    If Not CheckBrackets(objRange.Value) Then
                        If objErrorsRange Is Nothing Then
                            objRange.Activate
                           
                            Set objErrorsRange = objRange
                        Else
                            Set objErrorsRange = Union(objErrorsRange, objRange)
                        End If
                    End If
                Case Else
                    ' Nothing to do
            End Select
        Next
    End With
   
    If objErrorsRange Is Nothing Then
        MsgBox "Ошибок не найдено", vbOKOnly + vbInformation, "Ошибок не найдено"
    Else
        objErrorsRange.Select
        MsgBox "Найдено " & CStr(objErrorsRange.Cells.Count) & " ошибок", vbOKOnly + vbExclamation, "Найдены ошибки"
       
        Set objErrorsRange = Nothing
    End If
End Sub

Function CheckBrackets(strString As String) As Boolean
    Dim i As Integer
    Dim currLevel As Integer
   

    currLevel = 0

    For i = 1 To Len(strString)
        Select Case Mid(strString, i, 1)
            Case "("
                currLevel = currLevel + 1
            Case ")"
                currLevel = currLevel - 1
            Case Else
                ' Nothing to do
        End Select
   
        If currLevel < 0 Then
            CheckBrackets = False
           
            Exit Function
        End If
    Next
   
    CheckBrackets = currLevel = 0
End Function


Все найденные ячейки с ошибками выделяются, и активной становится ячейка с первой найденной ошибкой (внутри выделения удобно перебирать ячейки клавишей «Tab»).

Прилагаю и саму рабочую книгу с макросом и кнопкой: Файл 142120.

Invincible 15-12-2016 00:17 2695819

Iska, Спасибо, буду пробовать.

Iska 15-12-2016 00:22 2695821

Invincible, я там упростил код немного. Убедитесь, что Вы забрали именно исправленный (хотя работать будет и первый вариант).

Invincible 16-12-2016 19:57 2696292

Iska, А можете добавить, чтобы макрос работал при переносе данных в другой столбец/лист?

Iska 16-12-2016 20:25 2696300

Invincible, можете и сами. Вот здесь:
Код:

With ThisWorkbook.Worksheets.Item("Лист1")
— лист. Вот здесь:
Код:

For Each objRange In Intersect(.UsedRange, .Columns.Item("H"))
— столбец. Другое дело, как тогда быть с кнопкой на самом листе.

Основной вопрос — как найти в Рабочей книге данные, которые требуется обрабатывать? Как, например, определить потребный лист? Самое простое и правильное — использовать активный рабочий лист, вместо указания конкретного. Но тогда нам нужно как-то исключить из возможной обработки те листы, на которых никак не может быть потребных данных.

Тот же вопрос касается и местоположения потребных данных — как их найти на Рабочем листе, как определить их точное местоположение? Вот, Вы пишете просто «столбец», но по сути же это может быть неверным. Может присутствовать заголовок таблицы, шапка таблицы/заголовки столбцов (причём, в несколько строк), промежуточные данные, подвал/итоги таблицы, подписи и т.п. элементы. Как? Можно, скажем, зная структуру таблицы и или/содержимое шапки таблицы/заголовков столбцов, задаться некими правилами и от этого танцевать.

Что скажете?

Invincible 18-12-2016 18:36 2696678

Iska, Можно сделать, чтобы обрабатывались только данные в которых присутствуют скобки "()"?
Я имел в виду чтобы написали данные в столбец "A" проверили их макросом, потом перенесли их в столбец "С" и макрос также среагировал как и в первом случае, затем перенесли на другой лист в любой столбец и результат работы макроса оставался тем же.

Iska 18-12-2016 20:42 2696704

Цитата:

Цитата Invincible
Iska, Можно сделать, чтобы обрабатывались только данные в которых присутствуют скобки "()"? »

Э… а как определить без обработки есть ли там скобки?!

Цитата:

Цитата Invincible
Я имел в виду чтобы написали данные в столбец "A" проверили их макросом, »

Как определить, что данные именно в столбце A? А не в B, и не в C, и не в D?

Цитата:

Цитата Invincible
потом перенесли их в столбец "С" »

Как определить, что данные именно в столбце A? А не в B, и не в C, и не в D?

Цитата:

Цитата Invincible
затем перенесли на другой лист в любой столбец »

Как определить, что данные именно в столбце A? А не в B, и не в C, и не в D? Насчёт более раннего предложения: искомый лист == активный лист — согласны?

Invincible 18-12-2016 21:05 2696707

Цитата:

Цитата Iska
искомый лист == активный лист — согласны? »

Да.
А можно тогда искомый столбец == активный столбец?

Iska 18-12-2016 21:40 2696713

Цитата:

Цитата Invincible
А можно тогда искомый столбец == активный столбец? »

Можно. Можно даже так: есть выделение на активном листе — проверяем только выделение, нет выделения (активна/выделена только одна ячейка) — проверяем заполненную часть столбца, содержащего эту ячейку. Поведение выделения после обработки — как в последнем макросе. Устроит?

Invincible 19-12-2016 01:00 2696750

Цитата:

Цитата Iska
проверяем заполненную часть столбца, содержащего эту ячейку. »

Если у меня курсор стоит на ячейке B2, то проверка будет проходить с B2 и до конца столбца B?

Iska 19-12-2016 01:26 2696753

Вложений: 1
Цитата:

Цитата Invincible
Если у меня курсор стоит на ячейке B2, то проверка будет проходить с B2 и до конца столбца B? »

Нет. По дипазону, образованному пересечением заполненного диапазона листа (.UsedRange) и столбца B. Если выделено больше одной ячейки — только в пределах этого выделения.

Попробуйте так: Файл 142208 (листы диаграммы, диалога были добавлены намеренно для иллюстрации поведения, никакой значимой ценности они не несут).

Invincible 21-12-2016 00:53 2697301

Цитата:

Цитата Iska
Можно. Можно даже так: есть выделение на активном листе — проверяем только выделение, нет выделения (активна/выделена только одна ячейка) — проверяем заполненную часть столбца, содержащего эту ячейку. Поведение выделения после обработки — как в последнем макросе. Устроит? »

То есть сейчас осуществляется поиск с активного столбца?

Iska 21-12-2016 01:28 2697312

Цитата:

Цитата Invincible
…осуществляется поиск с активного столбца? »

Не понял.

Invincible 21-12-2016 01:30 2697313

Цитата:

Цитата Iska
Не понял. »

На котором курсор стоит, я так понял из Вашей рабочей книги

Iska 21-12-2016 02:39 2697320

Поиск в этом случае осуществляется в диапазоне, представляющем собой пересечение (Intersect()) Используемого диапазона (.UsedRange) активного Рабочего листа (.ActiveSheet) и столбца (.Columns.Item()), в котором находится активная ячейка (Selection.Column). В целом определяется вот здесь:
Код:

            With .ActiveSheet ' На активном Рабочем листе
                If Selection.Count = 1 Then ' Если в выделении присутствует одна ячейка…
                    ' …то искомый диапазон находим пересечением Используемого диапазона
                    ' активного Рабочего листа и столбца, в котором находится активная ячейка.
                    Set objCheckRange = Intersect(.UsedRange, .Columns.Item(Selection.Column))
                Else
                    ' …иначе — ищем в самом выделении.
                    Set objCheckRange = Selection
                End If
               
                If Not objCheckRange Is Nothing Then ' Если искомый диапазон не пуст…


Invincible 21-12-2016 07:22 2697328

Iska, Но если выделена одна ячейка а поиск осуществляется по всему столбцу?

Invincible 21-12-2016 07:48 2697332

Iska, Можно еще последнее попросить, чтобы выводилось сообщение с адресом где обнаружилось ошибка. К примеру находится ошибка в ячейке A2, после нахождения ошибки выводится MsgBox с сообщением "Обнаружена ошибка в ячейке A2", потом например ошибка в ячейке A10, выводится еще один MsgBox с сообщением "Обнаружена ошибка в ячейке A10", и в самом конце уже MsgBox с сообщением "Всего найдено 2 ошибки".

Iska 21-12-2016 08:06 2697334

Цитата:

Цитата Invincible
Iska, Но если выделена одна ячейка а поиск осуществляется по всему столбцу? »

Invincible, что значит «но»?

Iska 21-12-2016 08:55 2697336

Цитата:

Цитата Invincible
чтобы выводилось сообщение с адресом где обнаружилось ошибка. К примеру находится ошибка в ячейке A2, после нахождения ошибки выводится MsgBox с сообщением "Обнаружена ошибка в ячейке A2", потом например ошибка в ячейке A10, выводится еще один MsgBox с сообщением "Обнаружена ошибка в ячейке A10", »

Эти сообщения никак не будут помогать (ибо адреса банально забудутся), а станут только неимоверно раздражать. Разве недостаточно того, что ошибочные ячейки выделяются?

Я же написал, что внутри выделения, которым помечаются ошибки, надо использовать клавишу Tab (или Enter при редактировании), но не клавиши управления курсором. Вот у нас нашлись ошибки, вывелось сообшение об их общем числе и выделились ячейки с ошибками, активной стала ячейка с первой найденной ошибкой. Нажимаете F2, исправляете ошибку, нажимаете Tab или Enter, переходя тем самым к следующей в выделении ячейке с ошибкой. Опять F2, исправление, Tab/Enter, F2, исправление, Tab/Enter и т.д.

Invincible 21-12-2016 21:15 2697509

Цитата:

Цитата Iska
что значит «но»? »

Ничего, просто если выделена одна ячейка а поиск осуществляется по всему столбцу?
Цитата:

Цитата Iska
Эти сообщения никак не будут помогать (ибо адреса банально забудутся), а станут только неимоверно раздражать. Разве недостаточно того, что ошибочные ячейки выделяются? »

Да, наверно Вы правы

Iska 21-12-2016 22:38 2697525

Цитата:

Цитата Invincible
Ничего, просто если выделена одна ячейка а поиск осуществляется по всему столбцу? »

Осуществляется, но не по всему столбцу.

Вам непонятен принцип построения пересечения используемого диапазона со столбцом? Или само понятие используемого диапазона? Что вызывает сомнение/неуверенность в понимании?

Invincible 22-12-2016 00:40 2697551

Цитата:

Цитата Iska
Вам непонятен принцип построения пересечения используемого диапазона со столбцом? »

Да, непонятно как осуществляется поиск в столбце

Iska 24-02-2017 04:06 2714369

Цитата:

Цитата Invincible
Да, непонятно как осуществляется поиск в столбце »

Примерно так:
Скрытый текст


Время: 22:32.

Время: 22:32.
© OSzone.net 2001-