【问题标题】:How to extract text within a string of text如何提取文本字符串中的文本
【发布时间】:2011-10-28 12:19:45
【问题描述】:

我有一个简单的问题,我希望在不使用 VBA 的情况下解决它,但如果这是唯一可以解决的方法,那就这样吧。

我有一个包含多行(全部为一列)的文件。每行的数据如下所示:

1 7.82E-13 >gi|297848936|ref|XP_00| 4-氢氧化物 gi|297338191|gb|23343|randomrandom

2 5.09E-09 >gi|168010496|ref|xp_00| 2-丙酮酸

等等……

我想要的是某种方法来提取以“gi|”开头的数字字符串并以“|”结尾。对于某些行,这可能意味着多达 5 个 gi 数字,对于其他行,它只是一个。

我希望输出看起来像这样:

297848936,297338191

168010496

等等……

【问题讨论】:

    标签: excel vba excel-formula worksheet-function


    【解决方案1】:

    这是一个使用正则表达式对象的非常灵活的 VBA 答案。该函数所做的是提取它找到的每个子组匹配项(括号内的内容),用您想要的任何字符串分隔(默认为“,”)。您可以在此处找到有关正则表达式的信息:http://www.regular-expressions.info/

    假设第一个字符串在 A1 中,你可以这样称呼它:

    =RegexExtract(A1,"gi[|](\d+)[|]")
    

    因为这会寻找所有出现的“gi|”然后是一系列数字,然后是另一个“|”,对于您问题的第一行,这将为您提供以下结果:

    297848936, 297338191
    

    只需在列中运行它就可以了!

    Function RegexExtract(ByVal text As String, _
                          ByVal extract_what As String, _
                          Optional separator As String = ", ") As String
    
    Dim allMatches As Object
    Dim RE As Object
    Set RE = CreateObject("vbscript.regexp")
    Dim i As Long, j As Long
    Dim result As String
    
    RE.pattern = extract_what
    RE.Global = True
    Set allMatches = RE.Execute(text)
    
    For i = 0 To allMatches.count - 1
        For j = 0 To allMatches.Item(i).submatches.count - 1
            result = result & (separator & allMatches.Item(i).submatches.Item(j))
        Next
    Next
    
    If Len(result) <> 0 Then
        result = Right$(result, Len(result) - Len(separator))
    End If
    
    RegexExtract = result
    
    End Function
    

    【讨论】:

    • 天哪,这太美了。绝对棒极了。说真的,你为什么要这样做?这很有帮助,但我只是好奇为什么人们会花时间做这样的事情?你们都非常慈善。
    • 不客气!至于我为什么要花时间:我这样做是因为其他人这样做。我认为这更像是“向前支付”的事情。我帮助别人是因为有一天,他们会帮助我编写一些代码,而我帮助的人也会帮助别人等等。:)
    • 正则表达式是一个很好的方法。 +1 对于我自己,我回答问题是因为它很有趣,而且是学习/练习的好方法。另外,就像 Issun 所说,这些年来,我从新闻组和其他论坛中慷慨且非常有才华的人那里得到了惊人的帮助。
    • 看起来错字 Item(j) 应该是 Item(i) - 无法更正,因为它只有一个字母错误(对于编码网站来说有点愚蠢!)。 -- 通过正确拼写分隔符修复它。
    • 很棒的解决方案,优雅且运行良好,这应该是一个内置函数!我将在函数文档中添加指向此答案的链接
    【解决方案2】:

    在这里(假设数据在 A 列中)

    =VALUE(LEFT(RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2),
    FIND("|",RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2)) -1 ))
    

    不是最好的公式,但它可以提取数字。

    我刚刚注意到,因为每行有两个值,输出用逗号分隔。您将需要检查是否有第二个匹配、第三个匹配等,以使其适用于每个单元格的多个数字。

    参考您的确切示例(假设每个单元格最多 2 个值),以下代码将起作用:

    =IF(ISNUMBER(FIND("gi|",$A1,FIND("gi|", $A1)+1)),CONCATENATE(LEFT(RIGHT($A1,LEN($A1)
    - FIND("gi|",$A1) - 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ), 
    ", ",LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1) 
    - 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1) - 2)) 
    -1 )),LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2),
    FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ))
    

    丑的怎么样? VBA 解决方案可能更适合您,但我将把它留给您。

    要最多 5 个数字,请研究模式并在公式中手动递归。它会变长!

    【讨论】:

    • 哈哈,效果很好。谢谢你的帮助。你是对的,这会很快变得丑陋。也许我应该坚持使用VBA?我真的不介意我只是认为人们可能会发现 VBA 答案太麻烦了:P 老实说,我不确定我是否知道您包含的代码中发生了什么!我不确定我需要在哪里进行调整才能达到 5 或 7 个数字。
    • 如果您选择这种方法,最好使用 MID() 函数而不是 LEFT 和 RIGHT。这将使代码更具可读性。
    【解决方案3】:

    我可能首先使用将文本转换为列向导在| 分隔符上拆分数据。 在 Excel 2007 的 数据 选项卡上,数据工具 组,然后选择 Text to Columns。指定 Other:| 作为分隔符。

    从您发布的示例数据来看,在您执行此操作后,数字将全部位于同一列中,因此您可以删除不需要的列。

    【讨论】:

    • 其实我最初是这么想的,但我应该提一下,有时在 gb 列之后还有数字。因此,在我列出的示例字符串中,您还可以获得类似“randomrandomrandom gb|13151414|”的内容我刚刚更改了我的原始帖子以反映这一点。
    【解决方案4】:

    正如其他人介绍的没有 VBA 的解决方案...我将介绍一个确实使用的解决方案。现在,您是否愿意使用它。

    刚刚看到@Issun 提供了正则表达式的解决方案,非常好!无论哪种方式,都将为该问题提供一个“适度”的解决方案,仅使用“普通”VBA。

    Option Explicit
    Option Base 0
    
    Sub findGi()
    
        Dim oCell As Excel.Range
        Set oCell = Sheets(1).Range("A1")
    
        'Loops through every row until empty cell
        While Not oCell.Value = ""
    
            oCell.Offset(0, 1).Value2 = GetGi(oCell.Value)
            Set oCell = oCell.Offset(1, 0)
    
        Wend
    
    End Sub
    
    Private Function GetGi(ByVal sValue As String) As String
    
        Dim sResult As String
        Dim vArray As Variant
        Dim vItem As Variant
        Dim iCount As Integer
    
        vArray = Split(sValue, "|")
        iCount = 0
    
        'Loops through the array...
        For Each vItem In vArray
    
            'Searches for the 'Gi' factor...
            If vItem Like "*gi" And UBound(vArray) > iCount + 1 Then
    
                'Concatenates the results...
                sResult = sResult & vArray(iCount + 1) & ","
    
            End If
    
            iCount = iCount + 1
    
        Next vItem
    
        'And removes trail comma
        If Len(sResult) > 0 Then
    
            sResult = Left(sResult, Len(sResult) - 1)
    
        End If
    
        GetGi = sResult
    
    End Function
    

    【讨论】:

    • 啊哈哈,这也很棒。我看到 VBA 可以是一个非常顺利的方法,然后我没有意识到这一点。再次感谢您的帮助!
    猜你喜欢
    • 2021-03-29
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多