【问题标题】:Formula to eliminate all but alpha characters消除除字母字符以外的所有字符的公式
【发布时间】:2015-05-22 21:09:39
【问题描述】:

我需要在 Excel 中清理一列名称以消除所有非字母字符,包括句点、逗号、空格、连字符和撇号。

示例: 将O'Malley-Smith, Tom, Jr. 更改为OMALLEYSMITHTOMJR

客户端要求这是一个 Excel 函数,否则我会使用类似于replaceAll("[^a-zA-Z]", "").toUpperCase() 的快速 Java 程序来简化它。在一大堆 SUBSTITUTE 函数之外,我似乎找不到任何看起来像现成函数的东西来执行此操作 - 每个单元格似乎只有一个可用。

如果这是我需要的,我不太擅长开发自定义宏。

【问题讨论】:

    标签: excel excel-formula substitution excel-udf vba


    【解决方案1】:

    确实有很多 SUBSTITUTE,但在单个单元格中是可能的,例如:

    =UPPER(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1," ",""),",",""),"'",""),".",""),"-",""))   
    

    当然可能需要“扩展”以覆盖其他非字母字符。

    【讨论】:

    • 巧妙的公式化方法。
    • 你好,但公式不是我的菜。虽然我不认为巴里有任何同龄人,但他只是最好的接班人。
    • 删除有限的唯一非数字字符串的绝佳解决方案。当我不得不将“14D”、“8M”、“9hr”和“23min”等键转换为数值时,只需使用“D”、“M”、“hr”、“min”作为潜艇。
    • 消除少数字符的优秀解决方案。谢谢
    【解决方案2】:

    前段时间我也有类似的需求,发现了一些非常有用的东西。

    按 Alt+F11 打开 Visual Basic 编辑器。插入一个新模块并粘贴以下代码。

    Function CleanCode(Rng As Range)
        Dim strTemp As String
        Dim n As Long
    
        For n = 1 To Len(Rng)
            Select Case Asc(Mid(UCase(Rng), n, 1))
                Case 48 To 57, 65 To 90
                    strTemp = strTemp & Mid(UCase(Rng), n, 1)
            End Select
        Next
        CleanCode = strTemp
    End Function
    

    CleanCode 现在是新功能,您可以将其用作公式。

    所以在你想要操作的字符串旁边的单元格旁边复制=CleanCode(yourcell)

    【讨论】:

      【解决方案3】:

      如果您想走 VBA 路线 - 您不能使用用户定义函数 (UDF) 来更改您正在输入函数的单元格的值 - 但您可以使用一个简单的宏并采用Microsoft 的 VBScript RegEx 引擎的优势:

      Sub SO()
      
      Dim searchRange     As Excel.Range
      Dim cell            As Variant
      Dim RegEx           As Object
      
      Set RegEx = CreateObject("VBScript.RegExp")
      
      With RegEx
          .Pattern = "[^a-zA-Z]"
          .Global = True
          .MultiLine = True
      End With
      
      Set searchRange = ActiveSheet.Range("A1:D5") '// Change as required
      
          For Each cell In searchRange.Cells
              If RegEx.test(cell) Then cell.Value = RegEx.Replace(cell.Value, vbNullString)
              cell.Value = UCase(cell.Value)
          Next cell
      
      Set searchRange = Nothing
      Set RegEx = Nothing
      
      End Sub
      

      【讨论】:

      • 正则表达式是最有效的 VBA 方法。虽然会在变体数组而不是范围中使用它
      【解决方案4】:

      另一种 VBA 解决方案

      Sub RemoveCrap()
          Dim varRange As Range
          Dim varWorkRange As Range
      
          Set varWorkRange = Range("A1:A10")
      
          For Each varRange In varWorkRange
              varVal = ""
              For i = 1 To Len(varRange.Value)
                  varTemp = Mid(varRange.Value, i, 1)
                  If Not (varTemp Like "[a-z]" Or varTemp Like "[A-Z]") Then
                      varStr = ""
                  Else
                      varStr = UCase(varTemp)
                  End If
                  varVal = varVal & varStr
              Next i
              varRange.Value = varVal
          Next
      End Sub
      

      【讨论】:

      • @user3415869 - 这个概念会起作用,但代码不起作用,因为 Google Sheets 使用 Google Apps Script 而 MS Excel 使用 VBA
      【解决方案5】:

      这可以通过 Excel 2016 及更高版本中的单个公式来完成。

      虽然 pnuts 的解决方案列出了要去除的显式字符,但此解决方案列出了显式有效的字符。

      假设您的脏数据在 A 列中。 假设您想要 B 列中的干净数据。

      在单元格 B1 中使用下面最后一个公式。要将公式输入到单元格 B1,请执行以下操作:

      • 单击单元格 B1
      • 点击进入编辑栏
      • 粘贴公式
      • 按 CTRL+Shift+Enter

      根据需要复制单元格 B1 并将其粘贴到 B 列中。

      首先,这里有一个简短的例子来解释发生了什么:

      =TEXTJOIN("",TRUE,
      
      IFs(
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "t", "t",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "e", "e",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "s", "s",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "T", "T",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "E", "E",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "S", "S",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = "2", "2",
          MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1) = " ", " ",
          true, ""
        )
      
      )
      

      在这种情况下,我将以下字符指定为有效字符:t、e、s、T、E、S、2 和空格字符。

      显然,您需要将公式扩展到完整的字母表,分别列出每个大写和小写字符。同样,如果您想保留这些数字,请将其扩展为包括数字。请注意,数字被编码为字符串。

      这是如何工作的:

      简而言之,我们将源字符串拆分为一个单独的字符数组,然后对于每个字符,检查它是否在我们的有效字符集中,如果是则将其包含在结果中,否则将其替换为空如果不是,则为字符串。

      “IFS”函数一次通过一对参数。如果第一个参数的计算结果为真,则返回第二个参数。如果不是,它将继续下一对参数 - 这就是为什么您会看到每行列出两次字母的原因。 IFS 函数中的最后一对值是集合 'true' 和空字符串。这就是说,如果我们到达有效值集的末尾(即没有匹配有效值),则返回空字符串。

      更多关于为什么这样做的背景:

      这是ExcelJet 给出的解决方案的变体。在该解决方案中,TEXTJOIN 函数(用于连接数组的值)与 INDIRECT 函数(将字符串拆分为数组)以及数学运算符(加号)一起用于强制计算每个字符之间的计算在带有数值的字符串中。字符串中的数字字符将返回数值,而其他字符将返回错误。该解决方案使用函数 ISERR 检查错误以决定是否在最终输出中包含给定字符。那里有一篇类似的文章可以反过来解决 - 排除数字并保留字母。

      我想要解决的问题是让编码人员决定哪些值是有效的,哪些不是。我尝试将 VLOOKUP 和 INDEX 函数与 INDIRECT 函数合并,但它们仅适用于字符串中的第一个字符。诀窍在于,并非所有函数都会 INDIRECT 的输出以评估数组中的每个元素(即字符串中的每个字符)的方式。秘密在于 ExcelJet 使用了数学运算符。如果你查看微软完整的function reference,IFS 被归类为“逻辑”功能。我怀疑逻辑函数可以以这种方式与 INDIRECT 一起使用。

      (注意:我也尝试在各种组合中使用 AND 和 OR。但是,INDIRECT 评估字符串中的 所有 个字符。例如,使用 CODE 函数获取每个字符的 ASCII value 和断言所有字符必须具有 65 - 90(大写)或 97 - 122(小写字母)之间的值,仅当字符串中的 all 字符为大写或全部为小写时才有效,但如果有一种混合物。)

      我不知道这个解决方案的性能与之前使用 SUBSTITUTE 的建议相比如何。如果你只想去掉几个字符,我推荐 SUBSTITUTE 解决方案。如果您想明确指定要保留的有效字符(这是原始问题),请使用这个。

      最后,这是您需要的确切答案,包括您在问题中没有注意到但在您的示例中显示的大写转换。 (对于不希望进行大写转换的其他人,请从此示例中删除 'UPPER' 的实例,然后以小写形式再次将字母添加到列表中,并确保将 'true'/空字符串对保留为最后一个条目在列表中。)

      =TEXTJOIN("",TRUE,
      IFs(
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "A", "A",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "B", "B",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "C", "C",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "D", "D",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "E", "E",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "F", "F",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "G", "G",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "H", "H",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "I", "I",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "J", "J",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "K", "K",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "L", "L",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "M", "M",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "N", "N",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "O", "O",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "P", "P",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "Q", "Q",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "R", "R",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "S", "S",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "T", "T",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "U", "U",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "V", "V",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "W", "W",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "X", "X",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "Y", "Y",
          upper(MID(a1,ROW(INDIRECT(CONCATENATE("1:",LEN(a1)))),1)) = "Z", "Z",
          true, ""
      )
      )
      

      最初的问题是“消除除字母字符之外的所有字符” - 这个答案在公式中可以解决问题,而不需要 VBA。

      【讨论】:

        【解决方案6】:

        无法直接回复 aurezio,因为刚刚加入并且没有足够的声誉。我真的很喜欢这个解决方案,并且发现它非常有效且简短/简单,可以满足我的要求——即清理文本字段以将过滤的字符集输出到列以满足文件名和 Web 编码输出需求。

        虽然没有直接回答问题,但此页面是我找到的最接近我需要的解决方案的页面,因此我想为其他人提供更多背景信息,并扩展 aurezio 的解决方案以进行更通用的字符选择 - 以防万一有人感兴趣。

        第 7 行涉及允许的字符编号或数字系列。使用 excel 函数 CODE() 识别字符的代码,使用 CHAR() 将字符代码发布到。

        我的标准(如下所示)是过滤除 45(破折号)、48 到 57(数字系列)、65 到 90(字母数字大写系列)、97 到 122(字母数字小写系列)之外的所有内容。此外,不需要大写意味着可以删除 UCase()。

        'based off aurezio's solution
        Function CleanCode(Rng As Range)
            Dim strTemp As String
            Dim n As Long
        
            For n = 1 To Len(Rng)
                Select Case Asc(Mid(Rng, n, 1))
                    Case 45, 48 To 57, 65 To 90, 97 To 122
                        strTemp = strTemp & Mid(Rng, n, 1)
                End Select
            Next
            CleanCode = strTemp
        End Function
        

        最终我想对其进行改进以使其最终成为动态并允许所需过滤器的输入参数。 例如 ClearCode(Range,"45", "48-57", "65-90", "97-122")

        【讨论】:

          【解决方案7】:

          进一步了解上面的 youcantryreachingme 的答案,并使用 SEQUENCE 和 LET 函数(在最新版本的 Excel 中可用)将其与 https://exceljet.net/formula/strip-numeric-characters-from-cell 的建议合并,然后进一步试验,我已经能够将该函数降低到...

          =LET(character,MID(a1,SEQUENCE(LEN(a1)),1),TEXTJOIN("",TRUE,
           IFS(
               character=" "," ",
               CODE(UPPER(character))>90,"",
               CODE(UPPER(character))<65,"",
               TRUE,character)
           ))
          

          由于 IFS 似乎只执行匹配的第一个语句,因此在声明该范围之前放置要包含的任何超出排除范围 (>90、

          【讨论】:

            猜你喜欢
            • 2017-09-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-09-27
            • 1970-01-01
            相关资源
            最近更新 更多