Переписал код на массивы, может будет чуток быстрее работать. Код срабатывает только на изменение значения в первом столбце
Код
Private Sub get_color(dict As Object)
Dim i As Long, arr As Variant
Dim color As Long, upperbound As Long, lowerbound As Long
Set dict = CreateObject("Scripting.Dictionary")
With ActiveSheet
upperbound = 15983321 ' нижняя граница цвета
lowerbound = 15970000 ' верхняя граница цвета
arr = .Range("A1:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)
For i = 2 To UBound(arr, 1)
If .Cells(i, 1).Interior.color = 16777215 Then
If Not dict.exists(arr(i, 1)) Then
color = Int((upperbound - lowerbound + 1) * Rnd + lowerbound) ' случайный цвет
End If
Else
color = .Cells(i, 1).Interior.color
End If
If Not dict.exists(arr(i, 1)) Then
dict.Add arr(i, 1), color
Else
dict(arr(i, 1)) = color
End If
Next i
End With
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 1 Then Exit Sub
Static dict As Object
If dict Is Nothing Then Call get_color(dict)
Target.EntireRow.Interior.color = dict(Cells(Target.Row, 1).Value)
End Sub
Мария Мария, добрый день! Вариант макросом (открываем книгу->включить макросы->Alt+F11->смотрим в окне "Project" лист1->проваливаемся в него и смотрим код) Код нужно будет вставить в модуль листа Вашей книги Код:
Код
Option Explicit
Private Sub get_color(dict As Object)
Dim i As Object, color As Long, upperbound As Long, lowerbound As Long
Set dict = CreateObject("Scripting.Dictionary")
With ActiveSheet
upperbound = 15983321 ' нижняя граница цвета
lowerbound = 15970000 ' верхняя граница цвета
For Each i In .Range("A2:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)
If i.Interior.color = 16777215 Then
If Not dict.exists(i.Value) Then
color = Int((upperbound - lowerbound + 1) * Rnd + lowerbound) ' случайный цвет
End If
Else
color = i.Interior.color
End If
If Not dict.exists(i.Value) Then
dict.Add i.Value, color
Else
dict(i.Value) = color
End If
Next i
End With
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Static dict As Object
If dict Is Nothing Then Call get_color(dict)
Target.EntireRow.Interior.color = dict(Cells(Target.Row, 1).Value)
End Sub
Дмитрий Дегтяренко, добрый день! Во вложении вариант пользовательской функцией. Первый параметр - диапазон для суммирования, вторым - критерий: человеки, литры, см, и т.п.
Код
Function countWithRegEx(dataRange As Range, criteria As String) As String
Dim i As Range, totalSumm As Double
totalSumm = 0
With CreateObject("VBScript.Regexp")
.Global = False
.MultiLine = False
.IgnoreCase = False
.Pattern = "\d+\,?\d*"
For Each i In dataRange
If .test(i.Value) Then totalSumm = totalSumm + CDbl(.Execute(i.Value)(0))
Next i
End With
countWithRegEx = CStr(totalSumm) & " " & criteria
End Function
Артём Москвитин, добрый день! Вариант пользовательской функцией с использованием регулярных выражений (см столбец B):
Код
Function regexExtract(cell As Range) As String
With CreateObject("VBScript.Regexp")
.Pattern = "[A-Z]{2}\-?[A-Z0-9]+"
.Global = False
.MultiLine = False
.Ignorecase = False
If .test(cell) Then regexExtract = .Execute(cell)(0): Exit Function
End With
regexExtract = "without matches"
End Function
Можно регулярками. Если нужно макросом, то см. код ниже. Работает на активном листе и вытаскивает нужное во второй столбец (предполагается, что столбец у Вас один и он 1)
Код
Sub test()
Dim s as string
Dim arr
Dim i as long
With ActiveSheet
arr = .cells(1,1).CurrentRegion
for i = Lbound(arr, 1) to Ubound(arr, 1)
.cells(i,2) = split(arr(i,1), "_")(1)
next i
End With
End Sub
capybarasan, добрый вечер! Если вопрос потерпит до завтра, то смогу с утра посмотреть и выслать Вам свои предложения и черновой вариант работы. Если нет, то заказ не занимаю. Спасибо!
asesja, здравствуйте! Как вариант, если используете Windows, то пользоваться встроенным антивирусом от Microsoft, а файлы проверять на сервисе VirusTotal
Обернуть в пользовательскую функцию и вытаскивать 1 захватывающую группу (которая в скобках) Выражение означает: взять все символы до конца строки и уступить с конца строки все символы до 2 слешей, включая их, запомнить все, что совпало, кроме слешей в регулярном выражении, в группу 1 код:
Код
Function regex_execute(what, pattern) As String
'regex_execute -- функция для извлечения текста
'what - ячейка с исходным текстом
'pattern - паттерн - строка для регулярного выражения
With CreateObject("VBScript.Regexp")
.Global = False
.MultiLine = False
.Ignorecase = True
.pattern = pattern
If .test(what) Then regex_execute = .Execute(what).Item(0).submatches.Item(0): Exit Function
End With
regex_execute = "нет совпадений"
End Function
Hugo, большое спасибо! Внес правки в код (ниже). Михаил Л, второй вариант (теперь порядок слов в массиве исключений и регистр не имеет значения)
Скрытый текст
Код
Sub подсветить_дубликаты()
Dim dict As Object, arr As Variant, exception_arr As Variant, exception_dict As Object, item As Variant
Dim i As Variant, data_range As Range
exception_arr = Array("картошка", "огурцы") ' в этот массив ИСКЛЮЧЕНИЙ (регистр и порядок не имеет значения)
Set exception_dict = CreateObject("Scripting.Dictionary") ' создаем словарь исключений
' загружаем исключения в словарь исключений
For i = LBound(exception_arr) To UBound(exception_arr)
exception_dict.Add LCase(Trim(exception_arr(i))), 0 ' загоняем слова из масиива исключений в словарь exception_dict
Next i
Set data_range = Application.InputBox("выберите диапазон для выделения дубликатов", , , , , , , 8) ' выбор диапазона (тип 8 == объекту диапазон)
arr = data_range ' загоняем выделенный диапазон в массив
Set dict = CreateObject("Scripting.Dictionary") ' создаем словарь
' ниже цикл для поиска дубликатов в выделенном дипазоне (уже помещенном в массив)
For i = LBound(arr, 1) To UBound(arr, 1)
If Not dict.exists(arr(i, 1)) Then ' если нет такого в словаре, то
dict.Add (LCase(Trim(arr(i, 1)))), 1 ' ключ словаря == значение, значение словаря == 1 (т.е количество повторов)
Else ' иначе
dict(arr(i, 1)) = dict(arr(i, 1)) + 1 ' прибавляем 1 к значению словаря ( то есть этот участовк кода отрабатывает, когда найден первый и последующий дубликаты)
End If
Next i
'---------------------------------------------------------------------------
' ОБРАБАТЫВАЕМ ИСКЛЮЧЕНИЯ
For Each item In dict.keys() ' цикл по ключам словаря для удаления исключений
If exception_dict.exists(item) Then dict(item) = 0 ' если значение item присутствует в словаре исключений exception_dict, то сбрасываем счетчик количества этого значения _
в словаре dict с ключем item
Next item
'---------------------------------------------------------------------------
'ОКРАСКА ЯЧЕЕК
For i = LBound(arr, 1) To UBound(arr, 1) ' цикл по массиву
If dict(arr(i, 1)) > 1 Then data_range(i, 1).Interior.Color = RGB(255, 242, 204) ' если есть дубликаты, то красим
Next i
'----------------------------------------------------------------------------
End Sub
Sub очистка_формата()
' очистка форматов для выделенного участка листа
With Selection
.ClearFormats
End With
End Sub
Михаил Л, только сейчас посмотрел свое предыдущее сообщение (#14) Нюанс: предполагается, что значения в массиве исключений - exception_arr заносятся в алфавитном порядке (в комментариях в коде это прописал, так как функция бинарного поиска (использованнная в моём коде) работает только с отсортированным массивом), то есть:
Sub подсветить_дубликаты()
Dim dict As Object, arr As Variant, exception_arr As Variant, item As Variant
Dim i As Variant, data_range As Range
exception_arr = Array("картошка", "огурцы") ' в этот массив ИСКЛЮЧЕНИЙ заносим значения в алфавитном порядке, так как для поиску по нему используется БИНАРНЫЙ ПОИСК
Set data_range = Application.InputBox("выберите диапазон для выделения дубликатов", , , , , , , 8) ' выбор диапазона (тип 8 == объекту диапазон)
arr = data_range ' загоняем выделенный диапазон в массив
Set dict = CreateObject("Scripting.Dictionary") ' создаем словарь
' ниже цикл для поиска дубликатов в выделенном дипазоне (уже помещенном в массив)
For i = LBound(arr, 1) To UBound(arr, 1)
If Not dict.exists(arr(i, 1)) Then ' если нет такого в словаре, то
dict.Add (arr(i, 1)), 1 ' ключ словаря == значение, значение словаря == 1 (т.е количество повторов)
Else ' иначе
dict(arr(i, 1)) = dict(arr(i, 1)) + 1 ' прибавляем 1 к значению словаря ( то есть этот участовк кода отрабатывает, когда найден первый и последующий дубликаты)
End If
Next i
For Each item In dict.keys() ' цикл по ключам словаря для удаления исключений
If binary_search(exception_arr, item) <> -1 Then dict(item) = 0 ' если значение item присутствует в массиве исключений, то сбрасываем счетчик количества этого значения
Next item
For i = LBound(arr, 1) To UBound(arr, 1) ' цикл по массиву
If dict(arr(i, 1)) > 1 Then data_range(i, 1).Interior.Color = RGB(255, 242, 204) ' если есть дубликаты, то красим
Next i
End Sub
Sub очистка_формата()
' очистка форматов для выделенного участка листа
With Selection
.ClearFormats
End With
End Sub
Private Function binary_search(arr, what) As Long
'функция поиска значения what в одномерном массиве arr
Dim p, q, r
p = 0: r = UBound(arr)
While p <= r
q = Int((p + r) / 2)
If LCase(Trim(arr(q))) = LCase(Trim(what)) Then binary_search = q: Exit Function
If LCase(Trim(arr(q))) > LCase(Trim(what)) Then
r = q - 1
Else
p = q + 1
End If
Wend
binary_search = -1
End Function
Hugo, спасибо большое за code review, внес правки в свой код! Михаил Л, добавил функцию бинарного поиска и массив для исключений (в коде добавил соответствующие строки и комментарии). Предполагается, что значения в массиве исключений - exception_arr заносятся в алфавитном порядке, то есть, например:
Sub подсветить_дубликаты()
Dim dict As Object, arr As Variant, exception_arr As Variant
Dim i As Variant, data_range As Range
exception_arr = Array("картошка", "огурцы") ' в этот массив ИСКЛЮЧЕНИЙ заносим значения в алфавитном порядке, так как для поиску по нему используется БИНАРНЫЙ ПОИСК
With ActiveSheet
Set data_range = Application.InputBox("выберите диапазон для выделения дубликатов", , , , , , , 8) ' выбор диапазона (тип 8 == объекту диапазон)
arr = data_range ' загоняем выделенный диапазон в массив
Set dict = CreateObject("Scripting.Dictionary") ' создаем словарь
' ниже цикл для поиска дубликатов в выделенном дипазоне (уже помещенном в массив)
For i = LBound(arr, 1) To UBound(arr, 1)
If binary_search(exception_arr, arr(i, 1)) = -1 Then
If Not dict.exists(arr(i, 1)) Then ' если нет такого в словаре, то
dict.Add (arr(i, 1)), 1 ' ключ словаря == значение, значение словаря == 1 (т.е количество повторов)
Else ' иначе
dict(arr(i, 1)) = dict(arr(i, 1)) + 1 ' прибавляем 1 к значению словаря ( то есть этот участовк кода отрабатывает, когда найден первый и последующий дубликаты)
End If
End If
Next i
For i = LBound(arr, 1) To UBound(arr, 1) ' цикл по массиву
If dict(arr(i, 1)) > 1 Then data_range(i, 1).Interior.Color = RGB(255, 242, 204) ' если есть дубликаты, то красим
Next i
End With
End Sub
Sub очистка_формата()
' очистка форматов для выделенного участка листа
With Selection
.ClearFormats
End With
End Sub
Private Function binary_search(arr, what) As Long
'функция поиска значения what в одномерном массиве arr
Dim p, q, r
p = 0: r = UBound(arr)
While p <= r
q = Int((p + r) / 2)
If LCase(Trim(arr(q))) = LCase(Trim(what)) Then binary_search = q: Exit Function
If LCase(Trim(arr(q))) > LCase(Trim(what)) Then
r = q - 1
Else
p = q + 1
End If
Wend
binary_search = -1
End Function
Михаил Л, все таки выложу тут код с комментариями, вдруг пригодится Вам (запускаете макрос, выбираете диапазон (только с наименованием для поиска дубликатов)):
Скрытый текст
Код
Sub подсветить_дубликаты()
Dim dict As Object, arr As Variant, item As Variant, data_range As Range
Dim i As Long, nextRow As Long, next_range As Range
With ActiveSheet
Set data_range = Application.InputBox("выберите диапазон для выделения дубликатов", , , , , , , 8) ' выбор диапазона (тип 8 == объекту диапазон)
arr = data_range ' загоняем выделенный диапазон в массив
Set dict = CreateObject("Scripting.Dictionary") ' создаем словарь
' ниже цикл для поиска дубликатов в выделенном дипазоне (уже помещенном в массив)
For i = LBound(arr, 1) To UBound(arr, 1)
If Not dict.exists(arr(i, 1)) Then ' если нет такого в словаре, то
dict.Add (arr(i, 1)), 1 ' ключ словаря == значение, значение словаря == 1 (т.е количество повторов)
Else ' иначе
dict(arr(i, 1)) = dict(arr(i, 1)) + 1 ' прибавляем 1 к значению словаря ( то есть этот участовк кода отрабатывает, когда найден первый и последующий дубликаты)
End If
Next i
For Each item In dict.keys() ' цикл по клюючам словаря
If dict(item) > 1 Then ' если есть дубликаты, то
Set next_range = data_range.Find(item) ' ищем 1 дубликат в диапазоне (котрый выбрали в начале кода)
nextRow = next_range.Row ' запоминаем строку с дубликатом
Do ' пока
next_range.Interior.Color = RGB(255, 242, 204) ' красим дубликат
Set next_range = data_range.FindNext(next_range) ' ищем дальше дубликаты
Loop While nextRow <> next_range.Row ' первая строка с дубликатом не равна строке найденного совпадения
End If
Next item
End With
End Sub
Sub очистка_формата()
' очистка форматов для выделенного участка листа
With Selection
.ClearFormats
End With
End Sub
Михаил Л, здравствуйте! Можно, например, использовать код с такой логикой: 1.загоняем всю таблицу в массив 2.создаем словарь типа - ключ=наименование, значение=количество повторов (при помощи цикла по массиву) 3. проходим циклом по словарю и, где количество значений больше 1, используя метод find в диапазоне значений для выделения, выделяем нужное.