Загрузка данных
' ===== В САМОМ ВЕРХУ МОДУЛЯ (Personal.xlsb) =====
Private SavedRow As Long
Private SavedCol As Long
Private SavedNumLines As Long
Private SavedOldData As Variant
' =================================================
Sub ВставитьСписокИзWordСНумерацией()
Dim dataObj As Object, clipText As String, linesArr As Variant
Dim i As Long, lineText As String
Dim numPart As String, textPart As String
Dim dotPos As Long, numLines As Long
Dim ws As Worksheet
Dim rngBefore As Range
' 1. Читаем буфер обмена
On Error Resume Next
Set dataObj = CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
If Err.Number <> 0 Then
On Error GoTo 0
Set dataObj = CreateObject("MSForms.DataObject")
End If
On Error GoTo 0
If dataObj Is Nothing Then
MsgBox "Не удалось получить доступ к буферу обмена.", vbExclamation
Exit Sub
End If
dataObj.GetFromClipboard
clipText = dataObj.GetText
If Len(Trim(clipText)) = 0 Then
MsgBox "Буфер обмена пуст или содержит не текст.", vbInformation
Exit Sub
End If
' 2. Разбиваем на строки, отбрасываем полностью пустые
Dim rawLines As Variant
rawLines = Split(clipText, vbCrLf)
If UBound(rawLines) < 0 Then rawLines = Split(clipText, vbLf)
Dim col As New Collection
Dim rawLine As Variant
For Each rawLine In rawLines
If Len(Trim(CStr(rawLine))) > 0 Then
col.Add CStr(rawLine)
End If
Next rawLine
If col.Count = 0 Then
MsgBox "Не найдено ни одной строки текста.", vbInformation
Exit Sub
End If
ReDim linesArr(0 To col.Count - 1)
For i = 0 To col.Count - 1
linesArr(i) = col(i + 1)
Next i
numLines = col.Count
' 3. Сохраняем состояние ячеек (столбцы C, D, E, F)
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 + 3))
If Not rngBefore Is Nothing Then
SavedOldData = rngBefore.Value
Else
SavedOldData = Empty
End If
' 4. Единая запись отмены
Dim undoRec As Object
On Error Resume Next
Set undoRec = Application.UndoRecord
On Error GoTo 0
If Not undoRec Is Nothing Then
undoRec.StartCustomRecord "Вставить список из Word"
End If
' 5. Заполняем ячейки (с защитой от ошибок)
Application.ScreenUpdating = False
For i = 0 To numLines - 1
lineText = linesArr(i)
numPart = ""
textPart = ""
Dim field2 As String, field3 As String
field2 = ""
field3 = ""
On Error GoTo SkipLine
Dim parts As Variant
parts = Split(lineText, vbTab)
Dim v0 As Variant, v1 As Variant, v2 As Variant
v0 = parts(0)
If UBound(parts) >= 1 Then v1 = parts(1) Else v1 = Empty
If UBound(parts) >= 2 Then v2 = parts(2) Else v2 = Empty
Dim field1 As String
field1 = SafeString(v0)
field2 = SafeString(v1)
field3 = SafeString(v2)
If Len(field1) > 0 Then
dotPos = InStr(field1, ". ")
If dotPos > 0 And dotPos > 1 Then
Dim leftPart As String
leftPart = Left(field1, dotPos - 1)
If IsNumeric(leftPart) Then
numPart = Left(field1, dotPos + 1)
textPart = Trim(Mid(field1, dotPos + 2))
Else
textPart = field1
End If
Else
textPart = field1
End If
End If
On Error GoTo 0
With ws.Cells(SavedRow + i, SavedCol)
.Value = numPart: .Font.Bold = False: .HorizontalAlignment = xlRight
End With
With ws.Cells(SavedRow + i, SavedCol + 1)
.Value = textPart: .Font.Bold = False
End With
With ws.Cells(SavedRow + i, SavedCol + 2)
.Value = field2: .Font.Bold = False
End With
With ws.Cells(SavedRow + i, SavedCol + 3)
.Value = field3: .Font.Bold = False
End With
GoTo NextLine
SkipLine:
On Error GoTo 0
With ws.Range(ws.Cells(SavedRow + i, SavedCol), ws.Cells(SavedRow + i, SavedCol + 3))
.Value = "": .Font.Bold = False
End With
NextLine:
Next i
' 6. Автоподбор высоты
ws.Rows(SavedRow & ":" & SavedRow + numLines - 1).EntireRow.AutoFit
' 7. Удаляем последнюю строку, только если она реально пустая и без номера
Dim lastRow As Long
lastRow = SavedRow + numLines - 1
If numLines > 1 Then
If Not ws.Cells(lastRow, SavedCol).MergeCells Then
If Not HasNumberInC(ws, lastRow, SavedCol) And IsRowEmpty(ws, lastRow, SavedCol, SavedCol + 3) Then
ws.Rows(lastRow).Delete Shift:=xlUp
numLines = numLines - 1
lastRow = lastRow - 1
End If
End If
End If
' 8. Горизонтальное объединение C и D в первой строке
If numLines > 0 Then
Dim rngFirstCD As Range
Set rngFirstCD = ws.Range(ws.Cells(SavedRow, SavedCol), ws.Cells(SavedRow, SavedCol + 1))
If rngFirstCD.MergeCells Then rngFirstCD.UnMerge
Dim firstText As String
firstText = Trim(CStr(ws.Cells(SavedRow, SavedCol + 1).Value))
If Len(firstText) = 0 Then firstText = Trim(CStr(ws.Cells(SavedRow, SavedCol).Value))
rngFirstCD.Merge
rngFirstCD.Value = firstText
rngFirstCD.Font.Bold = False
End If
' 9. Вертикальное объединение E и F (если одинаковые значения)
If numLines > 1 Then
Dim rngE As Range, rngF As Range
Set rngE = ws.Range(ws.Cells(SavedRow, SavedCol + 2), ws.Cells(lastRow, SavedCol + 2))
Set rngF = ws.Range(ws.Cells(SavedRow, SavedCol + 3), ws.Cells(lastRow, SavedCol + 3))
Dim dictE As Object, dictF As Object
Set dictE = CreateObject("Scripting.Dictionary")
Set dictF = CreateObject("Scripting.Dictionary")
For i = 0 To numLines - 1
Dim vE As Variant, vF As Variant
vE = ws.Cells(SavedRow + i, SavedCol + 2).Value
vF = ws.Cells(SavedRow + i, SavedCol + 3).Value
If Not IsEmpty(vE) Then
Dim normE As String: normE = SuperClean(CStr(vE))
If Len(normE) > 0 Then dictE(normE) = True
End If
If Not IsEmpty(vF) Then
Dim normF As String: normF = SuperClean(CStr(vF))
If Len(normF) > 0 Then dictF(normF) = True
End If
Next i
If dictE.Count = 1 Then
If rngE.MergeCells Then rngE.UnMerge
Dim uniqueE As String: uniqueE = dictE.Keys()(0)
rngE.ClearContents
rngE(1).Value = uniqueE
rngE(1).Font.Bold = False
rngE.Merge
End If
If dictF.Count = 1 Then
If rngF.MergeCells Then rngF.UnMerge
Dim uniqueF As String: uniqueF = dictF.Keys()(0)
rngF.ClearContents
rngF(1).Value = uniqueF
rngF(1).Font.Bold = False
rngF.Merge
End If
End If
If Not undoRec Is Nothing Then undoRec.EndCustomRecord
Application.ScreenUpdating = True
End Sub
Private Function IsRowEmpty(ws As Worksheet, rowNum As Long, colStart As Long, colEnd As Long) As Boolean
Dim c As Long
For c = colStart To colEnd
Dim vv As Variant: vv = ws.Cells(rowNum, c).Value
If Not IsEmpty(vv) Then
If Len(SuperClean(CStr(vv))) > 0 Then Exit Function
End If
Next c
IsRowEmpty = True
End Function
Private Function HasNumberInC(ws As Worksheet, rowNum As Long, colNum As Long) As Boolean
Dim cellVal As Variant: cellVal = ws.Cells(rowNum, colNum).Value
If IsEmpty(cellVal) Then Exit Function
Dim txt As String: txt = Trim(CStr(cellVal))
If Len(txt) = 0 Then Exit Function
Dim pos As Long: pos = InStr(txt, ". ")
If pos > 1 Then
If IsNumeric(Left(txt, pos - 1)) Then HasNumberInC = True
End If
End Function
Private Function SuperClean(txt As String) As String
If Len(txt) = 0 Then Exit Function
Dim result As String: result = txt
result = Replace(result, Chr(160), " ")
result = Replace(result, vbTab, " ")
result = Replace(result, vbCrLf, " ")
result = Replace(result, vbLf, " ")
result = Replace(result, vbCr, " ")
While InStr(result, " ") > 0
result = Replace(result, " ", " ")
Wend
SuperClean = Trim(result)
End Function
Private Function SafeString(v As Variant) As String
If IsNull(v) Or IsError(v) Then SafeString = "" Else SafeString = Trim(CStr(v))
End Function