В VBA ошибка Too Many Line Continuations весьма редкая, что делает её несколько экзотичной. И тем не менее, столкнуться с ней можно даже ничего не программируя, а просто при записи макроса.
Прежде чем разобрать причину ошибки и способы её устранения, сначала неплохо бы немного теории. Предположу, что раз зашли на эту страницу - значит уже познакомились с макросами хотя бы поверхностно (если нет - статья в помощь: Что такое макрос и где его искать?). Т.к. макрос это код программы, значит этот код должен быть где-то записан. И записываются все коды в модулях (подробнее про модули: Что такое модуль? Какие бывают модули?). Помимо ограничений, накладываемых синтаксисом языка программирования (в данном случае это VBA), есть и иные ограничения - будем называть их физическими.
- максимальный размер одного модуля не должен превышать 64Кб
- количество символов в имени переменной или константы не должно превышать 255 символов
- длина строки не должна превышать 1023 символа
- количество физических строк внутри одной логической не должно превышать 25. Иными словами - переносов на строки не может быть более 24
Возможно я перечислил здесь не все физические ограничения - но для начальной теории и понимания разбираемой ошибки более чем достаточно.
Плюс пара терминов, которые нам пригодятся:
Физическая строка - строка кода(да и вообще любого текста) в привычном её понимании. Т.е. все то, что умещается в одну визуальную строку без всяких переносов.Логическая строка - может состоять из нескольких физических, но составляет в дальнейшем одну непрерывную логическую конструкцию.
Начнем с очевидного: при написании кодов хоть и есть возможность записать в одну физическую строку кода до 1023 символов, на практике это ни фига не удобно. Т.к. прокручивание ползунка внизу окна редактора для просмотра всей строки никак не совпадает с представлениями о комфортной работе с текстом. Именно поэтому часто длинные логические строки кода разбиваются на несколько физических:
Для разбиения логической строки на несколько физических применяется специальный оператора разбиения, состоящий из последовательно записанных пробела и знака нижнего подчеркивания:
Selection.PasteSpecial Paste:=xlPasteValues, _ Operation:=xlNone, _ SkipBlanks:=False, _ Transpose:=False |
Однако в коде есть специальный оператор, указывающий на принадлежность значения конкретному аргументу:
Operation: _
=xlNone, SkipBlanks:=False, Transpose:=False
Так же не допускается прямое разбиение текста в кавычках:
Range("D1 _
").Select
'
Range("D _
1").Select
В данном случае необходимо либо закрыть кавычки и не разбивать текст(в первом случае):
).Select
либо установить закрывающие кавычки для каждого фрагмента текста и объединить их специальным символом объединения текста(
"1").Select
И вот теперь, когда разобрались с тем как записываются строки и как их можно разбивать и какие ограничения накладываются на строки - совершенно не сложно догадаться,
Если ошибка возникла при написании кода самостоятельно - то здесь проблем возникнуть не должно. Можно ради работы кода пожертвовать удобством чтения в одной строке и просто убрать пару переносов на строки, объединив их в одну физическую:
'Вместо такой строки s = "1" & _ "2" & _ "3" & _ "4" & _ "5" 'записать так s = "1" & "2" & _ "3" & "4" & _ "5" 'хотя, конечно в данном конкретном случае правильнее так: s = "12" & _ "34" & _ "5" |
Куда хуже, когда ошибка возникает при записи макроса. Да, такое тоже может быть. При этом совершенно очевидно, что больше смахивает на бред, но все же - макрорекордер очень любит разбивать логические строки на физические. При этом длина каждой физической строки едва дотягивает до 100 символов как правило. Конечно, в подавляющем большинстве случаев и этого за глаза хватает. Но бывают ведь и исключения. Например, если попытаться записать макрорекордером разбиение текста на столбцы(Данные -Текст по столбцам) примерно такого текста(просто 200 раз повторяется "текст "):
применив в качестве разделителя пробел, то практически 100% получим ошибку Too Many Line Continuations и при этом код будет записан не полностью и оборвется на какой-то строке. У меня, например, кода хватило лишь для назначения формата 134 слову:
Вот в этом случае не остается ничего другого, как разбивать текст в ячейках на блоки. По сути самым оптимальным на мой взгляд будет посмотреть на каком фрагменте завершилась запись(в моем случае на
'--------------------------------------------------------------------------------------- ' Author : The_Prist(Щербаков Дмитрий) ' Профессиональная разработка приложений для MS Office любой сложности ' Проведение тренингов по MS Excel ' http://www.excel-vba.ru ' WebMoney - R298726502453; Яндекс.Деньги - 41001332272872 ' Purpose: http://www.excel-vba.ru/chto-umeet-excel/oshibka-too-many-line-continuations/ '--------------------------------------------------------------------------------------- Sub T2Cols() Const sDelim As String = " " 'разделитель текста Const lLIMIT_DelimCnt As Long = 100 'максимальное кол-во фрагментов в блоке Dim aFieldInfo 'массив назначения типов Dim ws As Worksheet, wsres As Worksheet Dim asSp, iTmpLen As Long Dim rTxt As Range, arr, aBreak, aTmp, aFTmp Dim lDelimCnt As Long, lMaxDelimCnt As Long, lMaxBreaks As Long Dim lr As Long, lt As Long, lc As Long, lcc As Long Dim s As String 'берем только первый столбец выделенного текста Set rTxt = Selection.Columns(1) 'отсекаем ячейки в конце столбца, не содержащие данных Set rTxt = Intersect(rTxt.Parent.UsedRange, rTxt) If rTxt Is Nothing Then Exit Sub Application.ScreenUpdating = 0 arr = rTxt.Value If Not IsArray(arr) Then ReDim arr(1 To 1, 1 To 1) arr(1, 1) = rTxt.Value End If 'определяем максимальное кол-во разделителей во всем диапазоне For lr = 1 To UBound(arr, 1) s = arr(lr, 1) If Len(s) Then lDelimCnt = Len(s) - Len(Replace(s, sDelim, "")) If lMaxDelimCnt < lDelimCnt Then lMaxDelimCnt = lDelimCnt End If End If Next 'максимальное кол-во блоков текста lMaxBreaks = Application.RoundUp(lMaxDelimCnt / lLIMIT_DelimCnt, 0) + 1 'создаем массив блоков текста для дальнейшего разбиения стандартными средствами If lMaxDelimCnt > lLIMIT_DelimCnt Then ReDim aBreak(1 To UBound(arr, 1), 1 To lMaxBreaks) ReDim aFieldInfo(1 To lMaxBreaks) For lr = 1 To UBound(arr, 1) s = arr(lr, 1) If Len(s) Then asSp = Split(s, sDelim) lcc = 0 For lc = 0 To UBound(asSp) Step lLIMIT_DelimCnt lcc = lcc + 1 If (UBound(asSp) - (lc)) < lLIMIT_DelimCnt Then iTmpLen = UBound(asSp) - lc Else iTmpLen = lLIMIT_DelimCnt - 1 End If ReDim aTmp(iTmpLen) ReDim aFTmp(iTmpLen) For lt = lc To lc + iTmpLen aTmp(lt - lc) = asSp(lt) aFTmp(lt - lc) = Array(1, 1) 'Array(1, 2) - если на выходе нужны текстовые значения Next aBreak(lr, lcc) = Join(aTmp, sDelim) & sDelim aFieldInfo(lcc) = aFTmp Next End If Next Else MsgBox "Данные можно разбить стандартными средствами: Данные -Текст по столбцам", vbInformation, "www.excel-vba.ru" Exit Sub End If 'Создаем лист Set ws = Worksheets.Add ws.Name = "tmp" 'записываем на временный лист все разбитые на блоки по 100 столбцы ws.Cells(1, 1).Resize(UBound(aBreak, 1), UBound(aBreak, 2)).Value = aBreak 'цикл по каждому столбцу, его копирование на результирующий лист и разбиение по разделителю(Пробел - Space:=True) 'если этот цикл не нужен и планируется вручную назначать столбцам параметры 'удалить все, что между чертой =========== '=============================================================================== Set wsres = Worksheets.Add wsres.Name = "result" For lc = 1 To UBound(aBreak, 2) lcc = wsres.Cells(1, wsres.Columns.Count).End(xlToLeft).Column + 1 aFTmp = aFieldInfo(lc) ws.Columns(lc).Copy wsres.Cells(1, lcc) 'Эта часть разбивает помещенный на листы текст wsres.Columns(lcc).TextToColumns Destination:=wsres.Cells(1, lcc), DataType:=xlDelimited, _ TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=False, _ Semicolon:=False, Comma:=False, Space:=True, Other:=False, FieldInfo _ :=aFTmp, TrailingMinusNumbers:=True Next Application.DisplayAlerts = False ws.Delete Application.DisplayAlerts = True wsres.Select '=============================================================================== Application.ScreenUpdating = 1 MsgBox "Данные обработаны", vbInformation, "www.excel-vba.ru" End Sub |
Скачать файл с кодом и примером данных:
Tips_VBE_T2Cols.xls (62,5 КиБ, 1 037 скачиваний)