22

次のような文字列を指定します。

a,"string, with",various,"values, and some",quoted

引用されたセクション内のコンマを無視しながら、コンマに基づいてこれを分割する良いアルゴリズムは何ですか?

出力は配列である必要があります。

[ "a", "string, with", "various", "values, and some", "quoted" ]

4

13 に答える 13

21

ここにいくつかの良い答えがあるようです。

独自の CSV ファイル解析を処理しようとしている人は、専門家からのアドバイスと独自の CSV パーサーをロールしないでくださいに注意してください。

あなたの最初の考えは、「引用符内のコンマを処理する必要がある」ということです。

あなたの次の考えは、「ああ、くそ、引用符内の引用符を処理する必要がある。エスケープされた引用符。二重引用符。単一引用符...」です。

それは狂気への道です。自分で書かないでください。すべての難しい部分に対応し、あなたのために地獄を経験した広範な単体テストをカバーするライブラリを見つけてください。.NET の場合は、無料のFileHelpersライブラリを使用します。

于 2008-08-08T19:36:34.093 に答える
6

パイソン:

import csv
reader = csv.reader(open("some.csv"))
for row in reader:
    print row
于 2008-08-08T21:07:28.450 に答える
2

もちろん、CSV パーサーを使用する方が優れていますが、楽しみのために次のことができます。

Loop on the string letter by letter.
    If current_letter == quote : 
        toggle inside_quote variable.
    Else if (current_letter ==comma and not inside_quote) : 
        push current_word into array and clear current_word.
    Else 
        append the current_letter to current_word
When the loop is done push the current_word into array 
于 2008-08-08T18:12:49.283 に答える
1

ここの著者は、問題が発生しているシナリオを処理する C# コードの塊をドロップしました。

.Net での CSV ファイルのインポート

翻訳するのはそれほど難しくないはずです。

于 2008-08-08T18:13:11.623 に答える
1

私の選択した言語が、考えずにこれを行う方法を提供しなかった場合、最初は簡単な方法として次の 2 つのオプションを検討します。

  1. 文字列内のコンマを事前解析して別の制御文字に置き換えてから分割し、その後、配列を事後解析して以前に使用した制御文字をコンマに置き換えます。

  2. または、コンマでそれらを分割し、結果の配列を別の配列に事後解析して、各配列エントリの先頭の引用符をチェックし、終了引用符に到達するまでエントリを連結します。

ただし、これらはハックであり、これが純粋な「頭の体操」である場合、役に立たないことが証明されると思います。これが現実の問題である場合は、具体的なアドバイスを提供できるように、言語を知っていると役立ちます。

于 2008-08-08T18:18:34.577 に答える
1

元の文字列に奇数の引用符が含まれている場合はどうなりますか?

これは、引用符で囲まれたフィールドの処理にいくつかの特殊性がある CSV 解析に奇妙に似ています。フィールドが二重引用符で区切られている場合にのみフィールドがエスケープされるため、次のようになります。

field1、"field2、field3"、field4、"field5、field6" field7

になる

フィールド1

フィールド2、フィールド3

フィールド4

"field5

フィールド6" フィールド7

開始と終了の両方が引用符で囲まれていない場合、それは引用符で囲まれたフィールドではなく、二重引用符は単に二重引用符として扱われることに注意してください。

私が正しく思い出せば、誰かがリンクした私のコードは、実際にはこれを正しく処理しません。

于 2008-08-08T22:21:53.510 に答える
1

以下は、Pat の疑似コードに基づく単純な python 実装です。

def splitIgnoringSingleQuote(string, split_char, remove_quotes=False):
    string_split = []
    current_word = ""
    inside_quote = False
    for letter in string:
      if letter == "'":
        if not remove_quotes:
           current_word += letter
        if inside_quote:
          inside_quote = False
        else:
          inside_quote = True
      elif letter == split_char and not inside_quote:
        string_split.append(current_word)
        current_word = ""
      else:
        current_word += letter
    string_split.append(current_word)
    return string_split
于 2010-10-05T05:43:24.533 に答える
0

これを使用して文字列を解析しますが、ここで役立つかどうかはわかりません。しかし、おそらくいくつかのマイナーな変更がありますか?

function getstringbetween($string, $start, $end){
    $string = " ".$string;
    $ini = strpos($string,$start);
    if ($ini == 0) return "";
    $ini += strlen($start);   
    $len = strpos($string,$end,$ini) - $ini;
    return substr($string,$ini,$len);
}

$fullstring = "this is my [tag]dog[/tag]";
$parsed = getstringbetween($fullstring, "[tag]", "[/tag]");

echo $parsed; // (result = dog) 

/mp

于 2008-08-08T18:36:07.460 に答える
0

簡単なアルゴリズムは次のとおりです。

  1. '"'文字列が文字で始まるかどうかを判別する
  2. 文字列を文字で区切られた配列に分割します'"'
  3. 引用符で囲まれたコンマをプレースホルダーでマークします#COMMA#
    • 入力が a で始まる場合'"'、インデックス % 2 == 0 の配列内の項目をマークします
    • それ以外の場合は、インデックス % 2 == 1 の配列内の項目をマークします。
  4. 配列内の項目を連結して、変更された入力文字列を形成します。
  5. 文字列を文字で区切られた配列に分割します','
  6. #COMMA#プレースホルダーの配列内のすべてのインスタンスを','文字に置き換えます。
  7. 配列は出力です。

Python の実装は次のとおりです:
('"a,b",c,"d,e,f,h","i,j,k"' を処理するように修正)

def parse_input(input):

    quote_mod = int(not input.startswith('"'))

    input = input.split('"')
    for item in input:
        if item == '':
            input.remove(item)
    for i in range(len(input)):
        if i % 2 == quoted_mod:
            input[i] = input[i].replace(",", "#COMMA#")

    input = "".join(input).split(",")
    for item in input:
        if item == '':
            input.remove(item)
    for i in range(len(input)):
        input[i] = input[i].replace("#COMMA#", ",")
    return input

# parse_input('a,"string, with",various,"values, and some",quoted')
#  -> ['a,string', ' with,various,values', ' and some,quoted']
# parse_input('"a,b",c,"d,e,f,h","i,j,k"')
#  -> ['a,b', 'c', 'd,e,f,h', 'i,j,k']
于 2008-08-08T18:40:40.617 に答える
0

これは、標準の CSV スタイルの解析です。多くの人がこれを正規表現で行おうとします。正規表現で約 90% に達することができますが、それを適切に行うには実際の CSV パーサーが本当に必要です。数か月前に CodeProject で高速で優れた C# CSV パーサーを見つけたので、強くお勧めします。

于 2008-08-08T18:52:50.030 に答える
0

これは、1回のパスでの疑似コード(別名Python)の1つです:-P

def parsecsv(instr):
    i = 0
    j = 0

    outstrs = []

    # i is fixed until a match occurs, then it advances
    # up to j. j inches forward each time through:

    while i < len(instr):

        if j < len(instr) and instr[j] == '"':
            # skip the opening quote...
            j += 1
            # then iterate until we find a closing quote.
            while instr[j] != '"':
                j += 1
                if j == len(instr):
                    raise Exception("Unmatched double quote at end of input.")

        if j == len(instr) or instr[j] == ',':
            s = instr[i:j]  # get the substring we've found
            s = s.strip()    # remove extra whitespace

            # remove surrounding quotes if they're there
            if len(s) > 2 and s[0] == '"' and s[-1] == '"':
                s = s[1:-1]

            # add it to the result
            outstrs.append(s)

            # skip over the comma, move i up (to where
            # j will be at the end of the iteration)
            i = j+1

        j = j+1

    return outstrs

def testcase(instr, expected):
    outstr = parsecsv(instr)
    print outstr
    assert expected == outstr

# Doesn't handle things like '1, 2, "a, b, c" d, 2' or
# escaped quotes, but those can be added pretty easily.

testcase('a, b, "1, 2, 3", c', ['a', 'b', '1, 2, 3', 'c'])
testcase('a,b,"1, 2, 3" , c', ['a', 'b', '1, 2, 3', 'c'])

# odd number of quotes gives a "unmatched quote" exception
#testcase('a,b,"1, 2, 3" , "c', ['a', 'b', '1, 2, 3', 'c'])
于 2008-08-08T19:15:34.463 に答える
0

Python ワンライナーで動作させることができるかどうかを確認するのに抵抗できませんでした。

arr = [i.replace("|", ",") for i in re.sub('"([^"]*)\,([^"]*)"',"\g<1>|\g<2>", str_to_test).split(",")]

['a', 'string, with', 'various', 'values, and some', 'quoted'] を返します

最初に引用符内の「,」を別のセパレーター (|) に置き換え、「,」で文字列を分割し、| を置き換えることで機能します。もう一度区切ります。

于 2008-08-08T19:51:25.200 に答える