【问题标题】:Separate words from numbers using VBA使用 VBA 将单词与数字分开
【发布时间】:2020-06-23 08:24:34
【问题描述】:

我有一个需要清理的地址列表。

目标是在数字前添加一个空格,如下例所示。

16AVCHARLESDAGAULLECS10525             16 Avcharlesdagaullecs 10525
1BDHIPPOLYTEMARQUES                    1 Bdhippolytemarques
20GARRICKSTREET4THFLOOR                20 Garrickstreet 4Thfloor
2109ZAC                                2109 Zac
2-4VANDRIESSTREET4                     2-4 Vandriesstreet 4
5:ETVÄRG.19.E                          5:Etvärg. 19.E
901ACEHIGHENTTOWE9TH233                901 Acehighenttowe 9Th 233

我找到了一个在字母之间放置空格的脚本,但这不是我的目标。这是我到目前为止的代码。 它没有给出上面的结果。

Function Add_Spaces(ByVal sText As String) As String
   Dim CharNum As Long
   Dim FixedText As String
   Dim CharCode As Long

   FixedText = Left(sText, 1)

   For CharNum = 2 To Len(sText)
      CharCode = Asc(Mid(sText, CharNum, 1))
      If CharCode >= 65 And CharCode <= 90 Then
         FixedText = FixedText & " " & Mid(sText, CharNum, 1) 'This needs to be rewritten
      Else
         FixedText = FixedText & Mid(sText, CharNum, 1)
      End If
   Next CharNum

   Add_Spaces = FixedText
End Function

你知道我该如何解决这个问题吗?

这里是一个正则表达式的解决方案,可能会提供线索:R separate words from numbers in string

【问题讨论】:

  • 啊,当街道名称中有数字时,这会变得特别有趣,例如 main 42nd street :)
  • ^^ 即使使用Ä 强调的大写字符也可能对下面的某些答案(取决于它们的位置)造成麻烦=)
  • 你能解释一下为什么不在5 :ETVÄRG. 19 .E后面加空格。是否还有其他例外,例如` : `?
  • 您能否解释一下为什么在示例#3 4THFLOOR 中的TH 之后没有添加空格?

标签: excel vba data-cleaning


【解决方案1】:

这似乎适用于您的所有示例:

正则表达式在从数字到字母的变化时分裂,反之亦然,并且对TH.也有例外

这些异常可能会导致其他数据出现问题,但似乎适用于您提供的数据。您的可变性是否会成为一个问题尚不清楚。

请注意,我对 Regex 使用了早期绑定(工具/参考设置为包括 Microsoft VBScript 正则表达式 5.5),但如果您要分发此代码,则可以将其更改为后期绑定。

编辑: 请注意,我没有将其转换为正确的大小写,但如果确实需要,可以这样做

`Set Reference to Microsoft VBScript Regular Expressions 5.5
Option Explicit
Function replacer(s As String) As String
    Dim RE As RegExp
    Const sPat As String = "(\dTH|\d)(?!TH)(?=[A-Z])|([A-Z.])(?=\d)"
    Const sRepl As String = "$1$2 "
    Dim sTemp As String
Set RE = New RegExp
With RE
    .Global = True
    .Pattern = sPat
    .IgnoreCase = True
    replacer = .Replace(s, sRepl)
End With

End Function

公式是,例如:

A2: =replacer(A2)

如果需要PROPER 大小写,则将公式更改为:

A2: =PROPER(replacer(A2))

这似乎比 VBA StrConv 函数更适用于您在美国的数据。

【讨论】:

  • 很难想出一个无懈可击的正则表达式。如果你有一个类似25THEODORESTREET4 的街道名称怎么办。或5:ETVÄRGÄ19.E。您正确地提到它适用于提供的数据,但有些事情告诉我这可能会缩短一点。尽管如此,还是不​​错的努力 =)
  • @JvdV 对此毫无疑问。但这可能足以将列表筛选为人工干预可以完成的事情。
  • A-ZÀ-Ý 可能会稍微改进一下。
  • @CLR 我同意。但我会等待 OP 的反馈,看看我们所拥有的是否足够好。可能还应该进行其他调整。如果以下内容以字母开头,我看到 OP 已接受不将 TH 与以下内容分开的答案。虽然这是他在他的例子中表明他想要的。
【解决方案2】:

尝试对以下模式使用两个正则表达式替换:

([A-Za-z])([0-9])
([0-9])([A-Za-z])

并替换为$1 $2:

Dim Regex As System.Text.RegularExpressions.Regex
Dim input As String = "16AVCHARLESDAGAULLECS10525"
Dim output As String = Regex.Replace(input, "([A-Za-z])([0-9])", "$1 $2")
output = Regex.Replace(output, "([0-9])([A-Za-z])", "$1 $2")
Console.WriteLine(output)

打印出来:

16 AVCHARLESDAGAULLECS 10525

这里的策略是在单独的捕获组中匹配每两个边界字符。这里的边界是一个数字后跟一个字母,反之亦然。然后,我们用这两个捕获的字符替换,在它们之间插入一个空格。

【讨论】:

  • @RonRosenfeld 太晚了,我已经用另一种方式修复了,但你的建议可能是最好的。
  • @Ron 不,带连字符的街道名称似乎被视为一个单词。
【解决方案3】:

毫无疑问,Regex 是一种更简洁的方式 - 但如果您想更改现有代码以达到预期的结果,我认为这可能有效:

Function Add_Spaces(ByVal sText As String) As String
    Dim CharNum As Long
    Dim FixedText As String
    Dim CharCode As Long
    Dim lastCharCode As Long

    FixedText = Left(sText, 1)

    For CharNum = 2 To Len(sText)
        CharCode = Asc(Mid(sText, CharNum, 1))
        lastCharCode = Asc(Mid(sText, CharNum - 1, 1))
         If (CharCode >= 65) <> (lastCharCode >= 65) Then
            FixedText = FixedText & " " & Mid(sText, CharNum, 1) 'This needs to be rewritten
        Else
            FixedText = FixedText & Mid(sText, CharNum, 1)
        End If
    Next CharNum

    Add_Spaces = Application.WorksheetFunction.Proper(FixedText)

End Function

【讨论】:

    【解决方案4】:

    此功能也适用于所有示例。它还避免在数字后面有'TH'的情况下分裂:

    Private Function SeparateNumbersFromString(x As String) As String
      Dim i As Long, j As Long, strInt As String, strFin As String
    
       For i = 1 To Len(x)
            strInt = ""
            If IsNumeric(Mid(x, i, 1)) Then
                For j = i To Len(x)
                    strInt = strInt & Mid(x, j, 1)
                    If Not IsNumeric(strInt) Or (Right(strInt, 1) = "-" And _
                                IsNumeric(left(strInt, Len(strInt) - 1))) Or _
                                (Right(strInt, 1) = "." And _
                                   IsNumeric(left(strInt, Len(strInt) - 1))) Then
                        strFin = IIf(strFin = "", strFin, strFin & " ") & _
                                      left(strInt, Len(strInt) - 1) & _
                                       IIf(UCase(Mid(x, j, 2)) = "TH", "", " ")
                        strInt = ""
                        i = j - 1
                        Exit For
                    End If
                    If j >= Len(x) Then strFin = strFin & " " & strInt: GoTo Ending
                Next j
            Else
                strFin = strFin & Mid(x, i, 1)
            End If
       Next i
    Ending:
       SeparateNumbersFromString = strFin
    End Function
    

    【讨论】:

    • 这解决了我的问题!我在 excel 中添加了一些公式,以删除以数字开头的数据中生成的多余空格,并删除 - 之前和之后创建的空格。 =SUBSTITUTE(CLEAN(TRIM(PROPER(SeparateNumbersFromString(DATA))));" - ";"-")
    • @Åsa:很高兴我能帮到你!我开始编写上述功能,但我不得不离开我的办公室。当我回来时,我已经找到了三个答案,我不知道发布另一个答案是否会对某人有所帮助。但是,因为它几乎准备好了......
    【解决方案5】:

    考虑:

    Public Function OutString(Instring As String) As String
        Dim L As Long, i As Long, CH As String
    
        L = Len(Instring)
        OutString = Left(Instring, 1)
    
        For i = 2 To L
            CH = Mid(Instring, i, 1)
            If CH Like "[0-9]" And Not Right(OutString, 1) Like "[0-9]" Then
                OutString = OutString & " " & CH
            Else
                OutString = OutString & CH
            End If
        Next i
    End Function
    

    代码类似于用指针沿着字符串爬行。如果指针右边的字符是数字,而指针左边的字符不是数字,则插入一个空格。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-21
      • 2019-03-09
      • 1970-01-01
      • 1970-01-01
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多