Домашняя страница Undo Do New Save Карта сайта Обратная связь Поиск по форуму
МИР MS EXCEL - Гость.xls

Вход

Регистрация

Напомнить пароль

 

= Мир MS Excel/Функция (UDF) "ИЗВЛЕЧЬЦЕЛЫЕ" - Мир MS Excel

Старая форма входа
  • Страница 1 из 2
  • 1
  • 2
  • »
Модератор форума: _Boroda_, китин  
Мир MS Excel » Вопросы и решения » Готовые решения » Функция (UDF) "ИЗВЛЕЧЬЦЕЛЫЕ" (создать массив из целых чисел, извлечённых из текста ячеек)
Функция (UDF) "ИЗВЛЕЧЬЦЕЛЫЕ"
Alex_ST Дата: Пятница, 18.11.2011, 15:59 | Сообщение № 1
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
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_ExtractNumb.xls (56.0 Kb)



С уважением,
Алексей
MS Excel 2003 - the best!!!


Сообщение отредактировал Alex_ST - Пятница, 18.11.2011, 16:00
 
Ответить
Сообщение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]

Пример - в файле.

Автор - Alex_ST
Дата добавления - 18.11.2011 в 15:59
nerv Дата: Суббота, 19.11.2011, 21:01 | Сообщение № 2
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Приветствую! Позволь поделиться мыслями, как (на мой взгляд) можно ускорить и упростить процесс:

1. Вместо цикла по ячейкам, использовать цикл по массиву
2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items : ) правда тогда 1-ый эл. будет 0.
Или использовать коллекцию и из нее выгружать в массив. Тут уж какой захочешь индекс можно установить.
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)

\на примере пользовательской функции СУММ (USUM): два цикла по массивам
впрочем, эт только мысли : )
К сообщению приложен файл: Function_USUM.zip (6.8 Kb)


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba
 
Ответить
СообщениеПриветствую! Позволь поделиться мыслями, как (на мой взгляд) можно ускорить и упростить процесс:

1. Вместо цикла по ячейкам, использовать цикл по массиву
2. Вместо ReDim Preserve Array использовать Scripting.Dictionary и одним махом Array = .Items : ) правда тогда 1-ый эл. будет 0.
Или использовать коллекцию и из нее выгружать в массив. Тут уж какой захочешь индекс можно установить.
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)

\на примере пользовательской функции СУММ (USUM): два цикла по массивам
впрочем, эт только мысли : )

Автор - nerv
Дата добавления - 19.11.2011 в 21:01
nerv Дата: Суббота, 19.11.2011, 21:40 | Сообщение № 3
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Quote (nerv)
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)

Эт понял) Сразу не въехал : )

Еще такой момент (осторожно!) если одна из ячеек содержит ошибку, то функция возвращает ошибку.


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Суббота, 19.11.2011, 21:41
 
Ответить
Сообщение
Quote (nerv)
3. Неужели есть надобность в RegExp? А как же чудесный Like "[0-9]"?)

Эт понял) Сразу не въехал : )

Еще такой момент (осторожно!) если одна из ячеек содержит ошибку, то функция возвращает ошибку.

Автор - nerv
Дата добавления - 19.11.2011 в 21:40
Alex_ST Дата: Суббота, 19.11.2011, 21:47 | Сообщение № 4
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
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 (я его практически не знаю, но надо же когда-то начинать) и переделал код под него. ИМХО, очень компактно получилось.



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
Сообщение
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
Дата добавления - 19.11.2011 в 21:47
Alex_ST Дата: Суббота, 19.11.2011, 21:50 | Сообщение № 5
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
nerv,
честно признаюсь: я только что из-за стола и ужин прошёл "не в сухую" smile
Поэтому смотреть и разбирать твой пример сейчас точно не в состоянии



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
Сообщениеnerv,
честно признаюсь: я только что из-за стола и ужин прошёл "не в сухую" smile
Поэтому смотреть и разбирать твой пример сейчас точно не в состоянии

Автор - Alex_ST
Дата добавления - 19.11.2011 в 21:50
Alex_ST Дата: Суббота, 19.11.2011, 21:55 | Сообщение № 6
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
Quote (nerv)
Эт понял) Сразу не въехал : )

ну вот, видишь, как я медленно реагирую и "топчу батоны"... Пока я писАл ответ, ты уже успел часть возражений сам снять..
Попытай, если не сложно ещё. Может, ещё что-нибудь найдёшь.
А макрос я закончил только в пятницу в районе обеда. Немного попытал сам и выложил. Ситуация с ошибкой в аргументах в моих испытаниях просто не попадалась. Надо будет подправить.
Я и с корректным #Н/Д - то не сразу допёр, как нужно делать...



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
Сообщение
Quote (nerv)
Эт понял) Сразу не въехал : )

ну вот, видишь, как я медленно реагирую и "топчу батоны"... Пока я писАл ответ, ты уже успел часть возражений сам снять..
Попытай, если не сложно ещё. Может, ещё что-нибудь найдёшь.
А макрос я закончил только в пятницу в районе обеда. Немного попытал сам и выложил. Ситуация с ошибкой в аргументах в моих испытаниях просто не попадалась. Надо будет подправить.
Я и с корректным #Н/Д - то не сразу допёр, как нужно делать...

Автор - Alex_ST
Дата добавления - 19.11.2011 в 21:55
nerv Дата: Суббота, 19.11.2011, 22:22 | Сообщение № 7
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

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]
К сообщению приложен файл: -UDF_ExtractNum.xls (42.5 Kb)


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Воскресенье, 20.11.2011, 08:56
 
Ответить
Сообщение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]

Автор - nerv
Дата добавления - 19.11.2011 в 22:22
v__step Дата: Воскресенье, 20.11.2011, 18:26 | Сообщение № 8
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 225
Репутация: 27 ±
Замечаний: 0% ±

Доброго времени суток. Извиняюсь, что вклинился, но я та рыбка, которая клюет на RegExp
А если так?
К сообщению приложен файл: UDF_ExtractNum_.xls (48.5 Kb)


С уважением, Владимир

Сообщение отредактировал v__step - Воскресенье, 20.11.2011, 18:43
 
Ответить
СообщениеДоброго времени суток. Извиняюсь, что вклинился, но я та рыбка, которая клюет на RegExp
А если так?

Автор - v__step
Дата добавления - 20.11.2011 в 18:26
v__step Дата: Воскресенье, 20.11.2011, 18:46 | Сообщение № 9
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 225
Репутация: 27 ±
Замечаний: 0% ±

Предлагаю познакомиться с моим добрым другом - тестером регулярных выражений (они, черти, не всегда дружны с кириллицей, и вообще за ними глаз да глаз...)
А это моя настольная книга
http://depositfiles.com/files/y486mmbp5

Тестер, естественно, ждет пожеланий и предложений
Там 2 листа, на одном можно работать с поиском, а на втором - с заменами
Я сторонник раннего связывания, поэтому устанавливаю прямую ссылку на соответствующую библиотеку

Ребят, обратите внимание, на втором листе есть строка, разбитая на подстроки по несколько символов
По-моему, это применимо к вашей задаче о нечетком сравнении строк, ведь все, что делается с помощью RegExp, должно работать быстрее
К сообщению приложен файл: UDF_RegExpTest.xls (37.0 Kb)


С уважением, Владимир

Сообщение отредактировал v__step - Воскресенье, 20.11.2011, 19:52
 
Ответить
СообщениеПредлагаю познакомиться с моим добрым другом - тестером регулярных выражений (они, черти, не всегда дружны с кириллицей, и вообще за ними глаз да глаз...)
А это моя настольная книга
http://depositfiles.com/files/y486mmbp5

Тестер, естественно, ждет пожеланий и предложений
Там 2 листа, на одном можно работать с поиском, а на втором - с заменами
Я сторонник раннего связывания, поэтому устанавливаю прямую ссылку на соответствующую библиотеку

Ребят, обратите внимание, на втором листе есть строка, разбитая на подстроки по несколько символов
По-моему, это применимо к вашей задаче о нечетком сравнении строк, ведь все, что делается с помощью RegExp, должно работать быстрее

Автор - v__step
Дата добавления - 20.11.2011 в 18:46
nerv Дата: Воскресенье, 20.11.2011, 19:11 | Сообщение № 10
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Quote (v__step)
Извиняюсь, что вклинился

Думаю, Вам не за что извиняться. На то он и форум. Пока не забыл - за книжку спасибо. Посмотрю позже : )
К сожалению, на данный момент я не могу поддержать беседу по RegExp, т.к. ни чего в них не понимаю. В том примере, кот. привел выше, я использовал код Alex_ST.

О чем могу сказать сейчас.
Попытался показать, как можно ускорить код на примере трех вложенных циклов по массивам.

По тому примеру, кот. привели Вы.
Допустим необходимо обработать две ячейки, содержащие следующие данные:
С6 - 1?kkkk2
С9 - 3 козла
В ходе конкатенсации строк, у Вас получается 23 козла)))


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba


Сообщение отредактировал nerv - Воскресенье, 20.11.2011, 21:52
 
Ответить
Сообщение
Quote (v__step)
Извиняюсь, что вклинился

Думаю, Вам не за что извиняться. На то он и форум. Пока не забыл - за книжку спасибо. Посмотрю позже : )
К сожалению, на данный момент я не могу поддержать беседу по RegExp, т.к. ни чего в них не понимаю. В том примере, кот. привел выше, я использовал код Alex_ST.

О чем могу сказать сейчас.
Попытался показать, как можно ускорить код на примере трех вложенных циклов по массивам.

По тому примеру, кот. привели Вы.
Допустим необходимо обработать две ячейки, содержащие следующие данные:
С6 - 1?kkkk2
С9 - 3 козла
В ходе конкатенсации строк, у Вас получается 23 козла)))

Автор - nerv
Дата добавления - 20.11.2011 в 19:11
v__step Дата: Воскресенье, 20.11.2011, 20:07 | Сообщение № 11
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 225
Репутация: 27 ±
Замечаний: 0% ±

Ах, конечно!
Я подправил
Подправил и текст своего последнего поста - добавил несколько теплых строк о нечетком сравнении строк
Регулярные выражения мне нужны периодически (иногда они незаменимы)
Тогда приходится все повторить, но очень быстро забывается
Поэтому я в них тоже порядочный профан...
Книга эта мне памятна прежде всего тем, что я ее очень долго сканировал smile (ее нет в инете)

Свой вариант Вашей функции я предложил только потому, что он показался мне проще
Все-таки, обратите внимание на тестер - он не раз выручал меня
К сообщению приложен файл: 5494241.xls (57.0 Kb)


С уважением, Владимир

Сообщение отредактировал v__step - Воскресенье, 20.11.2011, 21:09
 
Ответить
СообщениеАх, конечно!
Я подправил
Подправил и текст своего последнего поста - добавил несколько теплых строк о нечетком сравнении строк
Регулярные выражения мне нужны периодически (иногда они незаменимы)
Тогда приходится все повторить, но очень быстро забывается
Поэтому я в них тоже порядочный профан...
Книга эта мне памятна прежде всего тем, что я ее очень долго сканировал smile (ее нет в инете)

Свой вариант Вашей функции я предложил только потому, что он показался мне проще
Все-таки, обратите внимание на тестер - он не раз выручал меня

Автор - v__step
Дата добавления - 20.11.2011 в 20:07
Alex_ST Дата: Воскресенье, 20.11.2011, 22:49 | Сообщение № 12
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
Привет, ребята.
Володя, спасибо за пример и учебник. Буду завтра посмотреть. Эх, жалко, что учебник в djvu без OCR! Поэтому ни оглавления с ссылками не сделаешь, ни поиск не реализуешь...
Но главное, что такая книга есть и уже кем-то отсканена. Значит, есть где-нибудь и распознанный вариант. Поищу. Если найду, попрошу Сержа в Читальном зале выложить.
Володя, Александр, с вашими примерами поковыряюсь завтра на работе. К обеду, наверное, отпишусь о результатах.

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



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
СообщениеПривет, ребята.
Володя, спасибо за пример и учебник. Буду завтра посмотреть. Эх, жалко, что учебник в djvu без OCR! Поэтому ни оглавления с ссылками не сделаешь, ни поиск не реализуешь...
Но главное, что такая книга есть и уже кем-то отсканена. Значит, есть где-нибудь и распознанный вариант. Поищу. Если найду, попрошу Сержа в Читальном зале выложить.
Володя, Александр, с вашими примерами поковыряюсь завтра на работе. К обеду, наверное, отпишусь о результатах.

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

Автор - Alex_ST
Дата добавления - 20.11.2011 в 22:49
Alex_ST Дата: Понедельник, 21.11.2011, 12:43 | Сообщение № 13
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
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]



С уважением,
Алексей
MS Excel 2003 - the best!!!


Сообщение отредактировал Alex_ST - Понедельник, 21.11.2011, 21:10
 
Ответить
Сообщение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]

Автор - Alex_ST
Дата добавления - 21.11.2011 в 12:43
Alex_ST Дата: Понедельник, 21.11.2011, 13:00 | Сообщение № 14
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
К стати, народ, в своём последнем примере я сделал достаточно грубо в лоб: дошёл до перебора значений ячеек аргумента и если возникла ошибка, вывел ошибку в значение функции.
Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки?
Не хотелось бы перебором добираться до ошибки, а потом вываливаться...



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
СообщениеК стати, народ, в своём последнем примере я сделал достаточно грубо в лоб: дошёл до перебора значений ячеек аргумента и если возникла ошибка, вывел ошибку в значение функции.
Есть у кого-нибудь мысли о том, как чтобы не делать лишние вычисления, сразу сначала проверить, а нет ли в каком-нибудь из аргументов-диапазонов ошибки?
Не хотелось бы перебором добираться до ошибки, а потом вываливаться...

Автор - Alex_ST
Дата добавления - 21.11.2011 в 13:00
nerv Дата: Понедельник, 21.11.2011, 13:50 | Сообщение № 15
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Приветствую!

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 тоже можешь считать за идею)


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba
 
Ответить
СообщениеПриветствую!

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
Дата добавления - 21.11.2011 в 13:50
Alex_ST Дата: Понедельник, 21.11.2011, 14:02 | Сообщение № 16
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
Quote (nerv)
вместо промежуточного массива использовал строковую переменную

БЛИН!
Что ж я сам-то не допёр собирать в строку, а потом бить её на массив Split'ом?
Правда, массив будет с lBound=0...
Но это уже вопрос к формулистам: а как Excel на листе работает с формулами, возврашающими массив?
Я сам формул массива боюсь как бухгалтерия макросов biggrin
Поэтому на всякий случай в своей UDF-ке сделал возвращаемый массив с lBound=1 А оно кому-нибудь нужно?
К стати, код-то будет компактнее с наборной строкой, а вот про скорость...? Надо пытать. Есть у меня подозрение, что Split-Join внутри себя просто тупо перебирают массив.



С уважением,
Алексей
MS Excel 2003 - the best!!!
 
Ответить
Сообщение
Quote (nerv)
вместо промежуточного массива использовал строковую переменную

БЛИН!
Что ж я сам-то не допёр собирать в строку, а потом бить её на массив Split'ом?
Правда, массив будет с lBound=0...
Но это уже вопрос к формулистам: а как Excel на листе работает с формулами, возврашающими массив?
Я сам формул массива боюсь как бухгалтерия макросов biggrin
Поэтому на всякий случай в своей UDF-ке сделал возвращаемый массив с lBound=1 А оно кому-нибудь нужно?
К стати, код-то будет компактнее с наборной строкой, а вот про скорость...? Надо пытать. Есть у меня подозрение, что Split-Join внутри себя просто тупо перебирают массив.

Автор - Alex_ST
Дата добавления - 21.11.2011 в 14:02
v__step Дата: Понедельник, 21.11.2011, 14:07 | Сообщение № 17
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 225
Репутация: 27 ±
Замечаний: 0% ±

Ребята, все-таки, посмотрите код, приложенный к посту №11
Я же полностью переписал функцию, сохранив ParamArray
Задействовал не RegEx-замену, а RegEx.Matches + другой критерий поиска
Строку же для поиска предварительно получил конкатенацией всех строк
В какой-то мере это противоположный подход
А код получился - проще некуда
И не нужны ни Split, ни Join! Почти всю работу берет на себя RegExp
За замечание спасибо, я еще не усвоил все правила этикета


С уважением, Владимир

Сообщение отредактировал v__step - Понедельник, 21.11.2011, 14:18
 
Ответить
СообщениеРебята, все-таки, посмотрите код, приложенный к посту №11
Я же полностью переписал функцию, сохранив ParamArray
Задействовал не RegEx-замену, а RegEx.Matches + другой критерий поиска
Строку же для поиска предварительно получил конкатенацией всех строк
В какой-то мере это противоположный подход
А код получился - проще некуда
И не нужны ни Split, ни Join! Почти всю работу берет на себя RegExp
За замечание спасибо, я еще не усвоил все правила этикета

Автор - v__step
Дата добавления - 21.11.2011 в 14:07
nerv Дата: Понедельник, 21.11.2011, 14:18 | Сообщение № 18
Группа: Редакторы
Ранг: Обитатель
Сообщений: 431
Репутация: 193 ±
Замечаний: 0% ±

Quote (v__step)
Ребята, все-таки, посмотрите код, приложенный к посту №11

Так я по нем и делал : ) Только вместо цикла по ячейкам листа использовал цикл по массиву

Quote (nerv)
+ вместо промежуточного массива использовал строковую переменную

Это ж Ваше)


Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


YM 41001156540584 / WM WMR R21924176233

https://github.com/nervgh/vba
 
Ответить
Сообщение
Quote (v__step)
Ребята, все-таки, посмотрите код, приложенный к посту №11

Так я по нем и делал : ) Только вместо цикла по ячейкам листа использовал цикл по массиву

Quote (nerv)
+ вместо промежуточного массива использовал строковую переменную

Это ж Ваше)

Автор - nerv
Дата добавления - 21.11.2011 в 14:18
v__step Дата: Понедельник, 21.11.2011, 14:20 | Сообщение № 19
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 225
Репутация: 27 ±
Замечаний: 0% ±

Quote (v__step)
не RegEx-замену, а RegEx.Matches + другой критерий поиска
Это важнее!


С уважением, Владимир
 
Ответить
Сообщение
Quote (v__step)
не RegEx-замену, а RegEx.Matches + другой критерий поиска
Это важнее!

Автор - v__step
Дата добавления - 21.11.2011 в 14:20
Alex_ST Дата: Понедельник, 21.11.2011, 14:26 | Сообщение № 20
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3209
Репутация: 609 ±
Замечаний: 0% ±

2003
Володя,
я всегда догадывался, что ты круче варёных яиц! biggrin
Твой код из поста №11 прекрасно работает и невозможно краток
Ща полирну, добавлю обработку ошибок и ещё раз покручу-поверчу
Но куда уж нам, серым, про RegExp только краем уха слышавшим, до таких успехов в общении с МАЧО (matches biggrin ).
Надо учиться, учиться и ещё раз учиться, как говорил Вечно не похороненный.
Создай, плиз, топик-учебник по RegExp



С уважением,
Алексей
MS Excel 2003 - the best!!!


Сообщение отредактировал Alex_ST - Понедельник, 21.11.2011, 14:30
 
Ответить
СообщениеВолодя,
я всегда догадывался, что ты круче варёных яиц! biggrin
Твой код из поста №11 прекрасно работает и невозможно краток
Ща полирну, добавлю обработку ошибок и ещё раз покручу-поверчу
Но куда уж нам, серым, про RegExp только краем уха слышавшим, до таких успехов в общении с МАЧО (matches biggrin ).
Надо учиться, учиться и ещё раз учиться, как говорил Вечно не похороненный.
Создай, плиз, топик-учебник по RegExp

Автор - Alex_ST
Дата добавления - 21.11.2011 в 14:26
Мир MS Excel » Вопросы и решения » Готовые решения » Функция (UDF) "ИЗВЛЕЧЬЦЕЛЫЕ" (создать массив из целых чисел, извлечённых из текста ячеек)
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск:

Яндекс.Метрика Яндекс цитирования
© 2010-2024 · Дизайн: MichaelCH · Хостинг от uCoz · При использовании материалов сайта, ссылка на www.excelworld.ru обязательна!