Wie extrahiere ich nur die Zahlen, die sich in einem bestimmten Muster befinden, aus gemischtem Text in Excel?

1

Ich muss ein bestimmtes Zahlenmuster aus gemischtem Text in Excel extrahieren. Überlegungen:

  1. Die zu extrahierende Zahl hat immer das Muster 99.99.999.999
  2. Der String, in dem er enthalten ist, ist unterschiedlich lang, und die Position der zu extrahierenden Zahlen variiert ebenfalls.
  3. Am Anfang oder Ende der erforderlichen Zahlen befinden sich keine Zeichen, anhand derer sie extrahiert werden können

Beispiele:

01.11.202.037.2011_20171017150732.pdf  
01.26.304.012.09.re_20170621163250.pdf  
01.36.402.010 MAI 2011.pdf  
2011.mai.01.02.203.001_20170802112610.pdf  
lease_20161104110041.pdf  
re.01.02.203.001.2012_20171019085424.pdf  
16.20.116.014.14re_20170621161637.pdf  

Ergebnis sollte sein:

01.11.202.037  
01.26.304.012  
01.36.402.010  
01.02.203.001  
NA  
01.02.203.001  
16.20.116.014 
g_profile
quelle
2
Sie können diese Antwort verwenden, um sich selbst zu einer regulären Zellenfunktion zu machen: stackoverflow.com/a/43128681/1011724 , jetzt ist Ihre Frage nur, wie man Zahlen wie 99.99.999.999 in Regex und nach identifiziert Diese Seite du kannst es so machen \d{1,2}\.\d{1,2}\.\d{1,3}\.\d{1,3}
Dan
1
Das hat funktioniert, danke. Es gibt einige Fälle, die nicht funktionieren, z. Wenn das Präfix Zahlen und Punkte enthält, jedoch 9999. Beispiel: re.2009.18.31.300.016.pdf. Das Ergebnis sollte 18.31.300.016 sein, wird jedoch als 09.18.31.300 ausgegeben. Diese Instanzen sind jedoch viel zu selten. Insgesamt hat diese Lösung also funktioniert ...
g_profile
Sie könnten wahrscheinlich den regulären Ausdruck anpassen, um Muster auszuschließen, die mit 4 Ziffern beginnen
Dan

Antworten:

1

Hier ist etwas mit regulären Ausdrücken. Es funktioniert mit all Ihren Beispielen und prüft auch, ob das erste und das letzte Segment nicht mehr als zwei oder drei Ziffern haben:

Option Explicit
Function ExtractNumPattern(S As String) As String
    Dim RE As Object, MC As Object
    Const sPat As String = "(?:^|\D)(\d{2}\.\d{2}\.\d{3}\.\d{3})(?:\D|$)"

Set RE = CreateObject("vbscript.regexp")
With RE
    .Global = False
    .Pattern = sPat
    .MultiLine = True
    If .Test(S) = True Then
        Set MC = .Execute(S)
        ExtractNumPattern = MC(0).submatches(0)
    Else
        ExtractNumPattern = "NA"
    End If
End With
End Function

enter image description here

Das Regex-Muster sollte ziemlich klar sein, außer vielleicht für den Anfang und das Ende.

Der erste Teil (?:^|\D) Stellt sicher, dass dem Wert entweder eine Ziffer oder der Zeilenanfang vorangestellt wird.

Der letzte Teil (?:\D|$) Stellt sicher, dass dem Wert entweder eine Ziffer oder das Ende der Zeile folgt.

Ron Rosenfeld
quelle
Funktioniert perfekt für alle Fälle, danke.
g_profile
@g_profile Gern geschehen. Wenn dies die beste Antwort ist, können Sie sie bitte annehmen? Sehen Was soll ich tun, wenn jemand meine Frage beantwortet?
Ron Rosenfeld
1

Solch ein Overkill, warum gehst du immer zu VBA, würde ich einfach tun

=MID(A1,SEARCH("??.??.???.???",A1),13)

Ziehen Sie die Formel nach unten, oh ja, und fügen Sie eine Fehlerkorrektur für Werte ohne diese ein

=IFERROR(MID(A1,SEARCH("??.??.???.???",A1),13),"NA")

enter image description here

Luis Esparza LeedMx
quelle
1
Das Problem dabei ist, dass nicht überprüft wird, ob es sich nur um Ziffern handelt. Zum Beispiel. re.09.362.227.004.2015.pdf gibt das Ergebnis als re.09.362.227 an, wohingegen es NA sein sollte. In ähnlicher Weise wird auch die 9999-Komponente berücksichtigt, die jedoch nicht berücksichtigt werden sollte. Zum Beispiel. Re.13.09.33.005.2012.pdf gibt 09.33.005.201, während es NA sein sollte. Dies ist jedoch eine sehr einfache und unkomplizierte Lösung, die nur in NA-Situationen fehlschlägt.
g_profile
0

Wenn Sie eine ziemlich einfach zu verfolgende VBA-Funktion möchten,

Option Explicit

Sub TestIt()
  Dim c As Range
  For Each c In ActiveSheet.UsedRange
    Debug.Print c, ParsedAddr(c)
  Next c
End Sub

Function ParsedAddr(c As Range) As String
  Dim i As Long, iLen As Long

  iLen = Len(c)
  For i = 1 To iLen - 12
    If IsNumeric(Mid(c, i, 1)) Then                              '9
      If IsNumeric(Mid(c, i + 1, 1)) Then                        '99
        If Mid(c, i + 2, 1) = "." Then                           '99.
          If IsNumeric(Mid(c, i + 3, 1)) Then                    '99.9
            If IsNumeric(Mid(c, i + 4, 1)) Then                  '99.99
              If Mid(c, i + 5, 1) = "." Then                     '99.99.
                If IsNumeric(Mid(c, i + 6, 1)) Then              '99.99.9
                  If IsNumeric(Mid(c, i + 7, 1)) Then            '99.99.99
                    If IsNumeric(Mid(c, i + 8, 1)) Then          '99.99.999
                      If Mid(c, i + 9, 1) = "." Then             '99.99.999.
                        If IsNumeric(Mid(c, i + 10, 1)) Then     '99.99.999.9
                          If IsNumeric(Mid(c, i + 11, 1)) Then   '99.99.999.99
                            If IsNumeric(Mid(c, i + 12, 1)) Then '99.99.999.999
                              Exit For
                            End If
                          End If
                        End If
                      End If
                    End If
                  End If
                End If
              End If
            End If
          End If
        End If
      End If
    End If
  Next i
  If i < iLen - 11 Then
    ParsedAddr = Mid(c, i, 13)
  Else
    ParsedAddr = "NA"
  End If
End Function

Mit VBA können Sie in der Tat alles verschachteln, was Sie wollen. Sie können diesen Code mithilfe von Subroutinen massiv komprimieren - z. Suche nach Zeichen im Format "99". oder "999". - aber obwohl es nicht "eng" ist, ist es hübsch :) Ich lasse es nackt, also ist es extrem einfach zu folgen.

Ich habe dies als Funktion geschrieben, damit es angepasst werden kann, um geparste Zeichenfolgen in Zellen auszugeben.

MicrosoftShouldBeKickedInNuts
quelle
Das wurde herabgestimmt? "Ja wirklich?" DIESE Antwort hat ??? Total genial. Ah, Superuser - wo der Name des Spiels ist, alle anderen abzustimmen, weil der Downvoter "relativ" aufsteigt. Zumindest weiß ich, was mich während der Zombie-Apokalypse erwartet. Dank dieser Erschütterung meiner Perspektive sehe ich Sie jetzt kommen und bin bereit, anstatt davon auszugehen, dass alle daran sind, sich gegenseitig zu helfen. Vielen Dank für den Weckruf! Ich freue mich darauf, Ihnen während der Zombie-Apokalypse persönlich zu danken, Downvoter!
MicrosoftShouldBeKickedInNuts
0

Diese Frage hat mich wirklich beschäftigt, also habe ich beschlossen, es selbst zu versuchen. ich denke, dass Ron Rosenfeld Die Antwort von ist hübsch einfach und vielleicht ein bisschen elaganter; Überlegen Sie sich diese Methode also unbedingt zuerst.

Ich verwende die folgende Methodik :

  1. Verwandle die Schnur in ein einfaches Muster; Perioden gleich 0 s und alle anderen Zeichen sind gleich 1 s.
  2. Suchen Sie dann nach dem Muster, nach dem das OP fragt. ##. ##. ###. ### = 1101101110111
  3. Die Suche gibt den Startindex des Musters zurück - von diesem Index werden 13 Zahlen zurückgegeben.

Der zusätzliche Code dient wie üblich dazu, Fehler abzufangen, die Leistung zu verbessern (getestet mit 5.000 doppelten Datensätzen) und die Logik zu verbessern.

Unten sehen Sie ein Bild des xlsm-Layouts:

BILD-LINK

Bitte besuchen Sie diese Code Review Beitrag für eine genauere Analyse von Thomas Inzina und Zeiger von AJD , der dazu beigetragen hat, die Qualität des folgenden Codes zu verbessern.


Sub PatternScrub()

Dim Pattern As String
Dim x As Integer
Dim data As Variant
Dim Target As Range

With ThisWorkbook.Worksheets("Sheet1")
    Set Target = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With

data = Target.Value

    PerformanceBoost True

        For x = 1 To UBound(data)
            If data(x, 1) Like "*##.##.###.###*" Then
                data(x, 1) = getPatternValue(CStr(data(x, 1)))
            Else
                data(x, 1) = "NA"
            End If
        Next

        Target.Offset(0, 1).Value = data

    PerformanceBoost False

End Sub

Private Function Pattering(ByVal Target As String) As String

Dim i As Integer

    For i = 1 To Len(Target)
       Mid(Target, i, 1) = IIf(Mid(Target, i, 1) = ".", 0, 1)       'TURNS THE STRING INTO 1s AND 0s
    Next

Pattering = Target

End Function

Private Function PatternIndex(ByVal Pattern As String) As Integer

    On Error Resume Next
    PatternIndex = Application.WorksheetFunction.Search("1101101110111", Pattern)       ' MATCHES THE PATTERN AND RETURNS THE FIRST INDEX

End Function

Private Function getPatternValue(Text As String) As String

    Dim x As Long
    x = PatternIndex(Pattering(Text))
    getPatternValue = Mid(Text, x, 13)

End Function

Sub PerformanceBoost(TurnOn As Boolean)

    With Application
        .Calculation = IIf(Turn, xlCalculationManual, xlCalculationAutomatic)
        .ScreenUpdating = Not TurnOn
        .DisplayStatusBar = Not TurnOn
        .EnableEvents = Not TurnOn
    End With

End Sub
Nahuatl_C137
quelle