2011-08-16 11 views
14

Mam prosty problem, który mam nadzieję rozwiązać bez użycia VBA, ale jeśli jest to jedyny sposób, w jaki można go rozwiązać, niech tak będzie.Jak wyodrębnić tekst w ciągu tekstowym

Mam plik z wieloma wierszami (wszystkie kolumny). Każdy wiersz zawiera dane, które wyglądają mniej więcej tak:

1 7,82E-13> gi | 297848936 | ref | XP_00 | 4-wodorotlenek gi | 297338191 | gb | 23343 | randomrandom

2 5,09E-09> gi | 168010496 | ref | xp_00 | 2-pirogronian

etc ...

Co chcę jest jakiś sposób, aby wyodrębnić ciąg liczb, które zaczynają się od „GI |” i kończy się na "|". W przypadku niektórych wierszy może to oznaczać aż 5 gi liczb, dla innych będzie to po prostu jeden.

Co Mam nadzieję, wyjście będzie wyglądać będzie mniej więcej tak:

297848936,297338191

etc ...

Odpowiedz

31

Oto bardzo elastyczna odpowiedź VBA za pomocą obiektu regex. Funkcja ta wyodrębnia każdą znalezioną podgrupę (materiał wewnątrz nawiasu), oddzieloną dowolnym ciągiem znaków (domyślnie jest to ",").Można znaleźć informacje na temat wyrażeń regularnych tutaj: http://www.regular-expressions.info/

Można by nazwać tak, zakładając, że pierwszy ciąg jest w A1:

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

Ponieważ wygląda na wszystkich wystąpieniu z „GI |” po serii liczb, a następnie kolejny „|”, na pierwszej linii w swoim pytaniu, to nie daje to rezultatu:

297848936, 297338191 

Wystarczy uruchomić ten dół kolumny i masz wszystko gotowe!

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

Och człowiek, to jest piękne. Absolutnie fantastyczny. Poważnie, dlaczego to robisz? To bardzo pomocne, ale ciekawi mnie, dlaczego ludzie poświęcają swój czas na coś takiego? To wspaniale charytatywnie z was wszystkich. – Brandon

+15

Serdecznie witamy! Co do tego, dlaczego poświęcam czas: robię to, bo robią to inni ludzie. Myślę, że bardziej przypomina to "płacenie naprzód". Pomagam innym, bo któregoś dnia, pomogą mi z jakimś kodem, a ludzie, którym pomogę, pomogą innym itd. :) – aevanko

+2

Regex to świetny sposób na sukces. +1 Dla siebie, odpowiadam na pytania, ponieważ jest to dobra zabawa i świetny sposób na naukę/ćwiczenie. Poza tym, jak mówi Issun, od lat otrzymuję niesamowitą pomoc od hojnych i bardzo utalentowanych osób w grupach dyskusyjnych i na innych forach. –

5

tutaj jest (zakładając, że dane są w kolumna A)

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

Nie najładniejsza formuła, b ut będzie działać, aby wyodrębnić liczbę.

Właśnie zauważyłem, ponieważ masz dwie wartości na wiersz z wynikiem oddzielonym przecinkami. Musisz sprawdzić, czy istnieje drugi mecz, trzeci mecz itp., Aby działał on pod wieloma numerami na komórkę.

w odniesieniu do dokładnej próbki (zakładając, 2 wartości maksymalnie na komórkę) Poniższy kod będzie działać:

=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)) 

Jak to na brzydkie? Rozwiązanie VBA może być dla ciebie lepsze, ale zostawię to tutaj dla ciebie.

Aby przejść do 5 liczb, dobrze zbadaj wzór i ręcznie powtarzaj w formule. IT będzie długo!

+0

Haha, który działał cudownie. Dzięki za pomoc. Masz rację, to stanie się brzydkie szybko. Może powinienem więc trzymać się VBA? Nie przeszkadza mi to, że myślałam, że ludzie mogą uznać odpowiedzi VBA za zbyt kłopotliwe: P Szczerze mówiąc, nie jestem pewien, czy mam jakiekolwiek pojęcie o tym, co się dzieje w tym kodzie, który zawierasz! Nie jestem pewien, gdzie będę musiał dokonać poprawek, aby liczba ta wzrosła do 5 lub 7. – Brandon

+0

Jeśli wybierzesz to podejście, lepiej korzystaj z funkcji MID() zamiast LEWEGO i PRAWEGO. To sprawiłoby, że kod byłby bardziej czytelny. –

2

Najprawdopodobniej najpierw podzielę dane na ograniczniku | za pomocą kreatora konwersji tekstu na kolumny. W programie Excel 2007 znajdującym się w grupie Data, a następnie wybierz opcję Tekst do kolumn. Podaj Pozostałe: i | jako ogranicznik.

Z przykładowych danych, które wysłałeś, wygląda na to, że po wykonaniu tego wszystkie liczby będą znajdować się w tych samych kolumnach, więc możesz po prostu usunąć kolumny, których nie chcesz.

+0

Właściwie to początkowo pomyślałem, ale powinienem wspomnieć, że są chwile, w których po kolumnie gb znajdują się również liczby. Więc w tym łańcuchu przykładowym, który wymieniłem, możesz również uzyskać coś takiego jak "randomrandomrandom gb | 13151414 |" Właśnie zmieniłem mój pierwotny post, aby to odzwierciedlić. – Brandon

2

Jako, że inni faceci zaprezentowali rozwiązanie bez VBA ... Przedstawię ten, który go używa. Teraz jest twój telefon, aby go użyć lub nie.

Właśnie zobaczyłem, że @Issun przedstawił rozwiązanie z regex, bardzo ładne! Tak czy inaczej, przedstawi "skromne" rozwiązanie pytania, używając tylko "zwykłego" 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

Ah hah to także świetny. Widzę, że VBA może być naprawdę gładkim podejściem do tego, nie zdawałem sobie z tego sprawy. Jeszcze raz dziękuję za pomoc! – Brandon

Powiązane problemy