Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Excel VBA (часть 3)

Автор: asbo
Дата сообщения: 17.03.2011 23:35
Бля... я устал... Со мной-то что спорить? Я ничего не спрашивал.

* да, может и не то поудалять
* все-таки использовать .Value и сравнивать с "".
* Просто функцией IsEmpty вопрос не решается

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

И последнее:
* Если ячейка как-то модифицировалась, то возвращается "", а не Empty.
Кем возвращается? Код в студию.

Автор: DmitryPrint
Дата сообщения: 18.03.2011 00:52

Цитата:
Со мной-то что спорить?
Да бросьте, нафиг оно надо.

Цитата:
Кем возвращается? Код в студию.
для тестирования брал файл выложенный mrdime, и заново созданный.

на обоих одинаковые результаты выдаются при строке If Range(col & CStr(i)).Value <> "" Then
если использовать If Not IsEmpty(Range(col & CStr(i))) Then
то выложенном файле результат неверный, а в заново созданном все в порядке. С выложенным помогает только очистка ячеек.
(для сравнения с выложенным файлом, просмотр организован только для диапазона A8:A16)

Выходит, что сравнение с "" работает более универсально, чем IsEmpty.

P.S. А в случае, если информация содержит спецсимволы, то мне кажется проще все
это безобразие затянуть целиком в vba и обрабатывать в нем, обращаясь к Excel только для вывода результатов.

Код: Option Explicit

Function emptyCol(ByVal col As String) As Boolean
Dim i As Integer
For i = 8 To 16
' If Not IsEmpty(Range(col & CStr(i))) Then
If Range(col & CStr(i)).Value <> "" Then
emptyCol = False
Exit Function
End If
Next i
emptyCol = True
End Function

Sub test()
Dim myCol As String
myCol = "A"
If emptyCol(myCol) Then
MsgBox "column " & CStr(myCol) & " empty"
Else
MsgBox "column " & CStr(myCol) & " not empty"
End If
End Sub
Автор: SAS888
Дата сообщения: 18.03.2011 05:59
asbo
От Ваших слов "пахнет" оскорблением... Ну, ладно. Я не обидчивый. Давайте, все-таки, определим, какой метод быстрее. Для того, чтобы однозначно ответить на этот вопрос, предлагаю файл с исходными данными в столбце "A". Задача: с помощью макроса, получить значение первого встречающегося телефонного номера из каждой ячейки столбца "A" и поместить рядом в столбец "B".
В файл с данными я поместил свое решение этой задачи с применением объекта RegExp.
С нетерпением жду Вашего решения, которое (по Вашим, неизвестным науке расчетам) в 3 раза быстрее.
Автор: asbo
Дата сообщения: 18.03.2011 15:13
SAS888
* Давайте, все-таки, определим, какой метод быстрее.
А - Все уже определено. Меня не волнует, во сколько именно раз мой код быстрее Вашего. Важно то, что
1. Я это определил на глаз
2. Не выдавал это за безапелляционную истину.
3. Подтвердил свои утверждения отчетами.
4. Разница на порядок
5. Третьи библиотеки не используются
6. Я в сравнении не использовал заведомо более медленный вариант кода своего визави.
7. Алгоритм и его реализация более понятны конечному пользователю...
8. ... и, следоваетльно, легче адаптируются под возможные изменившиеся условия
(Последние два пункта - чисто субъективное имо - это все-таки мой код.)

Бэ - я с Вами буду взаимодействовать только после получения извинений за Вашу... э-э-э..., которую Вы позволили себе при проведении замеров.

Цэ - Если - см п. Бэ, то можно и побеседовать на тему моих "неизвестных науке расчетов". Только странно, как они могут Вас интересовать, если Вы уже дали им такую саркастическую оценку... И, обращаю Ваше внимание, что Вы, несмотря на неоднократные просьбы, так и не привели ни одной цифры из Ваших замеров. Одни [more=слова...]

* От Ваших слов "пахнет" оскорблением... Ну, ладно. Я не обидчивый
Главное, что от меня самого ничем не пахнет. Вы крайне непорядочно повели себя при этих замерах. Вот и делаем выводы - от кого и чем пахнет. И, во-первых, это не оскорбления, а констатация фактов, которые Вам кажутся оскорбительными, но от этого не перестают быть фактами. А во-вторых, если даже и посчитать это оскорблениями, то обида - немного не та эмоция, которую нормальный человек испытывает в ответ на оскорбления.

[/more]

Добавлено:
DmitryPrint
Я файл скачал, но кактастрофически не хватает времени взглянуть. Чуть позже, ОК?
Автор: SAS888
Дата сообщения: 18.03.2011 21:13
asbo

Цитата:
Меня не волнует, во сколько именно раз мой код быстрее Вашего

Вы не в то порядке употребили местоимения "мой" и "Ваш".

Цитата:
Бэ - я с Вами буду взаимодействовать только после получения извинений за Вашу... э-э-э..., которую Вы позволили себе при проведении замеров.
Все Ваши 8 пунктов ничего не стоят, пока Вы не утрете мне нос и представите решение предложенного примера быстрее, чем мой вариант (может быть и в 3 раза, кто Вас знает?), тогда получите мои извинения. В противном случае, извиниться должны Вы. Жду...
Автор: golkanavt
Дата сообщения: 19.03.2011 10:10
Всем привет. Вводная часть - есть Delphi-проект, в котором посредством Afalina XLReport создается прайс-лист с несколькими именованными листами (sheet). Каким образом можно в данном отчете после его создания добавить в начало книги еще один лист с оглавлением, т.е. чтобы в оглавлении были перечислены все листы со ссылками, т.е. чтобы по клику можно было переходить на нужный лист? В идеале кроме названия листов туда же желательно добавить и структурированное содержимое каждого листа, содержащего цены на те или иные объекты. Заранее спасибо откликнувшимся, готовым помочь в создании - буду благодарен посредством WMZ.
Автор: asbo
Дата сообщения: 19.03.2011 12:27
w01f14, DmitryPrint, Zloy_Gelud

У меня предложение - давайте забудем об использовании IsEmpty в качестве средства проверки содержимого ячейки на наличие-отсутствие чего-то. Это неправильно.

У меня это IsEmpty появилось в ответе w01f14 "Помогите сделать скрипт который проверит ячейку таблицы на пустоту". Почему я именно его взял? Не знаю. Я сейчас в Access-e плотно сижу, может на автомате написал... Впрочем, я оговорился в следующем же посте, но и меня это не насторожило, увы :( А когда речь зашла об апострофах и прочей нечисти, я уже на автомате посчитал использование IsEmpty за панацею от этих бед. После этого Zloy_Gelud задал вопрос с уже конкретно используемым IsEmpty и понеслось...

Предлагаю обратиться к первоисточникам. Прежде всего, IsEmpty - это VBA-шная функция, не Экселя, т.е. общая для всего Офиса:
Function IsEmpty(Expression) As Boolean, Member of VBA.Information

Во-вторых,

Цитата:
IsEmpty(expression) - Returns a Boolean value indicating whether a variable has been initialized.

The required expression argument is a Variant containing a numeric or string expression. However, because IsEmpty is used to determine if individual variables are initialized, the expression argument is most often a single variable name.

Remarks:
IsEmpty returns True if the variable is uninitialized, or is explicitly set to Empty; otherwise, it returns False. False is always returned if expression contains more than one variable. IsEmpty only returns meaningful information for variants.

Если кратко, то речь идет о проверке переменной - инициализированна она или нет.
Подсовывая ей выражение типа Cells(1,1).Value, мы передаем в нее переменную Value (свойство объекта Range) на предмет проверки ее на инициализацию. Не на проверку ее содержимого.

Я уже сокрушался по поводу убогости и скудности английского языка - вот и здесь (я всю тему просмотрел) все отчаянно ведутся на легко переводимое Empty - пустой. Как и я сам :)


Касательно апострофа...

Я пока не знаю, что с ним делать. Можно пытаться использовать Cells(1,1).SpecialCells(xlCellTypeConstants).Count
Но она странно работает с одиночной ячейкой. Надо ей в пару включать в проверяемый диапазон хотя бы еще одну ячейку, в которой заведомо содержится некое "нормальное" значение.

Автор: mrdime
Дата сообщения: 19.03.2011 12:55
В первую очередь адресую это asbo и DmitryPrint, которые заинтересовались моим вопросом насчет создания макроса по поиску и удалению из листа всех пустых строк и колонок.
Наваял вот такой макрос. Пока использовал проверку лишь на .Value=""
Пока получилось что-то такое, хотя конечно хотелось бы чтобы удалялись строки и колонки, заполенные пробелами и прочим содержимым, которое пропускает вышеуказанная проверка.
Хотелось бы услышать ваше мнение по этому поводу/ предложения по оптимизации кода.

Цитата:
Sub DelEmptyClmRws()
'Универсальный макрос для удаления пустых строк и колонок из листа
Dim R As Integer
Dim C As Integer
Dim I As Integer
Dim CheckCal As Integer
Dim CheckRaw As Integer
Dim ContrSum As Integer
'отменяем объединения ячеек, которые иногда создаются пользователями либо "кривыми" программами
ActiveSheet.UsedRange.MergeCells = False
'определям "рабочую зону" нашего листа
'строчки
R = ActiveSheet.UsedRange.Rows.Count
'колонки
C = ActiveSheet.UsedRange.Columns.Count
'ищем и удаляем пустые колонки
'задаем первую колонку, которая будет проверяться
CheckCol = 1
Do
ContrSum = 0
For I = 1 To R
If Cells(I, CheckCol).Value <> "" Then
'вводим контрольную сумму, если попадется хотя бы одна непустая ячейка
ContrSum = ContrSum + 1
End If
Next I
'если все ячейки пустые, удаляем колонку
If ContrSum = 0 Then
Columns(CheckCol).Delete Shift:=xlToLeft
'уменьшаем "рабочую зону" на единицу
C = C - 1
Else: CheckCol = CheckCol + 1
End If
Loop While CheckCol < C
'ищем и удаляем пустые строки
CheckRaw = 1
Do
ContrSum = 0
For I = 1 To C
If Cells(CheckRaw, I).Value <> "" Then
'вводим контрольную сумму, если попадется хотя бы одна непустая ячейка
ContrSum = ContrSum + 1
End If
Next I
'если все ячейки пустые, удаляем строчку
If ContrSum = 0 Then
Rows(CheckRaw).Delete Shift:=xlUp
'уменьшаем "рабочую зону" на единицу
R = R - 1
Else: CheckRaw = CheckRaw + 1
End If
Loop While CheckRaw < R
End Sub

Автор: asbo
Дата сообщения: 19.03.2011 14:09
На вскидку, - прежде всего я бы заменил
If Cells(I, CheckCol).Value <> ""
на
If Len(Cells(I, CheckCol).Value) > 0
Впрочем, с апострофом и это не проканает :) (т.е. ячейки, содержащие один-единственный апостроф тоже будет удалены, но, как я понял из файла , это вполне удовлятворяет)

Потом разделил бы код на четыре части:
1. Процедура определения рабочего диапазона
2. Процедура поиска пустых строк
3. Процедура поиска пустых колонок
4. Процедура удаления найденного по п.п. 2 и 3

Удобнее было бы и работать, и обсуждать :) И, главное(!) - модифицировать условия включения элементов в удаляемые. А это, скорее всего, понадобится :)
Автор: mrdime
Дата сообщения: 19.03.2011 14:41
asbo

Цитата:
прежде всего я бы заменил
If Cells(I, CheckCol).Value <> ""
на
If Len(Cells(I, CheckCol).Value) > 0

Что нам это даст?
Ячейки с пробелами, например, таким образом все равно проходят проверку.
Может ты хотел предложить проверку Len(Trim(Cells(I, CheckCol).Value)) > 0? Тогда диапазоны с пробелами улетают как надо.
НО не уверен насколько подобная проверка корректна, если в ячейках нестроковые данные. Ведь эта функция предназначена для работы с данными типа "string".

Цитата:
Потом разделил бы код на четыре части:

Хм... Может я чего-то не понял, но код фактически разделен на 3 части (нахождение рабочего диапазона, поиск пустых колонок, поиск пустых строк). Нет только 4-го пункта, т.е. пустые строки и столбцы удаляются непосредственно во время их нахождения.
Я думал о таком решении (выделить удаление отдельно). Как вариант можно их удалять не сразу, т.е. номера записывать в двухмерный массив, а потом в отдельной части их по очереди извлекать из массива (отдельно строчки, отдельно - столбцы) и удалять.
Я не особо силен в многомерных массивах, но попробую ради интереса реализовать.
В общем, узкую поставленную задачу можно считать решенной. Интересно создание универсального макроса (на все случааи жизни ), который бы кроме того, что уже делает предложенный выше вариант, мог удалять/ очищать строки и колонки со всем возможным мусором типа одинарных скобок ")", "(", апострофов, одинарных кавычек, неразрывных пробелов, знаков табуляции и т.д.
Автор: asbo
Дата сообщения: 19.03.2011 15:41
Бытует мнение, что так грамотнее. Вариант с Len должен работать быстрее, по-идее. Я в циклах именно его использую, а если всего один раз надо сравнить - пофиг, конечно. В первом случае сравниваются строки, вступает в действие стейтмент Options Compare (даже неявно). Просто пробел - частный случай строки с одним символом, как и пустая строка.

* Ячейки с пробелами, например, таким образом все равно проходят проверку.
Не понял... Результат идентичен:
? " " <> ""
True
? Len(" ") > 0
True

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

* эта функция предназначена для работы с данными типа "string".
Цитата:
Len Function returns a Long containing the number of characters in a string or the number of bytes required to store a variable.

Даже если говорить о первой части определения, то, я думаю, там используется неявное приведение типов к Str

* номера записывать в двухмерный массив
Быстрее запутаешься :) Один массив для номеров строк, второй - для номеров колонок. Когда заработает - можно и в двумерный загнать, если особая на то нужда будет. Часто читабельность кода перевешивает плюсы быстродействия и исполнения принятых нотаций написания.

Автор: Serzhsv
Дата сообщения: 19.03.2011 16:50
Помогите пожалуйста дополнить, исправить или вообще заменить код!
Нужно чтобы в листе "Отработано" после вставки выделялась следующая свободная строка, указывая место для следующей вставки.

Этот макрос вырезает выделенные строки в листе "NEW Счета", вставляет в выделенную строку (она всегда последняя свободная) в листе "Отработано". Затем в листе "NEW Счета" удаляет освободившиеся после вырезки строки.
После его выполнения в листе "Отработано" выделенными остаются последние вставленные строки, а нужно выделить следующую свободную, чтоб не указывать её каждый раз в ручную.

Sub отработано2()
'
' отработано2 Макрос
' Макрос записан 28.01.2011 (Менеджер)
'

'
Selection.Cut
Sheets("Отработано").Select
ActiveSheet.Paste
Sheets(" NEW Счета").Select
Selection.Delete Shift:=xlUp
ActiveCell.Rows("1:1").EntireRow.Select
End Sub
Автор: mrdime
Дата сообщения: 19.03.2011 17:54
asbo
В общем подшаманил код по твоим рекоммендациям (сделал два простых массива).
Вот что получилось:

Цитата:
Sub DelEmptyClmRws_v2()
'Универсальный макрос для удаления пустых строк из листа
Dim R As Integer
Dim C As Integer
Dim I As Integer
Dim Y As Integer
Dim Z As Integer
Dim CheckCal As Integer
Dim CheckRow As Integer
Dim ContrSum As Integer
'объявляем массивы с номерами пустых строк и столбцов
Dim EmptCol(1 To 100) As Integer
Dim EmptRow(1 To 100) As Integer

'отменяем объединения ячеек, которые иногда создаются пользователями либо "кривыми" программами
ActiveSheet.UsedRange.MergeCells = False
'1. определям "рабочую зону" нашего листа
'строчки
R = ActiveSheet.UsedRange.Rows.Count
'колонки
C = ActiveSheet.UsedRange.Columns.Count

'2. ищем пустые колонки
'задаем первую колонку, которая будет проверяться
CheckCol = 1
Y = 0
Do
ContrSum = 0
For I = 1 To R
If Len(Cells(I, CheckCol).Value) > 0 Then
'вводим контрольную сумму, если попадется хотя бы одна непустая ячейка
ContrSum = ContrSum + 1
End If
Next I
'если все ячейки пустые, записываем номер колонки
If ContrSum = 0 Then
Y = Y + 1
EmptCol(Y) = CheckCol
End If
CheckCol = CheckCol + 1
Loop While CheckCol <= C

'3. ищем пустые строки
CheckRow = 1
Z = 0
Do
ContrSum = 0
For I = 1 To C
If Len(Cells(CheckRow, I).Value) > 0 Then
'вводим контрольную сумму, если попадется хотя бы одна непустая ячейка
ContrSum = ContrSum + 1
End If
Next I
'если все ячейки пустые, записываем номер строчки
If ContrSum = 0 Then
Z = Z + 1
EmptRow(Z) = CheckRow
End If
CheckRow = CheckRow + 1
Loop While CheckRow <= R

'4. удаляем пустые строки и колонки
For I = 1 To Y
Columns(EmptCol(I)).Delete Shift:=xlToLeft
EmptCol(I + 1) = EmptCol(I + 1) - I
Next I
For I = 1 To Z
Rows(EmptRow(I)).Delete Shift:=xlUp
EmptRow(I + 1) = EmptRow(I + 1) - I
Next I

End Sub

Буду рад советам по расширению функционала по поиску разновсяческих "левых" символов в ячейках (как писал раньше).
Автор: asbo
Дата сообщения: 19.03.2011 18:37
mrdime, я бы процедуру удаления строк поместил перед процедурой поиска колонок - сократится количество ячеек к обработке. Если это приемлемо по логике работы и эргономике, конечно... Сорри, что я последовательно правлю - нет врмени.

Добавлено:
Да, чуть не забыл! Удалять сзаду надо начинать!
Автор: mrdime
Дата сообщения: 19.03.2011 20:49
asbo

Цитата:
Да, чуть не забыл! Удалять сзаду надо начинать!

Хорошая идея. Я здорово намучался, пока понял как правильно настроить удаление спереди.
Учту на будущее.
Автор: asbo
Дата сообщения: 19.03.2011 21:24
mrdime, ты меня все-таки разозлил на эту задачу :)) Не хотел я в нее глубоко вникать - нет времени, но, блин ...[more=Смотри:]

Код:
Sub sb_DelEmptyRC()
Dim rng As Range
Dim lR_Cnt&, lC_Cnt&
Set rng = ActiveSheet.UsedRange
With rng
lR_Cnt = .Rows.Count
lC_Cnt = .Columns.Count
End With

Call sb_DelEmptyRC_Del(rng1.Rows, lR_Cnt, lC_Cnt)
Call sb_DelEmptyRC_Del(rng1.Columns, lC_Cnt, lR_Cnt)
End Sub

Sub sb_DelEmptyRC_Del(pRng As Range, pEle&, pCmp&)
Dim i&
For i = pEle To 1 Step -1
With pRng(i)
If pCmp = .SpecialCells(xlCellTypeBlanks).Count Then
Debug.Print .Address
Stop
'.Delete
End If
End With
Next
End Sub
Автор: DmitryPrint
Дата сообщения: 20.03.2011 02:55

Цитата:
но что там произойдет с диапазонами
В порядке все. Второй раз по одному и тому же не проходит и ничего не пропускает. По лаконичности и компактности удаление здорово сделано.

Я бы, для начала, подрихтовал так:
Код: With rng
lR_Cnt = .Rows.Count
lC_Cnt = .Columns.Count

If lR_Cnt <= lC_Cnt Then
Call sb_DelEmptyRC_Del(.Columns, lC_Cnt, lR_Cnt)
Call sb_DelEmptyRC_Del(.Rows, lR_Cnt, .Columns.Count)
Else
Call sb_DelEmptyRC_Del(.Rows, lR_Cnt, lC_Cnt)
Call sb_DelEmptyRC_Del(.Columns, lC_Cnt, .Rows.Count)
End If
'Если первые пустые, то в .UsedRange они не входят
'удаляем (если надо конечно)
Do While (Mid(.Address, 2, 1) <> "A")
Range("A:A").Delete
Loop
Do While (Mid(.Address, 4, 1) <> "1")
Range("1:1").Delete
Loop
End With
Автор: mrdime
Дата сообщения: 21.03.2011 11:32
asbo
Взялся разобраться с твоей версией. Выглядит замечательно. Оч. лаконично.
Но, не понял, что ты здесь имеешь в виду:

Цитата:
Надо только перед этим удалить подводные камни с листа (очистить ячейки).

Какие ячейки и зачем их очищать?
Проверка If pCmp = .SpecialCells(xlCellTypeBlanks).Count Then
чего-то отрабатывает только на 20-й строчке (в выложенном мной примере) и все. Даже окно с адресом не выскакивает по Debug.Print. Как-то странно...
Что за "хитрая" констранта xlCellTypeBlanks? В объяснении написано, что это пустые ячейки. Только что в данном случае подразумевается под "пустыми ячейками"?
Автор: SAS888
Дата сообщения: 21.03.2011 13:51
mrdime
Хочу предупредить: (может быть, уважаемый asbo об этом не знает), что метод SpecialCells возвращает не более 8192 несмежных ячеек/диапазонов. Поэтому, при больших объемах таблиц, возможны ошибки. Будьте внимательны.
Автор: asbo
Дата сообщения: 21.03.2011 18:13
DmitryPrint, mrdime
* В порядке все...
- Увы нет, не все в порядке... См. файл с уточнениями.

mrdime
* Какие ячейки и зачем их очищать?
Если применительно к твоему файлу, то такие, как A15 (C,I,K etc.), в которых находится нечто и, поэтому, они не являются xlCellTypeBlanks. То же самое справедливо и для апострофов. "Очищать" (здесь) - удалять из них эти подводные камни, чтобы они корректно обрабатывались xlCellTypeBlanks.

* что в данном случае подразумевается под "пустыми ячейками"?
Это не ко мне. Это к БГ :) Возвращает якобы пустые (исключения мы уже видели)

* отрабатывает только на 20-й строчке (в выложенном мной примере)
Задача как стояла? Удалить пустые строки и колонки. Так ведь?
В упомянутом примере только одна (всего одна) пустая строка - 13. 20-я не пустая. Пустых колонок нет вообще.

SAS888
Цитата:
Хочу предупредить: (может быть, уважаемый asbo об этом не знает), что ...

Знал когда-то. Забыл. Извините, белая масса! Простите, белая масса!
Бзв, ограничение это применимо к Экселям до 2010

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

И, обращаю Ваше внимание - читайте тему. Внимательно(!) читайте. Вот мои оговорки, которые я делал выше: "Навскидку - логика правильная", "в качестве рыбы - пойдет". Да и других много.

Неужели без упоминания моего имени Ваш совет стал бы менее ценным?
Вы еще за прошлое не расчитались, а уже в новые дрязги пытаетеь встревать? Погодите малость - я Вам отповедь приготовил... Вы мне все настроение портите :(

Автор: SAS888
Дата сообщения: 23.03.2011 06:19
asbo

Цитата:
Вы еще за прошлое не расчитались...

Ну, вот... опять... Давайте отбросим всякие "нападки" и раз и навсегда решим этот спор.
Вот Вы меня обвинили в том, что для сравнения скорости выполнения поставленной задачи я взял не самый последний Ваш вариант. Да. Согласен. Но ведь Вы в своем сравнении сделали то же самое. В предложенном мной файле-примере я так же, как и Вы, немного скорректировал код (просто вынес одну строку кода за цикл). Но Вы никак не хотите этот файл посмотреть, сравнить со своим, и, наконец, сделать вывод. Только после этого будем говорить о взаиморасчетах...

Цитата:
Погодите малость - я Вам отповедь приготовил...
Очень надеюсь на то, что она ("отповедь") написана после того, как Вы сумели написать код, работающий быстрее моего (речь идет о предложенном файле-примере). С удовольствием посмотрю на это чудо. Но... все больше и больше сомневаюсь, что когда-нибудь это произойдет.

mrdime
Для решения Вашей задачи, предлагаю [more=такой]
Код: Sub Main()
Dim i As Long, x As Range: Application.ScreenUpdating = False
With ActiveSheet.UsedRange
For i = 1 To 3: .Replace Space(i), "", xlWhole: Next
.Value = .Value
For i = 1 To .Row + .Rows.Count - 1
If Rows(i).Text = "" Then If x Is Nothing Then Set x = Rows(i) Else Set x = Union(x, Rows(i))
Next
If Not x Is Nothing Then x.Delete
Set x = Nothing
For i = 1 To .Column + .Columns.Count - 1
If Columns(i).Text = "" Then If x Is Nothing Then Set x = Columns(i) Else Set x = Union(x, Columns(i))
Next
If Not x Is Nothing Then x.Delete
End With
End Sub
Автор: asbo
Дата сообщения: 23.03.2011 10:09
SAS888
Цитата:
Давайте отбросим всякие "нападки" и раз и навсегда решим этот спор.

Аристарх, голубь, давай бросим весь этот официоз и мирно-полюбовно встретимся где-нибудь в укромном уголке.

Хе-хе... Что творится - последнее время я уже с десяток, наверное, цитат из "Энергичных людей" по разным поводам нацитировал :)

* Да. Согласен. Но...
- Не надо "но". Вы и так все запутали. Надо - "извините".

* Вы в своем сравнении сделали то же самое
- Я не выбирал из имеющихся на тот момент вариантов. Что было, то и сравнил. После первого сравнения корретировок было уже множество, давайте не будем о том, что "после".

* Вы никак не хотите этот файл посмотреть
- Я посмотрел все материалы, предложенные Вами после возникновения этого скользкого (для Вас) статус-кво. Более того, провел необходимые замеры. Результаты интересные, неоднозначные, но я не хочу это обсуждать до того, как решится вопрос с самыми первыми замерами.

* надеюсь на то, она ("отповедь") написана после того, как Вы сумели написать код, работающий быстрее моего (речь идет о предложенном файле-примере).
- Точно так. Но Вы не даете мне возможность ее запостить, постоянно переключая меня на новые коды, их анализ, сравнение и погоню за этим гребанным быстродействием.

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

А касательно быстродействия - мой последний оптимизированный код все равно быстрее Вашего, предпоследнего (перед сегодняшним). Конечно, уже не с таким впечатляющим преимуществом. А иногда даже просто наравне... Но...

Но остается ведь еще пара немаловажных моментов для конечного пользователя:
- Отсутствие сторонних библиотек
- Отсутствие того дискомфорта, которое многие испытывают при работе с рег. выражениями.


Добавлено:
SAS888
* Application.ScreenUpdating = False
Я уже второй раз обращаю внимание ВСЕХ на необходимость отбойного
Application.ScreenUpdating = True

Добавлено:

Код: For i = 1 To 3
.Replace Space(i), "", xlWhole
Next
Автор: SAS888
Дата сообщения: 23.03.2011 10:52
asbo

Цитата:
Поймите - времени катстрофически мало. И меня уже не столько волнует быстродействие, как некоторые нюансы в методе измерений.
Согласен абсолютно. Данные моих замеров показывают либо одинаковые результаты, либо небольшое преимущество в мою пользу. Но, если хотите, в погоне "...за этим гребанным быстродействием." Можно оптимизировать и Ваш код. Так, например, функцию Mid(), которая Вами используется в цикле, лучше заменить на Mid$(), которая вернет результат немедленно, без его неявного преобразования в Variant. Также, в конструкции Select Case... Case... End Select, вместо Case 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 40, 41, 45 лучше использовать Case 48 To 57, 40, 41, 45, т.к. в первом случае, сравнение осуществляется с каждым элементом непрерывного диапазона, а во втором - только два сравнения с крайними значениями. Но, оба эти замечания, хоть и верные, но малосущественные. Однако, с Вашего позволения, я внес эти изменения в Ваш вариант и получил результаты измерения времени выполнения процедуры (как ни странно) совершенно одинаковыми с моим временем (+/- погрешность о которой Вы говорили).
Так что, получите и мои извинения.

Цитата:
Но остается ведь еще пара немаловажных моментов для конечного пользователя:
- Отсутствие сторонних библиотек
- Отсутствие того дискомфорта, которое многие испытывают при работе с рег. выражениями.

1. Эти "сторонние" библиотеки есть в Excel. Почему бы их не использовать? Можно, но зачем "вручную" выполнять встроенные в Excel методы?
2. Про какой дискомфорт Вы говорите? Наоборот, используя рег. выражения, все становится более компактным.
Автор: asbo
Дата сообщения: 23.03.2011 10:59
SAS888, ОК. Вернемся к этому. Позже.
А пока - я добавил свой вопросник по коду для mrdime постом выше. Взгляните, плз...
Автор: SAS888
Дата сообщения: 23.03.2011 10:59

Цитата:
А что делает вот это: .Value = .Value ?

Получаем массив из диапазона ячеек и вставляем его на то же место.
При формировании массива из непрерывного диапазона ячеек (например, a=ActiveSheet.UsedRange.Value), если какая-либо ячейка этого диапазона содержит одиночный апостроф, то он не будет помещен в массив. После этого, мы помещаем значения полученного массива на то же место. В результате, ячейки, которые содержали одиночный апостроф (невидимый в ячейке) будут пустыми.
Автор: asbo
Дата сообщения: 23.03.2011 11:08
SAS888 .Value = .Value
Ага... Это может оказаться хорошим инструментом для предварительной очистки. Как-то подозрительно гладко и просто :)

Применительно к данной задаче - пойдет. А вот как быть в общем случае, когда этот невидимый апостроф является значащим? Впрочем, когда доходит уже до таких узких задач обработки текстовых данных, надо ужЕ брать Access. Могут ведь и последовательности пробелов тоже оказаться значащими :)
Автор: SAS888
Дата сообщения: 23.03.2011 11:09
"Ответник" на вопросник:

Цитата:
Мне не нравится это If Rows(i).Text = "" Then
Неявное приведение интерепретирует Null как False в то же время, как при наличии данных в яейках проверка всей строки все равно выдет Null...

Великий Уокенбах для проверки строки на пустоту советует использовать Application.CountA(). Но она (эта функция), опять же, работает медленнее. Что касается If Rows(i).Text="", то мне такая конструкция нравится. Не совсем верно то, что она Null интерпретирует как False. Точнее, она Null интерпретирует как "". Более того, сравнивать можно только на равенство с пустотой (""). Если же нужно проверить, что строка не пуста, то только так: If Rows(i).Text="" Then Else... Т.е. запись If Rows(i).Text<>"" Then..., также, как и If Not Rows(i).Text="" Then... не приведет к ошибке, но выдаст ошибочный результат.


Цитата:
Как-то подозрительно гладко и просто
Есть существенное ограничение на применение данного способа, т.к. кроме апострофов исчезнут все формулы и связи (если таковые присутствовали). Все будет преобразовано в значения. Кстати говоря, иногда требуется выполнить именно такую задачу.


Цитата:
Сугубо частный случай. Нужно общее решение. И для 10-ти и 20-ти...

Кто не дает использовать цикл For i=1 To 20 ? Явного перебора ячеек в макросе нет (что есть хорошо). А цикл Replace-ов много времени не займет.


Цитата:
А вот как быть в общем случае, когда этот невидимый апостроф является значащим?
Могут ведь и последовательности пробелов тоже оказаться значащими

Благодаря опции xlWhole, примененной в методе Replace, очищены будут только те ячейки, которые кроме пробела(ов) больше не содержат ни одного символа. Логично предположить, что такие пробелы вряд ли могут быть значащими. Аналогично и с апострофом: если ячейка, помимо лидирующего апострофа содержит хотя бы один значащий символ (пусть даже еще один апостроф), то, во-первых, ее содержимое будет видно на рабочем листе. Во-вторых, она считается непустой и, соответственно, очищена не будет.
Вообще, я преследовал цель, убрать все символы, которые не видно в ячейках рабочего листа, т.е. сделать их пустыми. Вторая цель - это избежать явный перебор ячеек.


Цитата:
Впрочем, когда доходит уже до таких узких задач обработки текстовых данных...
Абсолютно с Вами согласен. Если есть полный и точный список того, что нужно очищать, то все выполнимо. А если нет... К каждой задаче требуется индивидуальный подход. Но в данном конкретном случае, автор вопроса просил удалить все пустые, а также те, которые "кажутся" пустыми (т.е. содержат символы невидимые на рабочем листе) строки и столбцы.


Цитата:
Я уже второй раз обращаю внимание ВСЕХ на необходимость отбойного
Application.ScreenUpdating = True
По большому счету, Вы правы. Но, если в проекте не предусматривается вызов процедуры из процедуры, то True восстанавливается поле окончания работы макроса. Попробуйте, например, выполнить процедуру, после выхода из которой, значение Application.ScreenUpdating не устанавливается в True. Затем попробуйте выполнить другую процедуру, которая никак не затрагивает Application.ScreenUpdating. Очевидно, что обновление экрана осуществляется.
Повторяюсь, что во избежании возможных неприятностей, для более сложных проектов и для проектов, использующих события, лучше это значение восстанавливать. А если речь идет об отдельно взятом макросе, то можно этого и не делать. Каюсь. Грешен. Я часто "не закрываю скобки", применяя ScreenUpdating, DisplayAlerts, On Error Resume Next и т.п. Во-первых, просто лень. Во-вторых, в таком случае, нужно следить за ходом выполнения всех процедур проекта в целом.
Автор: golkanavt
Дата сообщения: 24.03.2011 18:25

Цитата:
Всем привет. Вводная часть - есть Delphi-проект, в котором посредством Afalina XLReport создается прайс-лист с несколькими именованными листами (sheet). Каким образом можно в данном отчете после его создания добавить в начало книги еще один лист с оглавлением, т.е. чтобы в оглавлении были перечислены все листы со ссылками, т.е. чтобы по клику можно было переходить на нужный лист? В идеале кроме названия листов туда же желательно добавить и структурированное содержимое каждого листа, содержащего цены на те или иные объекты. Заранее спасибо откликнувшимся, готовым помочь в создании - буду благодарен посредством WMZ.

Ну что, нет желающих взяться за задачу?
Автор: andrewkard1980
Дата сообщения: 24.03.2011 22:33
Добрый день!
Если возможность средствами vba excel перевести строку из символов HTML в латиницу?

Например, строка - &#50;&#52;&#48;&#110;&#111;&#107
Когда я получаю данные, я могу скопировать их в блокнот и сохранить файл в формате .html и все читается. Но так не совсем годится.
Подскажите, пожалуйста.
Заранее спасибо.

Автор: AndVGri
Дата сообщения: 25.03.2011 04:38
golkanavt

Код:
Public Sub AddSheetLinks()
Dim i As Long, pSheet As Excel.Worksheet, sName As String
Set pSheet = ActiveWorkbook.Worksheets.Add(ActiveWorkbook.Worksheets(1))
For i = 2 To ActiveWorkbook.Worksheets.Count
sName = ActiveWorkbook.Worksheets(i).Name
pSheet.Hyperlinks.Add pSheet.Cells(i, 1), "", sName & "!A1", , sName
Next i
End Sub

Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127

Предыдущая тема: VS 2010


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.