Преобразование неструктурированных данных (сцепленных строк текста) в пригодный для чтения, читаемый формат / извлечение точек данных из строк - PullRequest
0 голосов
/ 11 марта 2020

Я пытаюсь извлечь указанные c точки данных из строки текста, и мне трудно понять, как это сделать.


Что мне нужно сделать, это извлечь даты с указанием c строка . Структура строки выглядит следующим образом: Продукт: XX1, Сделано: WWW ZZZ, Дата: ГГГГ-ММ-ДД; , и это может повторяться несколько раз (см. Скриншот ниже). Существует три различных типа продуктов (скажем, Car_VW, Car_Tesla, Car_PS - нет записей с другими типами продуктов), и date необходимо извлекать отдельно для каждого из них.

Более того, один тип продукта может появляться несколько раз (до трех раз) в этой строке , поэтому дата должна храниться отдельно для каждого экземпляра ее появления.

Columns E - M show what I need to achieve based on data in column C

Столбцы E - M показывают, что мне нужно достичь на основе данных в столбце C

Я пришел по следующей формуле :

=IFERROR(IF(AND(FIND(LEFT(E$3,6),$C4,1)>0,FIND("Product",$C4,1)=1),MID(MID($C4,FIND(LEFT(E$3,6),$C4,1),LEN($C4)-FIND(LEFT(E$3,6),$C4,1)),FIND("Date: ",MID($C4,FIND(LEFT(E$3,6),$C4,1),LEN($C4)-FIND(LEFT(E$3,6),$C4,1)),1)+6,10),"no go"),"")

, который работает только для первых «итераций» каждого продукта. dates after formula is applied

Глядя на форматирование данных в столбце C, думаете ли вы, ребята, что можно написать что-то, что будет возвращать правильные значения для каждой итерации / l oop ? Если это так, небольшая помощь будет высоко ценится. Если кто-нибудь знает лучший способ сделать это, пожалуйста, дайте мне знать. Будет ли лучше использовать VBA?

Ответы [ 2 ]

1 голос
/ 11 марта 2020

Не уверен, что это лучший подход, но он будет обрабатывать любое количество продуктов / появлений и создает соответствующие заголовки строки 3, а также временную таблицу нормализованных данных.

Option Explicit

Sub normalize()

    Const COL_TEXT = 3
    Const RE_PATTERN = "Product: ?([^,]+), Made.*?Date: ?([\d-]+)"

    ' use a regular expression for pattern matching
    Dim Regex As Object
    Set Regex = CreateObject("vbscript.regexp")

    With Regex
        .Global = True
        .MultiLine = True
        .IgnoreCase = True
        .Pattern = "(" & RE_PATTERN & ")"
    End With

    ' Us dictionary to count dates for each Product
    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")

    Dim wb As Workbook, ws As Worksheet, wsTmp As Worksheet, iTmp As Long
    Set wb = ThisWorkbook
    Set ws = wb.Sheets("Sheet1")

    ' create temp sheet to store table
    Set wsTmp = wb.Sheets.Add
    iTmp = 0

    ' scan sheet
    Dim iRow As Long, iLastRow As Long
    Dim sText As String, sProduct As String, sDate As String
    Dim matches As Object, match As Object, key As Variant
    Dim n As Long, r As Long, c As Long
    Dim iBlocks As Long, t0 as single
    t0 = Timer

    iLastRow = ws.Cells(Rows.count, COL_TEXT).End(xlUp).Row
    'Debug.Print iLastRow

    ' scan sheet with text
    For iRow = 4 To iLastRow
        sText = ws.Cells(iRow, COL_TEXT) ' text in  C
        'Debug.Print s

        ' extract product and date
        If Regex.test(sText) Then
            Set matches = Regex.Execute(sText)
            For Each match In matches

                sProduct = match.submatches(1)
                sDate = match.submatches(2)

                ' update dictionary
                If dict.exists(sProduct) Then
                    dict(sProduct) = dict(sProduct) + 1
                Else
                    dict.Add sProduct, 1
                End If

                ' store result temporarily
                iTmp = iTmp + 1
                wsTmp.Cells(iTmp, 1) = iRow
                wsTmp.Cells(iTmp, 2) = sProduct
                wsTmp.Cells(iTmp, 3) = dict(sProduct)
                wsTmp.Cells(iTmp, 4) = sDate
            Next
        End If

        ' increase no of blocks if required
        For Each key In dict.keys
           If dict(key) > iBlocks Then
               iBlocks = dict(key)
           End If
           dict(key) = 0
        Next
    Next

    ' create headings in row 3 for each block/product
    c = 5 ' start in E
    For n = 1 To iBlocks
       For Each key In dict.keys
          If n = 1 Then dict(key) = c ' reuse dict for column no
          ws.Cells(3, c) = key & " Loop" & n
          c = c + 1
       Next
    Next

    ' scan down temp result sheet
    For iRow = 1 To iTmp
        r = wsTmp.Cells(iRow, 1)
        sProduct = wsTmp.Cells(iRow, 2)
        n = wsTmp.Cells(iRow, 3)
        sDate = wsTmp.Cells(iRow, 4)

        ' fill in correct cell on original
        c = dict(sProduct) ' start column
        ws.Cells(r, c + (n - 1) * dict.count) = sDate
    Next
    wsTmp.Delete

    ' end
    ws.Activate
    ws.Cells(3, 3).Select
    MsgBox iTmp & " Product/Dates Extracted in " & int(Timer - t0) & " secs"

End Sub


0 голосов
/ 11 марта 2020

Я завершил формулу. Вот эта мерзость:

=IFERROR(MID(MID($C4,FIND("XXX",SUBSTITUTE($C4,LEFT(E$3,6),"XXX",RIGHT(E$3,1))),LEN($C4)-FIND(LEFT(E$3,6),$C4,1)),FIND("Date: ",MID($C4,FIND("XXX",SUBSTITUTE($C4,LEFT(E$3,6),"XXX",RIGHT(E$3,1))),LEN($C4)-FIND("XXX",SUBSTITUTE($C4,LEFT(E$3,6),"XXX",RIGHT(E$3,1)))),1)+6,10),"")

^ работает для таблицы, структурированной как таблица в первом посте

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...