2011-08-16 70 views
14

我有一個簡單的問題,我希望在不使用VBA的情況下解決問題,但如果這是解決問題的唯一方法,那就這樣吧。如何提取文本字符串中的文本

我有一個文件有多行(全部一列)。每行的數據看起來像這樣:

1 7.82E-13> gi | 297848936 | ref | XP_00 | 4-hydroxide gi | 297338191 | gb | 23343 | randomrandom

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

等等

我想一些方法來提取開頭串號「GI |」並以「|」結尾。對於某些行,這可能意味着多達5個gi數字,對於其他行,它只會是一個。

什麼我希望輸出看起來像會是這樣的:

297848936,297338191

等等

回答

31

這是一個非常靈活的使用正則表達式對象的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 
+4

哦,這個人很漂亮。絕對神話般。 說真的,你爲什麼這樣做?這非常有幫助,但我只是很好奇爲什麼人們會爲此付出時間?這對你們來說都是非常慈善的。 – Brandon

+15

非常歡迎!至於我爲什麼花時間:我這樣做是因爲其他人這樣做。我認爲這更像是「付出前進」的東西。我有一天幫助別人,他們會幫助我一些代碼,我幫助的人會幫助別人,等等。:) – aevanko

+2

正則表達式是一個很好的方式。 +1對於我自己,我回答問題是因爲它很有趣,是一種學習/練習的好方法。此外,像Issun說的,多年來,我在新聞組和其他論壇中從慷慨和非常有才華的人那裏獲得了驚人的幫助。 –

5

這是(假設數據是在列A)

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

不是最好的公式,b它將會提取數字。

我剛剛注意到,因爲每行有兩個值,輸出之間用逗號隔開。您將需要檢查是否有第二次比賽,第三次比賽等,使其工作在每個單元多個數字。

關於你確切的樣品(假設每單元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個數字,好,學習模式和手動遞歸公式中。 IT會變長!

+0

哈哈,做了奇妙的工作。謝謝你的幫助。你說得對,這會變得很難看。也許我應該堅持使用VBA呢?我並不介意我只是認爲人們可能會發現VBA的答案太麻煩:P說實話,我不確定我是否有任何線索,包括你所包含的代碼中發生了什麼。我不確定我需要做些什麼調整才能達到5或7個數字。 – Brandon

+0

如果您選擇此方法,最好使用MID()函數而不是LEFT和RIGHT。這將使代碼更具可讀性。 –

2

我可能會首先在|分隔符上使用convert text to columns嚮導分割數據。 在Excel 2007中是數據選項卡,數據工具組然後選擇文本到列。指定其他:|作爲分隔符。

從您發佈的樣本數據看起來像這樣做後數字將全部在相同的列中,因此您可以刪除不想要的列。

+0

我其實原本是這麼想的,但我應該提到有時候在gb欄之後還有數字。所以在我列出的那個例子中,你也可以得到類似「randomrandomrandom gb | 13151414 |」 我只是改變了我原來的帖子,以反映這一點。 – Brandon

2

由於其他人提出的解決方案沒有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 
+0

中添加一個鏈接到這個答案啊哈這也是一個很好的答案。我看到VBA可以成爲一種非常流暢的方法,但我沒有意識到這一點。再次感謝你的幫助! – Brandon