#vba #excel
#vba #excel
Вопрос:
У меня есть рабочий лист с множеством таблиц, и я только начинаю использовать таблицы, потому что они кажутся довольно удобными. Но я никогда раньше не манипулировал содержимым в таблице Excel. И эти таблицы в основном представляют собой списки столбцов с именем и фамилией. На основе значений в этих столбцах я хочу сгенерировать имя пользователя. Но я пытаюсь написать общий подраздел, который принимает аргументы, такие как рабочий лист и имя таблицы.
Ранее я делал это, когда данных не было в таблице:
Cells(2, 2).Select
Do
strFirstName = ActiveCell.Value
strLastName = ActiveCell.Offset(0, 2).Value
strFirstName = Left(strFirstName, 1)
strUserName = strFirstName amp; strLastName
strUserName = LCase(strUserName)
ActiveCell.Offset(0, 5).Value = strUserName
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell)
И теперь я пытаюсь сделать то же самое, только с данными из таблицы. Есть идеи? Я добавил наблюдение за «ActiveSheet», чтобы посмотреть, смогу ли я найти таблицы, и они, похоже, есть ActiveSheet.ListObjects
, но я не видел .Select
там никаких опций. Возможно, мне не нужно выбирать таблицу, чтобы манипулировать ее содержимым?
Ответ №1:
При циклическом перемещении по диапазону (будь то в таблице или в диапазоне) обычно быстрее копировать данные в массив вариантов, манипулировать этим массивом, а затем копировать результат обратно на лист.
Sub zz()
Dim oUsers As ListObject
Dim v As Variant
Dim vUserName() As Variant
Dim i As Long
Dim colFirst As Long
Dim colLast As Long
Dim colUser As Long
Set oUsers = ActiveSheet.ListObjects(1)
colFirst = oUsers.ListColumns("FirstName").Index
colLast = oUsers.ListColumns("LastName").Index
colUser = oUsers.ListColumns("UserName").Index
v = oUsers.DataBodyRange
ReDim vUserName(1 To UBound(v, 1), 1 To 1)
For i = 1 To UBound(v, 1)
vUserName(i, 1) = LCase(Left(v(i, colFirst), 1) amp; v(i, colLast))
Next
oUsers.ListColumns("UserName").DataBodyRange = vUserName
End Sub
Если вы действительно хотите перебрать сам диапазон:
For i = 1 To oUsers.ListRows.Count
oUsers.ListColumns("UserName").DataBodyRange.Rows(i) = LCase(Left( _
oUsers.ListColumns("FirstName").DataBodyRange.Rows(i), 1) amp; _
oUsers.ListColumns("LastName").DataBodyRange.Rows(i))
Next
В этой ситуации вы также можете просто использовать формулу в самом UserName
столбце, без необходимости vba
=LOWER(LEFT([@FirstName],1)amp;[@LastName])
Редактировать
Извините, не знаю способа удаления любого из списка символов из строки. Возможно, для этого вам придется вернуться к vba. Вот определяемая пользователем функция для этого. Ваша формула станет
=DeleteChars([@UserName],{"$","#"})
Чтобы удалить символы {"$","#"}
, замените массив списком символов, которые вы хотите удалить (вы можете сделать список таким длинным, какой вам нужен)
Для замены символов используйте {"$","#";"X","X"}
, где список до; старые символы, после ; новые. Просто убедитесь, что listsa имеют одинаковую длину.
UDF-код:
Function DeleteChars(r1 As Range, ParamArray c() As Variant) As Variant
Dim i As Long
Dim s As String
s = r1
If UBound(c(0), 1) = 1 Then
For i = LBound(c(0), 2) To UBound(c(0), 2)
s = Replace(s, c(0)(1, i), "")
Next
Else
For i = LBound(c(0), 2) To UBound(c(0), 2)
s = Replace(s, c(0)(1, i), c(0)(2, i))
Next
End If
DeleteChars = s
End Function
Комментарии:
1. Последняя формула идеальна! Спасибо! Есть ли у вас, кстати, какой-либо способ объединить эту формулу для замены символов? У некоторых людей в фамилиях есть странные символы, и я бы хотел заменить их на имена пользователей. Только если вы случайно знаете 🙂