Загрузка данных
' ===== В САМОМ ВЕРХУ МОДУЛЯ (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
' Табуляций нет — возможно, скопированы не ячейки строки, а отдельные абзацы
If CountNonEmptyLines(clipText) > 1 Then
MsgBox "В буфере обмена нет табуляций." & vbCrLf & _
"Скопируйте ТРИ ЯЧЕЙКИ В ОДНОЙ СТРОКЕ (выделив их горизонтально).", vbExclamation
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. Сохраняем состояние ячеек
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. Вставляем строки и заполняем
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
' Номер и текст в C и D
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
' Дополнительные ячейки в E и F
If multiPart Then
ws.Cells(SavedRow + i - 1, 5).Value = cell2Text
ws.Cells(SavedRow + i - 1, 5).Font.Bold = False
ws.Cells(SavedRow + i - 1, 6).Value = cell3Text
ws.Cells(SavedRow + i - 1, 6).Font.Bold = False
End If
Next i
' 6. Автоподбор высоты
ws.Rows(SavedRow & ":" & SavedRow + numLines - 1).EntireRow.AutoFit
' 7. Удаление пустых строк до следующей объединённой ячейки в 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 CountNonEmptyLines(ByVal text As String) As Long
Dim lines() As String
lines = SplitTextToLines(text)
Dim cnt As Long
Dim i As Long
cnt = 0
For i = 0 To UBound(lines)
If Len(Trim(lines(i))) > 0 Then cnt = cnt + 1
Next i
CountNonEmptyLines = cnt
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