web-dev-qa-db-ja.com

テキストの文字列内のテキストを抽出する方法

VBAを使用せずに解決したい単純な問題がありますが、それが解決できる唯一の方法である場合は、そうしてください。

複数行(すべて1列)のファイルがあります。各行には、次のようなデータがあります。

1 7.82E-13> gi | 297848936 | ref | XP_00 | 4-水酸化GI | 297338191 | GB | 23343 |ランダムランダム

2 5.09E-09> gi | 168010496 | ref | xp_00 | 2-ピルビン酸塩

等...

「gi |」で始まる数字の文字列を抽出する方法が欲しい「|」で終了します。一部の行では、これは5桁もの数字を意味する場合がありますが、他の行では1つだけになります。

出力が次のようになることを望みます:

297848936,297338191

168010496

等...

16
Brandon

これは、regexオブジェクトを使用した非常に柔軟な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
46
aevanko

ここにあります(データが列Aにあると想定)

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

最も良い式ではありませんが、数値を抽出するのに役立ちます。

カンマで区切られた出力を持つ行ごとに2つの値があるため、私はちょうど気づきました。セルごとに複数の数値で機能するようにするには、2番目の一致、3番目の一致などがあるかどうかを確認する必要があります。

正確なサンプルを参照して(セルごとに最大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は長くなります!

6
Zelgada

テキストを列に変換ウィザードを使用して、最初に|区切り文字でデータを分割します。 Dataタブ、Data ToolsグループにあるExcel 2007では、次にText to Columnsを選択します。区切り文字としてその他:および|を指定します。

投稿したサンプルデータから、これを実行すると、すべての列が同じ列になるため、不要な列を削除できます。

2
Jason S

他の人たちが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
2
Tiago Cardoso