UDF ИЗВЛЕЧЬЦЕЛЫЕ создаёт массив из целых чисел, извлечённых из текста произвольно расположенных ячеек. К полученному массиву далее можно применять любые стандартные формулы листа. Нумерация элементов массива - с 1. Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д [vba]
Код
Function ИЗВЛЕЧЬЦЕЛЫЕ(ParamArray ЯЧЕЙКА()) ' создать массив из целых чисел, выбранных из текста произвольно расположенных ячеек '--------------------------------------------------------------------------------------- ' Procedure : ИЗВЛЕЧЬЦЕЛЫЕ ' Author : Alex_ST ' DateTime : 18.11.11, 14:57 ' Purpose : создать массив из целых чисел, извлечённых из текста произвольно расположенных ячеек ' Notes : К полученному массиву можно применять любые стандартные формулы листа ' Notes : Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д '---------------------------------------------------------------------------------------
Dim rArea, rCell, Arr0, sStr$, i&, j& Dim Arr(): ReDim Arr(1 To 1) ' чтобы нумерация массива начиналась с 1 With CreateObject("VBScript.RegExp"): .Global = True: .Pattern = "[^0-9]" For Each rArea In ЯЧЕЙКА ' в каждой из областей For Each rCell In rArea ' в каждой из ячеек Arr0 = Split(Application.Trim(.Replace(rCell, " "))) ' массив целых чисел, выбранный из ячейки (LBound=0) If UBound(Arr0) > -1 Then ' если чисел нет, то UBound = -1 j = UBound(Arr) ReDim Preserve Arr(1 To UBound(Arr) + UBound(Arr0) + 1) For i = 0 To UBound(Arr0): Arr(j + i) = CLng(0 & Arr0(i)): Next i End If Next rCell Next rArea End With If UBound(Arr) = 1 Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrNA): Exit Function ' вернуть ошибку если чисел нет ReDim Preserve Arr(1 To UBound(Arr) - 1) ' убрать последний (лишний) элемент массива ИЗВЛЕЧЬЦЕЛЫЕ = Arr End Function
[/vba]
Пример - в файле.
UDF ИЗВЛЕЧЬЦЕЛЫЕ создаёт массив из целых чисел, извлечённых из текста произвольно расположенных ячеек. К полученному массиву далее можно применять любые стандартные формулы листа. Нумерация элементов массива - с 1. Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д [vba]
Код
Function ИЗВЛЕЧЬЦЕЛЫЕ(ParamArray ЯЧЕЙКА()) ' создать массив из целых чисел, выбранных из текста произвольно расположенных ячеек '--------------------------------------------------------------------------------------- ' Procedure : ИЗВЛЕЧЬЦЕЛЫЕ ' Author : Alex_ST ' DateTime : 18.11.11, 14:57 ' Purpose : создать массив из целых чисел, извлечённых из текста произвольно расположенных ячеек ' Notes : К полученному массиву можно применять любые стандартные формулы листа ' Notes : Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д '---------------------------------------------------------------------------------------
Dim rArea, rCell, Arr0, sStr$, i&, j& Dim Arr(): ReDim Arr(1 To 1) ' чтобы нумерация массива начиналась с 1 With CreateObject("VBScript.RegExp"): .Global = True: .Pattern = "[^0-9]" For Each rArea In ЯЧЕЙКА ' в каждой из областей For Each rCell In rArea ' в каждой из ячеек Arr0 = Split(Application.Trim(.Replace(rCell, " "))) ' массив целых чисел, выбранный из ячейки (LBound=0) If UBound(Arr0) > -1 Then ' если чисел нет, то UBound = -1 j = UBound(Arr) ReDim Preserve Arr(1 To UBound(Arr) + UBound(Arr0) + 1) For i = 0 To UBound(Arr0): Arr(j + i) = CLng(0 & Arr0(i)): Next i End If Next rCell Next rArea End With If UBound(Arr) = 1 Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrNA): Exit Function ' вернуть ошибку если чисел нет ReDim Preserve Arr(1 To UBound(Arr) - 1) ' убрать последний (лишний) элемент массива ИЗВЛЕЧЬЦЕЛЫЕ = Arr End Function
Приветствую! Позволь поделиться мыслями, как (на мой взгляд) можно ускорить и упростить процесс:
1. Вместо цикла по ячейкам, использовать цикл по массиву 2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items : ) правда тогда 1-ый эл. будет 0. Или использовать коллекцию и из нее выгружать в массив. Тут уж какой захочешь индекс можно установить. 3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)
\на примере пользовательской функции СУММ (USUM): два цикла по массивам впрочем, эт только мысли : )
Приветствую! Позволь поделиться мыслями, как (на мой взгляд) можно ускорить и упростить процесс:
1. Вместо цикла по ячейкам, использовать цикл по массиву 2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items : ) правда тогда 1-ый эл. будет 0. Или использовать коллекцию и из нее выгружать в массив. Тут уж какой захочешь индекс можно установить. 3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)
\на примере пользовательской функции СУММ (USUM): два цикла по массивам впрочем, эт только мысли : )nerv
1. Вместо цикла по ячейкам, использовать цикл по массиву
У меня сначала так и было. Но, когда стал "пытать во всяких позах", выяснил, что вылетает с ошибкой когда диапазон состоит из одной ячейки. Долго не ковырялся. Решил сделать цикл по диапазону. Да и когда ячеек не миллион (всё-таки это UDF для использования на листе, а не макрос для обработки огромных массивов информации), то, наверное, быстродействие не столь критично. Да и к тому же у меня в планах на будущее доработать UDF так, чтобы была опция "обрабатывать только видимые ячейки". А тогда перекидывание диапазона в массив точно не подойдёт, т.к. массив значений "видимо"/"невидимо" создать так просто без цикла не удастся. А это - затраты времени...
Quote (nerv)
2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items
М - один из моих любимых объектов. Но что-то мне показалось, что с массивом будет проще. Опять же, долго не ковырялся. Да и трудности возникают если диапазон "рваный" - из нескольких областей.
Quote (nerv)
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)
RegExp позволяет одним махом заменить не цифры на пробелы, которые потом элементарно ужимаются до одиночных Trim'ом и расщепляются в массив Split'ом. А если использовать Like "[0-9]", то надо циклом ещё проходить по буквам каждого слова. У меня, к стати, сначала в коде так и было. Но потом я напрягся, посмотрел в нескольких местах, как используют RegExp (я его практически не знаю, но надо же когда-то начинать) и переделал код под него. ИМХО, очень компактно получилось.
Quote (nerv)
1. Вместо цикла по ячейкам, использовать цикл по массиву
У меня сначала так и было. Но, когда стал "пытать во всяких позах", выяснил, что вылетает с ошибкой когда диапазон состоит из одной ячейки. Долго не ковырялся. Решил сделать цикл по диапазону. Да и когда ячеек не миллион (всё-таки это UDF для использования на листе, а не макрос для обработки огромных массивов информации), то, наверное, быстродействие не столь критично. Да и к тому же у меня в планах на будущее доработать UDF так, чтобы была опция "обрабатывать только видимые ячейки". А тогда перекидывание диапазона в массив точно не подойдёт, т.к. массив значений "видимо"/"невидимо" создать так просто без цикла не удастся. А это - затраты времени...
Quote (nerv)
2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items
М - один из моих любимых объектов. Но что-то мне показалось, что с массивом будет проще. Опять же, долго не ковырялся. Да и трудности возникают если диапазон "рваный" - из нескольких областей.
Quote (nerv)
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)
RegExp позволяет одним махом заменить не цифры на пробелы, которые потом элементарно ужимаются до одиночных Trim'ом и расщепляются в массив Split'ом. А если использовать Like "[0-9]", то надо циклом ещё проходить по буквам каждого слова. У меня, к стати, сначала в коде так и было. Но потом я напрягся, посмотрел в нескольких местах, как используют RegExp (я его практически не знаю, но надо же когда-то начинать) и переделал код под него. ИМХО, очень компактно получилось.Alex_ST
nerv, честно признаюсь: я только что из-за стола и ужин прошёл "не в сухую" Поэтому смотреть и разбирать твой пример сейчас точно не в состоянии
nerv, честно признаюсь: я только что из-за стола и ужин прошёл "не в сухую" Поэтому смотреть и разбирать твой пример сейчас точно не в состоянии Alex_ST
ну вот, видишь, как я медленно реагирую и "топчу батоны"... Пока я писАл ответ, ты уже успел часть возражений сам снять.. Попытай, если не сложно ещё. Может, ещё что-нибудь найдёшь. А макрос я закончил только в пятницу в районе обеда. Немного попытал сам и выложил. Ситуация с ошибкой в аргументах в моих испытаниях просто не попадалась. Надо будет подправить. Я и с корректным #Н/Д - то не сразу допёр, как нужно делать...
Quote (nerv)
Эт понял) Сразу не въехал : )
ну вот, видишь, как я медленно реагирую и "топчу батоны"... Пока я писАл ответ, ты уже успел часть возражений сам снять.. Попытай, если не сложно ещё. Может, ещё что-нибудь найдёшь. А макрос я закончил только в пятницу в районе обеда. Немного попытал сам и выложил. Ситуация с ошибкой в аргументах в моих испытаниях просто не попадалась. Надо будет подправить. Я и с корректным #Н/Д - то не сразу допёр, как нужно делать...Alex_ST
Alex_ST, хорошего застолья ; ) Будет время, посмотри)
[vba]
Код
Public Function io(ByRef Argument As String) As Variant Dim x, v, z, k As New Collection With CreateObject("VBScript.RegExp") .Global = True: .Pattern = "[^0-9]" For Each v In Split(Argument, ";"): Set v = Range(v) For Each x In IIf(v.Count = 1, Array(v.Value), v.Value) 'If одна ячейка Then cоздать массив Else цикл по массиву : ) If Not IsError(x) Then For Each z In Split(Application.Trim(.Replace(x, " "))) k.Add CLng(z) Next End If Next Next End With If k.Count = 0 Then io = CVErr(xlErrNA): Exit Function ReDim v(1 To k.Count) For x = 1 To k.Count: v(x) = k.Item(x): Next: io = v End Function
[/vba]
Alex_ST, хорошего застолья ; ) Будет время, посмотри)
[vba]
Код
Public Function io(ByRef Argument As String) As Variant Dim x, v, z, k As New Collection With CreateObject("VBScript.RegExp") .Global = True: .Pattern = "[^0-9]" For Each v In Split(Argument, ";"): Set v = Range(v) For Each x In IIf(v.Count = 1, Array(v.Value), v.Value) 'If одна ячейка Then cоздать массив Else цикл по массиву : ) If Not IsError(x) Then For Each z In Split(Application.Trim(.Replace(x, " "))) k.Add CLng(z) Next End If Next Next End With If k.Count = 0 Then io = CVErr(xlErrNA): Exit Function ReDim v(1 To k.Count) For x = 1 To k.Count: v(x) = k.Item(x): Next: io = v End Function
Предлагаю познакомиться с моим добрым другом - тестером регулярных выражений (они, черти, не всегда дружны с кириллицей, и вообще за ними глаз да глаз...) А это моя настольная книга http://depositfiles.com/files/y486mmbp5
Тестер, естественно, ждет пожеланий и предложений Там 2 листа, на одном можно работать с поиском, а на втором - с заменами Я сторонник раннего связывания, поэтому устанавливаю прямую ссылку на соответствующую библиотеку
Ребят, обратите внимание, на втором листе есть строка, разбитая на подстроки по несколько символов По-моему, это применимо к вашей задаче о нечетком сравнении строк, ведь все, что делается с помощью RegExp, должно работать быстрее
Предлагаю познакомиться с моим добрым другом - тестером регулярных выражений (они, черти, не всегда дружны с кириллицей, и вообще за ними глаз да глаз...) А это моя настольная книга http://depositfiles.com/files/y486mmbp5
Тестер, естественно, ждет пожеланий и предложений Там 2 листа, на одном можно работать с поиском, а на втором - с заменами Я сторонник раннего связывания, поэтому устанавливаю прямую ссылку на соответствующую библиотеку
Ребят, обратите внимание, на втором листе есть строка, разбитая на подстроки по несколько символов По-моему, это применимо к вашей задаче о нечетком сравнении строк, ведь все, что делается с помощью RegExp, должно работать быстрееv__step
Думаю, Вам не за что извиняться. На то он и форум. Пока не забыл - за книжку спасибо. Посмотрю позже : ) К сожалению, на данный момент я не могу поддержать беседу по RegExp, т.к. ни чего в них не понимаю. В том примере, кот. привел выше, я использовал код Alex_ST.
О чем могу сказать сейчас. Попытался показать, как можно ускорить код на примере трех вложенных циклов по массивам.
По тому примеру, кот. привели Вы. Допустим необходимо обработать две ячейки, содержащие следующие данные: С6 - 1?kkkk2 С9 - 3 козла В ходе конкатенсации строк, у Вас получается 23 козла)))
Quote (v__step)
Извиняюсь, что вклинился
Думаю, Вам не за что извиняться. На то он и форум. Пока не забыл - за книжку спасибо. Посмотрю позже : ) К сожалению, на данный момент я не могу поддержать беседу по RegExp, т.к. ни чего в них не понимаю. В том примере, кот. привел выше, я использовал код Alex_ST.
О чем могу сказать сейчас. Попытался показать, как можно ускорить код на примере трех вложенных циклов по массивам.
По тому примеру, кот. привели Вы. Допустим необходимо обработать две ячейки, содержащие следующие данные: С6 - 1?kkkk2 С9 - 3 козла В ходе конкатенсации строк, у Вас получается 23 козла)))nerv
Чебурашка стал символом олимпийских игр. А чего достиг ты? Тишина - самый громкий звук
Ах, конечно! Я подправил Подправил и текст своего последнего поста - добавил несколько теплых строк о нечетком сравнении строк Регулярные выражения мне нужны периодически (иногда они незаменимы) Тогда приходится все повторить, но очень быстро забывается Поэтому я в них тоже порядочный профан... Книга эта мне памятна прежде всего тем, что я ее очень долго сканировал (ее нет в инете)
Свой вариант Вашей функции я предложил только потому, что он показался мне проще Все-таки, обратите внимание на тестер - он не раз выручал меня
Ах, конечно! Я подправил Подправил и текст своего последнего поста - добавил несколько теплых строк о нечетком сравнении строк Регулярные выражения мне нужны периодически (иногда они незаменимы) Тогда приходится все повторить, но очень быстро забывается Поэтому я в них тоже порядочный профан... Книга эта мне памятна прежде всего тем, что я ее очень долго сканировал (ее нет в инете)
Свой вариант Вашей функции я предложил только потому, что он показался мне проще Все-таки, обратите внимание на тестер - он не раз выручал меняv__step
Привет, ребята. Володя, спасибо за пример и учебник. Буду завтра посмотреть. Эх, жалко, что учебник в djvu без OCR! Поэтому ни оглавления с ссылками не сделаешь, ни поиск не реализуешь... Но главное, что такая книга есть и уже кем-то отсканена. Значит, есть где-нибудь и распознанный вариант. Поищу. Если найду, попрошу Сержа в Читальном зале выложить. Володя, Александр, с вашими примерами поковыряюсь завтра на работе. К обеду, наверное, отпишусь о результатах.
Володя, а чем тебе не нравится позднее связывание? Ведь с ним на любой машине работать будет, а не только на твоей, где все нужные референсы подключены.
Привет, ребята. Володя, спасибо за пример и учебник. Буду завтра посмотреть. Эх, жалко, что учебник в djvu без OCR! Поэтому ни оглавления с ссылками не сделаешь, ни поиск не реализуешь... Но главное, что такая книга есть и уже кем-то отсканена. Значит, есть где-нибудь и распознанный вариант. Поищу. Если найду, попрошу Сержа в Читальном зале выложить. Володя, Александр, с вашими примерами поковыряюсь завтра на работе. К обеду, наверное, отпишусь о результатах.
Володя, а чем тебе не нравится позднее связывание? Ведь с ним на любой машине работать будет, а не только на твоей, где все нужные референсы подключены.Alex_ST
nerv, попытал твою функцию и понял, что ИМХО ты не прав: из-за применения у меня задания аргументов как ParamArray моя UDF ведёт себя как совершенно нормальная функция с аргументами-диапазонами. И "протягивание" формулы по ячейкам работает, и если "встать" мышкой на диапазон, указанный внутри формулы, то он выделится и его можно будет двигать/ресайзать мышкой как в обычной формуле. К тому же мою UDF можно использовать не только на листе, но и внутри макросов, т.к. параметры у неё задаются абсолютно стандартно: при использовании на листе диапазоны перечисляются через точку с запятой, а при использовании в макросе - элементы массива перечисляются через запятую. В твоей же UDF идёт задание аргумента как стринга. Поэтому при использовании на листе она не "протягивается", диапазон влияющих ячеек не выделяется и т.д. А в макросе тоже неудобно: подсказка при вводе не говорит как перечислять аргументы. А по поводу выдаваемой ошибки когда один из аргументов содержит ошибку, так ведь так, вроде и должна себя вести нормальная формула? Из твоего кода взял хорошую идею по определению цикла:[vba]
Код
For Each x In IIf(v.Count = 1, Array(v.Value), v.Value)
[/vba] , которая позволит работать с массивом значений вместо диапазона, что, действительно, намного быстрее. И вот что у меня получилось в итоге:[vba]
Код
Function ИЗВЛЕЧЬЦЕЛЫЕ(ParamArray ЯЧЕЙКА()) ' создать массив из целых чисел, выбранных из текста произвольно расположенных ячеек '--------------------------------------------------------------------------------------- ' Procedure : ИЗВЛЕЧЬЦЕЛЫЕ ' Author : Alex_ST ' DateTime : 21.11.11, 12:15 ' Purpose : создать массив из целых чисел, извлечённых из текста произвольно расположенных ячеек ' Notes : К полученному массиву можно применять любые стандартные формулы листа ' Notes : Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д '--------------------------------------------------------------------------------------- Dim rArea, rCell, Arr0, sStr$, i&, j& Dim Arr(): ReDim Arr(1 To 1) ' чтобы нумерация массива начиналась с 1 On Error GoTo xlErrEXIT With CreateObject("VBScript.RegExp"): .Global = True: .Pattern = "[^0-9]" For Each rArea In ЯЧЕЙКА ' в каждой из областей For Each rCell In IIf(rArea.Count = 1, rArea, rArea.Value) ' в каждой из ячеек Arr0 = Split(Application.Trim(.Replace(rCell, " "))) ' массив целых чисел, выбранный из ячейки (LBound=0) If UBound(Arr0) > -1 Then ' если чисел нет, то UBound = -1 j = UBound(Arr) ReDim Preserve Arr(1 To UBound(Arr) + UBound(Arr0) + 1) For i = 0 To UBound(Arr0): Arr(j + i) = CLng(0 & Arr0(i)): Next i End If Next rCell Next rArea End With If UBound(Arr) = 1 Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrNA): Exit Function ' вернуть ошибку #Н/Д если чисел нет ReDim Preserve Arr(1 To UBound(Arr) - 1) ' убрать последний (лишний) элемент массива ИЗВЛЕЧЬЦЕЛЫЕ = Arr xlErrEXIT: If Err Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrValue): Exit Function ' вернуть ошибку #ЗНАЧЕНИЕ если была ошибка в аргументах
End Function
[/vba]
а вот так очень просто можно протестировать:[vba]
Код
Sub test_ИЗВЛЕЧЬЦЕЛЫЕ() With Лист2 .[A1] = "1 бык и 2 коровы" .[B1] = "3 барана,4 овцы" .[C1] = "всего 5 кур; 6 гусей" .[D1] = CVErr(xlErrNA) End With Dim i%, Arr Arr = ИЗВЛЕЧЬЦЕЛЫЕ(Лист2.[A1], Лист2.[B1:C1]) If VarType(Arr) = vbError Then Debug.Print "No numbers in string": Exit Sub For i = LBound(Arr) To UBound(Arr): Debug.Print i, Arr(i): Next i End Sub
[/vba]
nerv, попытал твою функцию и понял, что ИМХО ты не прав: из-за применения у меня задания аргументов как ParamArray моя UDF ведёт себя как совершенно нормальная функция с аргументами-диапазонами. И "протягивание" формулы по ячейкам работает, и если "встать" мышкой на диапазон, указанный внутри формулы, то он выделится и его можно будет двигать/ресайзать мышкой как в обычной формуле. К тому же мою UDF можно использовать не только на листе, но и внутри макросов, т.к. параметры у неё задаются абсолютно стандартно: при использовании на листе диапазоны перечисляются через точку с запятой, а при использовании в макросе - элементы массива перечисляются через запятую. В твоей же UDF идёт задание аргумента как стринга. Поэтому при использовании на листе она не "протягивается", диапазон влияющих ячеек не выделяется и т.д. А в макросе тоже неудобно: подсказка при вводе не говорит как перечислять аргументы. А по поводу выдаваемой ошибки когда один из аргументов содержит ошибку, так ведь так, вроде и должна себя вести нормальная формула? Из твоего кода взял хорошую идею по определению цикла:[vba]
Код
For Each x In IIf(v.Count = 1, Array(v.Value), v.Value)
[/vba] , которая позволит работать с массивом значений вместо диапазона, что, действительно, намного быстрее. И вот что у меня получилось в итоге:[vba]
Код
Function ИЗВЛЕЧЬЦЕЛЫЕ(ParamArray ЯЧЕЙКА()) ' создать массив из целых чисел, выбранных из текста произвольно расположенных ячеек '--------------------------------------------------------------------------------------- ' Procedure : ИЗВЛЕЧЬЦЕЛЫЕ ' Author : Alex_ST ' DateTime : 21.11.11, 12:15 ' Purpose : создать массив из целых чисел, извлечённых из текста произвольно расположенных ячеек ' Notes : К полученному массиву можно применять любые стандартные формулы листа ' Notes : Если цифр в ячейках-аргументах функции нет, то возвращается КОРРЕКТНОЕ #Н/Д '--------------------------------------------------------------------------------------- Dim rArea, rCell, Arr0, sStr$, i&, j& Dim Arr(): ReDim Arr(1 To 1) ' чтобы нумерация массива начиналась с 1 On Error GoTo xlErrEXIT With CreateObject("VBScript.RegExp"): .Global = True: .Pattern = "[^0-9]" For Each rArea In ЯЧЕЙКА ' в каждой из областей For Each rCell In IIf(rArea.Count = 1, rArea, rArea.Value) ' в каждой из ячеек Arr0 = Split(Application.Trim(.Replace(rCell, " "))) ' массив целых чисел, выбранный из ячейки (LBound=0) If UBound(Arr0) > -1 Then ' если чисел нет, то UBound = -1 j = UBound(Arr) ReDim Preserve Arr(1 To UBound(Arr) + UBound(Arr0) + 1) For i = 0 To UBound(Arr0): Arr(j + i) = CLng(0 & Arr0(i)): Next i End If Next rCell Next rArea End With If UBound(Arr) = 1 Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrNA): Exit Function ' вернуть ошибку #Н/Д если чисел нет ReDim Preserve Arr(1 To UBound(Arr) - 1) ' убрать последний (лишний) элемент массива ИЗВЛЕЧЬЦЕЛЫЕ = Arr xlErrEXIT: If Err Then ИЗВЛЕЧЬЦЕЛЫЕ = CVErr(xlErrValue): Exit Function ' вернуть ошибку #ЗНАЧЕНИЕ если была ошибка в аргументах
End Function
[/vba]
а вот так очень просто можно протестировать:[vba]
Код
Sub test_ИЗВЛЕЧЬЦЕЛЫЕ() With Лист2 .[A1] = "1 бык и 2 коровы" .[B1] = "3 барана,4 овцы" .[C1] = "всего 5 кур; 6 гусей" .[D1] = CVErr(xlErrNA) End With Dim i%, Arr Arr = ИЗВЛЕЧЬЦЕЛЫЕ(Лист2.[A1], Лист2.[B1:C1]) If VarType(Arr) = vbError Then Debug.Print "No numbers in string": Exit Sub For i = LBound(Arr) To UBound(Arr): Debug.Print i, Arr(i): Next i End Sub
К стати, народ, в своём последнем примере я сделал достаточно грубо в лоб: дошёл до перебора значений ячеек аргумента и если возникла ошибка, вывел ошибку в значение функции. Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки? Не хотелось бы перебором добираться до ошибки, а потом вываливаться...
К стати, народ, в своём последнем примере я сделал достаточно грубо в лоб: дошёл до перебора значений ячеек аргумента и если возникла ошибка, вывел ошибку в значение функции. Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки? Не хотелось бы перебором добираться до ошибки, а потом вываливаться...Alex_ST
Alex_ST, согласен, передача параметров с ParamArray намного удобней.
Попытался собрать в кучу идеи всех авторов: + задействовал ParamArray + убрал ReDim Preserve + использовал только циклы по массивам + вместо промежуточного массива использовал строковую переменную
- ошибки не обрабатывал
[vba]
Код
Public Function io(ParamArray Arguments()) As Variant Dim v, x, i With CreateObject("VBScript.RegExp") .Global = True: .Pattern = "[^0-9]" For Each v In Arguments For Each x In IIf(v.Count = 1, Array(v.Value), v.Value) i = i & " " & Application.Trim(.Replace(x, " ")) Next Next x = Split(LTrim(i)): ReDim v(1 To UBound(x) + 1) For i = 0 To UBound(x): v(i + 1) = CLng(x(i)): Next io = v End With End Function
[/vba]
Цитата (Alex_ST)
Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки?
Идеи есть) Чуть позже покажу. Вариант выше с IsError тоже можешь считать за идею)
Приветствую!
Alex_ST, согласен, передача параметров с ParamArray намного удобней.
Попытался собрать в кучу идеи всех авторов: + задействовал ParamArray + убрал ReDim Preserve + использовал только циклы по массивам + вместо промежуточного массива использовал строковую переменную
- ошибки не обрабатывал
[vba]
Код
Public Function io(ParamArray Arguments()) As Variant Dim v, x, i With CreateObject("VBScript.RegExp") .Global = True: .Pattern = "[^0-9]" For Each v In Arguments For Each x In IIf(v.Count = 1, Array(v.Value), v.Value) i = i & " " & Application.Trim(.Replace(x, " ")) Next Next x = Split(LTrim(i)): ReDim v(1 To UBound(x) + 1) For i = 0 To UBound(x): v(i + 1) = CLng(x(i)): Next io = v End With End Function
[/vba]
Цитата (Alex_ST)
Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки?
Идеи есть) Чуть позже покажу. Вариант выше с IsError тоже можешь считать за идею)nerv
Чебурашка стал символом олимпийских игр. А чего достиг ты? Тишина - самый громкий звук
вместо промежуточного массива использовал строковую переменную
БЛИН! Что ж я сам-то не допёр собирать в строку, а потом бить её на массив Split'ом? Правда, массив будет с lBound=0... Но это уже вопрос к формулистам: а как Excel на листе работает с формулами, возврашающими массив? Я сам формул массива боюсь как бухгалтерия макросов Поэтому на всякий случай в своей UDF-ке сделал возвращаемый массив с lBound=1 А оно кому-нибудь нужно? К стати, код-то будет компактнее с наборной строкой, а вот про скорость...? Надо пытать. Есть у меня подозрение, что Split-Join внутри себя просто тупо перебирают массив.
Quote (nerv)
вместо промежуточного массива использовал строковую переменную
БЛИН! Что ж я сам-то не допёр собирать в строку, а потом бить её на массив Split'ом? Правда, массив будет с lBound=0... Но это уже вопрос к формулистам: а как Excel на листе работает с формулами, возврашающими массив? Я сам формул массива боюсь как бухгалтерия макросов Поэтому на всякий случай в своей UDF-ке сделал возвращаемый массив с lBound=1 А оно кому-нибудь нужно? К стати, код-то будет компактнее с наборной строкой, а вот про скорость...? Надо пытать. Есть у меня подозрение, что Split-Join внутри себя просто тупо перебирают массив.Alex_ST
Ребята, все-таки, посмотрите код, приложенный к посту №11 Я же полностью переписал функцию, сохранив ParamArray Задействовал не RegEx-замену, а RegEx.Matches + другой критерий поиска Строку же для поиска предварительно получил конкатенацией всех строк В какой-то мере это противоположный подход А код получился - проще некуда И не нужны ни Split, ни Join! Почти всю работу берет на себя RegExp За замечание спасибо, я еще не усвоил все правила этикета
Ребята, все-таки, посмотрите код, приложенный к посту №11 Я же полностью переписал функцию, сохранив ParamArray Задействовал не RegEx-замену, а RegEx.Matches + другой критерий поиска Строку же для поиска предварительно получил конкатенацией всех строк В какой-то мере это противоположный подход А код получился - проще некуда И не нужны ни Split, ни Join! Почти всю работу берет на себя RegExp За замечание спасибо, я еще не усвоил все правила этикетаv__step
С уважением, Владимир
Сообщение отредактировал v__step - Понедельник, 21.11.2011, 14:18
Володя, я всегда догадывался, что ты круче варёных яиц! Твой код из поста №11 прекрасно работает и невозможно краток Ща полирну, добавлю обработку ошибок и ещё раз покручу-поверчу Но куда уж нам, серым, про RegExp только краем уха слышавшим, до таких успехов в общении с МАЧО (matches ). Надо учиться, учиться и ещё раз учиться, как говорил Вечно не похороненный. Создай, плиз, топик-учебник по RegExp
Володя, я всегда догадывался, что ты круче варёных яиц! Твой код из поста №11 прекрасно работает и невозможно краток Ща полирну, добавлю обработку ошибок и ещё раз покручу-поверчу Но куда уж нам, серым, про RegExp только краем уха слышавшим, до таких успехов в общении с МАЧО (matches ). Надо учиться, учиться и ещё раз учиться, как говорил Вечно не похороненный. Создай, плиз, топик-учебник по RegExp Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Понедельник, 21.11.2011, 14:30