Загрузка данных
' ===== В САМОМ ВЕРХУ МОДУЛЯ (Personal.xlsb) =====
Private SavedRow As Long
Private SavedCol As Long
Private SavedNumLines As Long
Private SavedOldData As Variant
' =================================================
Sub ВставитьСписокИзWordСНумерацией()
On Error GoTo ErrorHandler
Dim clipText As String
Dim ws As Worksheet
Dim rngBefore As Range
Dim multiPart As Boolean
Dim cell2Text As String, cell3Text As String
Dim colLines As Collection
Dim i As Long, numLines As Long
Dim lineText As String, numPart As String, textPart As String
Dim dotPos As Long
' 1. Получаем текст из буфера
clipText = GetClipboardText()
If Len(clipText) = 0 Then
MsgBox "Буфер обмена пуст или содержит не текст.", vbInformation
Exit Sub
End If
' 2. Определяем тип буфера: табуляции (горизонтально) или несколько строк (вертикально)
multiPart = (InStr(clipText, vbTab) > 0)
cell2Text = ""
cell3Text = ""
If multiPart Then
' Горизонтально: одна строка с табуляциями
Dim rows() As String, rowText As String
rows = SplitTextToLines(clipText)
rowText = ""
For i = 0 To UBound(rows)
If Len(Trim(rows(i))) > 0 Then
rowText = rows(i)
Exit For
End If
Next i
If rowText <> "" Then
Dim parts() As String
parts = Split(rowText, vbTab)
If UBound(parts) >= 1 Then
clipText = parts(0)
If UBound(parts) >= 2 Then cell2Text = CleanString(parts(1))
If UBound(parts) >= 3 Then cell3Text = CleanString(parts(2))
End If
End If
Else
' Нет табуляций – возможно вертикально (каждая ячейка на новой строке)
Dim allNonEmpty() As String
allNonEmpty = GetNonEmptyLines(clipText)
If UBound(allNonEmpty) >= 2 Then
' Первая строка – список, вторая и третья – доп. ячейки
clipText = allNonEmpty(0)
cell2Text = allNonEmpty(1)
If UBound(allNonEmpty) >= 3 Then cell3Text = allNonEmpty(2)
multiPart = True ' чтобы вставить E и F
Else
' Одна строка – обычный список
multiPart = False
End If
End If
' 3. Извлекаем непустые строки из первой части
Dim allLines() As String
allLines = SplitTextToLines(clipText)
Set colLines = New Collection
For i = 0 To UBound(allLines)
lineText = CleanString(allLines(i))
If Len(Trim(lineText)) > 0 Then
colLines.Add lineText
End If
Next i
If colLines.Count = 0 Then
MsgBox "Не найдено ни одной строки текста.", vbInformation
Exit Sub
End If
numLines = colLines.Count
' 4. Сохраняем состояние ячеек (C и D)
Set ws = ActiveSheet
SavedRow = ActiveCell.Row
SavedCol = ActiveCell.Column
SavedNumLines = numLines
Set rngBefore = ws.Range(ws.Cells(SavedRow, SavedCol), ws.Cells(SavedRow + numLines - 1, SavedCol + 1))
If Not rngBefore Is Nothing Then
SavedOldData = rngBefore.Value
Else
SavedOldData = Empty
End If
' 5. Вставляем строки и заполняем столбцы C и D
Application.ScreenUpdating = False
ws.Rows(SavedRow & ":" & SavedRow + numLines - 1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
For i = 1 To numLines
lineText = colLines(i)
dotPos = InStr(lineText, ". ")
If dotPos > 0 Then
Dim leftPart As String
leftPart = Left(lineText, dotPos - 1)
If IsNumeric(leftPart) And Len(leftPart) > 0 Then
numPart = leftPart & ". "
textPart = LTrim(Mid(lineText, dotPos + 2))
Else
numPart = ""
textPart = lineText
End If
Else
numPart = ""
textPart = lineText
End If
With ws.Cells(SavedRow + i - 1, SavedCol)
.Value = numPart
.Font.Bold = False
.HorizontalAlignment = xlRight
End With
With ws.Cells(SavedRow + i - 1, SavedCol + 1)
.Value = textPart
.Font.Bold = False
End With
Next i
' 6. Вставляем дополнительные ячейки ОДИН раз в строке SavedRow (E и F)
If multiPart Then
ws.Cells(SavedRow, 5).Value = cell2Text ' E
ws.Cells(SavedRow, 5).Font.Bold = False
ws.Cells(SavedRow, 6).Value = cell3Text ' F
ws.Cells(SavedRow, 6).Font.Bold = False
End If
' 7. Автоподбор высоты
ws.Rows(SavedRow & ":" & SavedRow + numLines - 1).EntireRow.AutoFit
' 8. Удаление строк до объединённой ячейки в C/D
Dim lastInsertedRow As Long, nextMergedRow As Long, r As Long
lastInsertedRow = SavedRow + numLines - 1
nextMergedRow = 0
For r = lastInsertedRow + 1 To lastInsertedRow + 1000
If ws.Cells(r, 3).MergeCells Or ws.Cells(r, 4).MergeCells Then
If ws.Cells(r, 3).MergeCells Then
nextMergedRow = ws.Cells(r, 3).MergeArea.Row
Else
nextMergedRow = ws.Cells(r, 4).MergeArea.Row
End If
Exit For
End If
Next r
If nextMergedRow > 0 Then
Dim firstRowToDelete As Long, lastRowToDelete As Long
firstRowToDelete = lastInsertedRow + 1
lastRowToDelete = nextMergedRow - 1
If lastRowToDelete >= firstRowToDelete Then
ws.Rows(firstRowToDelete & ":" & lastRowToDelete).Delete Shift:=xlUp
End If
End If
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "Ошибка " & Err.Number & ": " & Err.Description, vbCritical, "Ошибка в макросе"
End Sub
' ============================================================
' Вспомогательные функции (оставьте без изменений)
' ============================================================
Private Function GetClipboardText() As String
On Error Resume Next
Dim dataObj As Object
Set dataObj = CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
If Err.Number <> 0 Then
Err.Clear
Set dataObj = CreateObject("MSForms.DataObject")
End If
On Error GoTo 0
If dataObj Is Nothing Then
GetClipboardText = ""
Exit Function
End If
dataObj.GetFromClipboard
Dim txt As String
txt = ""
On Error Resume Next
txt = dataObj.GetText
If Err.Number <> 0 Then txt = ""
On Error GoTo 0
If IsNull(txt) Then txt = ""
GetClipboardText = txt
End Function
Private Function SplitTextToLines(ByVal text As String) As String()
Dim result() As String
If Len(text) = 0 Then
ReDim result(0 To 0)
result(0) = ""
SplitTextToLines = result
Exit Function
End If
Dim col As New Collection
Dim curLine As String
Dim i As Long
curLine = ""
For i = 1 To Len(text)
Dim ch As String
ch = Mid(text, i, 1)
If ch = vbCr Or ch = vbLf Then
If Len(curLine) > 0 Then
col.Add curLine
curLine = ""
End If
If ch = vbCr And i < Len(text) Then
If Mid(text, i + 1, 1) = vbLf Then i = i + 1
End If
Else
curLine = curLine & ch
End If
Next i
If Len(curLine) > 0 Then col.Add curLine
If col.Count = 0 Then
ReDim result(0 To 0)
result(0) = ""
Else
ReDim result(0 To col.Count - 1)
For i = 1 To col.Count
result(i - 1) = col(i)
Next i
End If
SplitTextToLines = result
End Function
Private Function CleanString(ByVal txt As String) As String
If Len(txt) = 0 Then
CleanString = ""
Exit Function
End If
txt = Replace(txt, Chr(160), " ")
Dim i As Long
For i = 1 To 31
If i <> 9 And i <> 10 And i <> 13 Then
txt = Replace(txt, Chr(i), "")
End If
Next i
CleanString = txt
End Function
Private Function GetNonEmptyLines(ByVal text As String) As String()
Dim lines() As String
lines = SplitTextToLines(text)
Dim col As New Collection
Dim i As Long
For i = 0 To UBound(lines)
If Len(Trim(CleanString(lines(i)))) > 0 Then
col.Add CleanString(lines(i))
End If
Next i
Dim result() As String
If col.Count = 0 Then
ReDim result(0 To 0)
result(0) = ""
Else
ReDim result(0 To col.Count - 1)
For i = 1 To col.Count
result(i - 1) = col(i)
Next i
End If
GetNonEmptyLines = result
End Function
' ============================================================
' Отмена последней вставки
' ============================================================
Sub ОтменитьПоследнююВставкуСписка()
On Error GoTo CancelError
If SavedNumLines <= 0 Then
MsgBox "Нет данных для отмены последней вставки.", vbInformation
Exit Sub
End If
Dim ws As Worksheet
Set ws = ActiveSheet
Application.ScreenUpdating = False
ws.Rows(SavedRow & ":" & SavedRow + SavedNumLines - 1).Delete Shift:=xlUp
If Not IsEmpty(SavedOldData) Then
Dim rngRestore As Range
Set rngRestore = ws.Range(ws.Cells(SavedRow, SavedCol), ws.Cells(SavedRow + SavedNumLines - 1, SavedCol + 1))
rngRestore.Value = SavedOldData
End If
SavedNumLines = 0
SavedOldData = Empty
Application.ScreenUpdating = True
Exit Sub
CancelError:
Application.ScreenUpdating = True
MsgBox "Ошибка при отмене: " & Err.Description, vbExclamation
End Sub