CSVファイルを読み取り、値を配列に格納する


317

- *.csvファイルを読み込もうとしています。

*.csv-fileは、セミコロンで区切られた2つの列で構成します(「;」)。

*.csvStreamReaderを使用して-fileを読み取ることができ、Split()関数を使用して各行を区切ることができます。各列を個別の配列に格納してから表示したい。

それは可能ですか?


2
@Marc:残念ながら、英語以外のカルチャ(イタリア語など)では、ExcelをCSVに保存すると";"、セパレータとして使用されます...これにより、CSVが非標準の
imo

25
区切り文字としてコンマを使用していなくてもファイルをCSVで呼び出すため、私は常にCSVを文字区切り値として読み取ります。また、実際には引用符やエスケープルールが異なる方言が多数あるため、理論的にはRFCがあっても、実際に標準について話すことはできません。
CodesInChaos

1
CSVファイル拡張子名がDSVに変更されるようになりました- 区切り
文字

区切り文字で文字列を単に分割するすべての回答について、これは最善の方法ではありません。これがカバーしないCSVフォーマットにはさらに多くのルールがあります。サードパーティのパーサーを使用するのが最善です。詳細 -dotnetcoretutorials.com/2018/08/04/csv-parsing-in-net-core
iliketocode

回答:


415

あなたはこのようにそれを行うことができます:

using System.IO;

static void Main(string[] args)
{
    using(var reader = new StreamReader(@"C:\test.csv"))
    {
        List<string> listA = new List<string>();
        List<string> listB = new List<string>();
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var values = line.Split(';');

            listA.Add(values[0]);
            listB.Add(values[1]);
        }
    }
}

5
このためおかげで、私はcsvファイル内の行に分割する方法を忘れていたが、あなたのソリューションは、私を助け:)(ダム私を!)
Hallaghan

4
それから3年以上が経過し、この質問はまだ誰かを助けています。これが受け入れられなかったのは残念です。
AdamMc331 2014

12
コンマなどでフィールド値を処理しない
Mike

12
usingここでは節を使用する必要があります。または、リソースであるClose()ため、少なくとも手動で使用してください。readerIDisposible
Assaf Israel

30
これは、適切にCSVは次のように書かれて解析しませんcolumn1;"Special ; char in string";column3- tools.ietf.org/html/rfc4180
オレKを

173

私のお気に入りのCSVパーサーは、.NETライブラリに組み込まれているものです。これは、Microsoft.VisualBasic名前空間内の隠された宝物です。以下はサンプルコードです:

using Microsoft.VisualBasic.FileIO;

var path = @"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
 csvParser.CommentTokens = new string[] { "#" };
 csvParser.SetDelimiters(new string[] { "," });
 csvParser.HasFieldsEnclosedInQuotes = true;

 // Skip the row with the column names
 csvParser.ReadLine();

 while (!csvParser.EndOfData)
 {
  // Read current line fields, pointer moves to the next line.
  string[] fields = csvParser.ReadFields();
  string Name = fields[0];
  string Address = fields[1];
 }
}

への参照を追加することを忘れないでください Microsoft.VisualBasic

パーサーの詳細については、こちらをご覧ください:http : //codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html


6
私はこのオプションが一番好きです。クラスはCSVパーサーであり、手動で作成されたものではないため、エスケープ文字について心配する必要はありません。
ティモシーゴンザレス

22
誰かがこれに遭遇して不思議に思っている場合は、Microsoft.VisualBasicフレームワークアセンブリへの参照を含める必要があります。これは通常、デフォルトでは参照されないためです。
apokryfos

3
私がVB6の日からこれを覚えていたら、私は何年にもわたって多くの時間を節約できただろう。一部のユーザーはVBについて怒鳴っていますが、値がある場合、コードにdllと名前空間を追加しても問題はありません。これには多くの価値があります。
Walter

2
このソリューションはホームランです。私の経験から非常に信頼できるパーサー。
グレンフェリー

3
なぜVB dllだけなのですか?
Mark Choi

75

LINQの方法:

var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
          select (from piece in line
                  select piece);

^^間違った- ニック編集

元の回答者がcsv2次元配列(配列を含む配列)を入力しようとしたようです。最初の配列の各項目には、その行番号を表す配列が含まれ、ネストされた配列の各項目には、その特定の列のデータが含まれています。

var csv = from line in lines
          select (line.Split(',')).ToArray();

2
多分私は何かが足りないのですが、csv変数のポイントが何であるかわかりません-すでに行にあるのと同じデータ構造を再作成していませんか?
ベンヒューズ2013年

13
@ClayShannon .NET 1.1?ごめんなさい。
contactmatt

5
@contactmatt:私はあなたがその感情を乱用することはありません。
B.クレイシャノン

9
csvは引用できることも指摘したいので、string.Splitを使用することは現実的なオプションではありません。
Alxandr 2013

5
「System.Array」には「Split」の定義が含まれておらず、「System.Array」タイプの最初の引数を受け入れる拡張メソッド「Split」が見つかりません(usingディレクティブまたはアセンブリ参照がありません) ?)
Kala J

36

最初から行数を知る必要があるため、配列をすぐに作成することはできません(CSVファイルを2回読み取る必要があります)。

値を2つに格納List<T>してから使用するか、次を使用して配列に変換できます。List<T>.ToArray()

非常に簡単な例:

var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
    while (!rd.EndOfStream)
    {
        var splits = rd.ReadLine().Split(';');
        column1.Add(splits[0]);
        column2.Add(splits[1]);
    }
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
    Console.WriteLine(element);

// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
    Console.WriteLine(element);

NB

これは非常に単純な例にすぎないこと注意してください。を使用string.Splitしても、一部のレコードにセパレータ;が含まれている場合は考慮されません。
より安全なアプローチのために、nugetでCsvHelperのようなcsv固有のライブラリを使用することを検討してください。


;例のように、値の一部であるとは見なされません"value with ; inside it"。特殊文字を含むCSV値は、それがリテラル文字列であることを示すために二重引用符で囲みます。
ChickenFeet 2018

1
@ChickenFeet:確かに、それがキャプションの理由です:"Very simple example"。とにかく、それについてのメモを追加することができます;)
digEmAll

心配ありません。他の多くの回答もここでは考慮されていないことに気付きました:)
ChickenFeet

1
Regex.Split(sr.ReadLine()、 "、(?=(?:[^ \"] * \ "[^ \"] * \ ")* [^ \"] * $) "); //見つかりましたこのように...速く図書館より。
ピンチ

34

このライブラリに出くわした:https : //github.com/JoshClose/CsvHelper

非常に直感的で使いやすいです。nugetパッケージもあり、実装が簡単です:http ://nuget.org/packages/CsvHelper/1.17.0 。また、私が積極的に維持しているように見えます。

セミコロンを使用するように構成するのは簡単です:https : //github.com/JoshClose/CsvHelper/wiki/Custom-Configurations


3
これが一番の答えです!簡単にドロップして持ち運べる堅牢なライブラリ。
タイラーフォーサイス2014年

3
CsvHelperライブラリは素晴らしいです。超迅速で使いやすいです。
スティーブパリッシュ

3
引用符で囲まれた文字列を含むcsv形式のあらゆる側面を処理できるライブラリを探している場合は、これを使用してください。驚くばかり!
マット

Thx、本当に素晴らしいライブラリ、使いやすく、非常に堅牢です。
セバスティアン・ゲレロ

2
パフォーマンスはどのように比較されMicrosoft.VisualBasic.FileIO.TextFieldParserますか(@Habeebの回答を参照)?
bovender 2016年

33

私は通常、このパーサーをcodeprojectから使用します。これは、文字のエスケープやそれに似た文字エスケープがたくさんあるためです。


2
これはとても良くて速いです。あなたがビジネスの状況にいて、クラッキングを取得する必要がある場合は、これを使用してください。
gjvdkamp

8
このパーサーは、ダウンロードするCodeProjectに登録したくない場合に備えて、LumenWorks.Framework.IOとしてNugetギャラリーで入手できます。
グレッグマッコイ

30

ここに、トップ投票の回答の私のバリエーションがあります:

var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
          select line.Split(',').ToArray();

このcsv変数は、次の例のように使用できます。

int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
    .TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
    String zerothColumnValue = row[0]; // leftmost column
    var firstColumnValue = row[1];
}

csv変数の行と列にどのようにアクセスしますか?
マシューロック

1
エスケープコンマをどのように処理しますか?
Kuangwei Zhang

列内のコンマは処理しません。joshbの回答によると、堅牢なライブラリCsvHelperを使用する方が良い
Tim Partridge

11

(ヘッド)行や列をスキップする必要がある場合は、これを使用して2次元配列を作成できます。

    var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
    var csv = (from line in lines               
               select (from col in line
               select col).Skip(1).ToArray() // skip the first column
              ).Skip(2).ToArray(); // skip 2 headlines

これは、さらに処理する前にデータを形成する必要がある場合に非常に役立ちます(最初の2行が見出しで構成され、最初の列が行タイトルであると仮定します-配列に必要ないため、データを考慮したい)。

:次のコードを使用すると、見出しと1列目を簡単に取得できます。

    var coltitle = (from line in lines 
                    select line.Skip(1).ToArray() // skip 1st column
                   ).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
    var rowtitle = (from line in lines select line[0] // take 1st column
                   ).Skip(2).ToArray(); // skip 2 headlines

このコード例では、*.csvファイルの次の構造を想定しています。

CSVマトリックス

注:空の行をスキップする必要がある場合-便利な場合もありますが、

    where line.Any(a=>!string.IsNullOrWhiteSpace(a))

fromおよびselect内のステートメントLINQの上のコード例。


10

Microsoft.VisualBasic.FileIO.TextFieldParser dllをC#で使用してパフォーマンスを向上させることができます

上記の記事からコード例を取得

static void Main()
{
    string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";

    DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);

    Console.WriteLine("Rows count:" + csvData.Rows.Count);

    Console.ReadLine();
}


private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
    DataTable csvData = new DataTable();

    try
    {

    using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
        {
            csvReader.SetDelimiters(new string[] { "," });
            csvReader.HasFieldsEnclosedInQuotes = true;
            string[] colFields = csvReader.ReadFields();
            foreach (string column in colFields)
            {
                DataColumn datecolumn = new DataColumn(column);
                datecolumn.AllowDBNull = true;
                csvData.Columns.Add(datecolumn);
            }

            while (!csvReader.EndOfData)
            {
                string[] fieldData = csvReader.ReadFields();
                //Making empty value as null
                for (int i = 0; i < fieldData.Length; i++)
                {
                    if (fieldData[i] == "")
                    {
                        fieldData[i] = null;
                    }
                }
                csvData.Rows.Add(fieldData);
            }
        }
    }
    catch (Exception ex)
    {
    }
    return csvData;
}

9
SplitはTextFieldParserが行うすべてのことを行うわけではないため、効率的ではありません。たとえば、コメント行をスキップし、引用符で囲まれたフィールドを処理し、先頭/末尾の空白を削除します。厳密には1:1の比較ではありません。
ロバートマッキー

5

こんにちは、私はこれを行うための静的クラスを作成しました。+列チェック+クォータ記号の削除

public static class CSV
{
    public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
    }

    private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
    {
        string[] result = new string[0];
        List<string[]> lst = new List<string[]>();

        string line;
        int currentLineNumner = 0;
        int columnCount = 0;

        // Read the file and display it line by line.  
        using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
        {
            while ((line = file.ReadLine()) != null)
            {
                currentLineNumner++;
                string[] strAr = line.Split(csvDelimiter);
                // save column count of dirst line
                if (currentLineNumner == 1)
                {
                    columnCount = strAr.Count();
                }
                else
                {
                    //Check column count of every other lines
                    if (strAr.Count() != columnCount)
                    {
                        throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
                    }
                }

                if (removeQuoteSign) strAr = RemoveQouteSign(strAr);

                if (ignoreHeadline)
                {
                    if(currentLineNumner !=1) lst.Add(strAr);
                }
                else
                {
                    lst.Add(strAr);
                }
            }

        }

        return lst;
    }
    private static string[] RemoveQouteSign(string[] ar)
    {
        for (int i = 0;i< ar.Count() ; i++)
        {
            if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
            if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);

        }
        return ar;
    }

}

4
var firstColumn = new List<string>();
var lastColumn = new List<string>();

// your code for reading CSV file

foreach(var line in file)
{
    var array = line.Split(';');
    firstColumn.Add(array[0]);
    lastColumn.Add(array[1]);
}

var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();

ご協力いただきありがとうございます。それは私の問題を解決するのに役立つかもしれません。実際には、ファイルからデータを読み取り、データベースに挿入する必要があります。挿入時に主キー制約エラーが発生します(すでにデータベースにデータがあるため)。したがって、変数が既に存在するようにプログラムしてから、データを更新する必要があります。
Rushabh Shah

PKの場合、最初の値を想定します。データベースからIDでレコードを取得する必要があり、存在する場合はUPDATEステートメントを発行します。それ以外の場合は、新しいレコードを挿入します。
Jakub Konecki

3

以下は、データフィールドの1つにデータの一部としてセミコロン( ";")が含まれる特殊なケースです。この場合、上記のほとんどの回答は失敗します。

その場合の解決策

string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
    lstFields = new List<string>();
    field = "";
    for (int i = 0; i < csvRow.Length; i++)
    {
        string tmp = csvRow.ElementAt(i).ToString();
        if(String.Compare(tmp,"\"")==0)
        {
            quoteStarted = !quoteStarted;
        }
        if (String.Compare(tmp, ";") == 0 && !quoteStarted)
        {
            lstFields.Add(field);
            field = "";
        }
        else if (String.Compare(tmp, "\"") != 0)
        {
            field += tmp;
        }
    }
    if(!string.IsNullOrEmpty(field))
    {
        lstFields.Add(field);
        field = "";
    }
// This will hold values for each column for current row under processing
    fields = lstFields.ToArray(); 
}

2

オープンソースのAngara.Tableライブラリを使用すると、CSVを型付きの列にロードできるため、列から配列を取得できます。各列には、名前またはインデックスの両方でインデックスを付けることができます。http://predictionmachines.github.io/Angara.Table/saveload.htmlを参照してください。

ライブラリはCSVのRFC4180に準拠しています。型推論と複数行の文字列を有効にします。

例:

using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;

...

ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;

for(int i = 0; i < a.Length; i++)
{
    Console.WriteLine("{0}: {1}", i, a[i]);
}

タイプColumnを使用して、列タイプを表示できます。例:

Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);

ライブラリはF#に重点を置いているため、FSharp.Core 4.4アセンブリへの参照を追加する必要がある場合があります。プロジェクトの[参照の追加]をクリックし、[アセンブリ]-> [拡張機能]の下のFSharp.Core 4.4を選択します。


2

適切なライブラリを探すために数時間を費やしましたが、最後に独自のコードを書きました:)必要なツールを使用してファイル(またはデータベース)を読み取り、次のルーチンを各行に適用できます。

private static string[] SmartSplit(string line, char separator = ',')
{
    var inQuotes = false;
    var token = "";
    var lines = new List<string>();
    for (var i = 0; i < line.Length; i++) {
        var ch = line[i];
        if (inQuotes) // process string in quotes, 
        {
            if (ch == '"') {
                if (i<line.Length-1 && line[i + 1] == '"') {
                    i++;
                    token += '"';
                }
                else inQuotes = false;
            } else token += ch;
        } else {
            if (ch == '"') inQuotes = true;
            else if (ch == separator) {
                lines.Add(token);
                token = "";
                } else token += ch;
            }
    }
    lines.Add(token);
    return lines.ToArray();
}

1

私は何年もcsvreader.com(有料コンポーネント)を使用していますが、問題は一度もありません。それはしっかりしていて、小さくて速いですが、あなたはそれにお金を払わなければなりません。区切り文字は好きなように設定できます。

using (CsvReader reader = new CsvReader(s) {
    reader.Settings.Delimiter = ';';
    reader.ReadHeaders();  // if headers on a line by themselves.  Makes reader.Headers[] available
    while (reader.ReadRecord())
        ... use reader.Values[col_i] ...
}

1

私は修士論文を書いているだけの学生ですが、これは私がそれを解決した方法であり、私にとってはうまくいきました。まずディレクトリからファイルを選択し(csv形式のみ)、次にデータをリストに入れます。

List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
    try
    {
        dialog.Filter = "csv files (*.csv)|*.csv";
        dialog.Multiselect = false;
        dialog.InitialDirectory = ".";
        dialog.Title = "Select file (only in csv format)";
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
            int counter = 0;
            foreach (var line in fs)
            {
                counter++;
                if (counter > 2)    // Skip first two headder lines
                {
                    this.t.Add(float.Parse(line[0]));
                    this.SensorI.Add(float.Parse(line[1]));
                    this.SensorII.Add(float.Parse(line[2]));
                    this.SensorIII.Add(float.Parse(line[3]));
                }
            }
        }
    }
    catch (Exception exc)
    {
        MessageBox.Show(
            "Error while opening the file.\n" + exc.Message, 
            this.Text, 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Error
        );
    }
}

0

まだ間違っています。引用符内の ""を補正する必要があります。これが私の解決策であるMicrosoftスタイルのcsvです。

               /// <summary>
    /// Microsoft style csv file.  " is the quote character, "" is an escaped quote.
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="sepChar"></param>
    /// <param name="quoteChar"></param>
    /// <param name="escChar"></param>
    /// <returns></returns>
    public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
    {
        List<string[]> ret = new List<string[]>();

        string[] csvRows = System.IO.File.ReadAllLines(fileName);

        foreach (string csvRow in csvRows)
        {
            bool inQuotes = false;
            List<string> fields = new List<string>();
            string field = "";
            for (int i = 0; i < csvRow.Length; i++)
            {
                if (inQuotes)
                {
                    // Is it a "" inside quoted area? (escaped litteral quote)
                    if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
                    {
                        i++;
                        field += quoteChar;
                    }
                    else if(csvRow[i] == quoteChar)
                    {
                        inQuotes = false;
                    }
                    else
                    {
                        field += csvRow[i];
                    }
                }
                else // Not in quoted region
                {
                     if (csvRow[i] == quoteChar)
                    {
                        inQuotes = true;
                    }
                    if (csvRow[i] == sepChar)
                    {
                        fields.Add(field);
                        field = "";
                    }
                    else 
                    {
                        field += csvRow[i];
                    }
                }
            }
            if (!string.IsNullOrEmpty(field))
            {
                fields.Add(field);
                field = "";
            }
            ret.Add(fields.ToArray());
        }

        return ret;
    }
}

3
列の値内に改行がある場合は処理されません;)
Emil

0

私はあなたがまさに必要としているライブラリを持っています。

少し前に、CSVファイルを処理するための十分にシンプルで高速なライブラリを作成しました。次のリンクで見つけることができます:https : //github.com/ukushu/DataExporter

2次元配列と同様にCSVで動作します。まさにあなたが必要とするように。

例として、3行目のすべての値が必要な場合は、次のように記述するだけです。

Csv csv = new Csv();

csv.FileOpen("c:\\file1.csv");

var allValuesOf3rdRow = csv.Rows[2];

またはの第2セルを読む

var value = csv.Rows[2][1];

-1

これを見て

CsvFrameworkを使用します。

System.Collections.Generic;を使用します。

名前空間CvsParser {

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Order> Orders { get; set; }        
}

public class Order
{
    public int Id { get; set; }

    public int CustomerId { get; set; }
    public int Quantity { get; set; }

    public int Amount { get; set; }

    public List<OrderItem> OrderItems { get; set; }

}

public class Address
{
    public int Id { get; set; }
    public int CustomerId { get; set; }

    public string Name { get; set; }
}

public class OrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }

    public string ProductName { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        var customerLines = System.IO.File.ReadAllLines(@"Customers.csv");
        var orderLines = System.IO.File.ReadAllLines(@"Orders.csv");
        var orderItemLines = System.IO.File.ReadAllLines(@"OrderItemLines.csv");

        CsvFactory.Register<Customer>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.Name).Type(typeof(string)).Index(1);
            builder.AddNavigation(n => n.Orders).RelationKey<Order, int>(k => k.CustomerId);

        }, false, ',', customerLines);

        CsvFactory.Register<Order>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.CustomerId).Type(typeof(int)).Index(1);
            builder.Add(a => a.Quantity).Type(typeof(int)).Index(2);
            builder.Add(a => a.Amount).Type(typeof(int)).Index(3);
            builder.AddNavigation(n => n.OrderItems).RelationKey<OrderItem, int>(k => k.OrderId);

        }, true, ',', orderLines);


        CsvFactory.Register<OrderItem>(builder =>
        {
            builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
            builder.Add(a => a.OrderId).Type(typeof(int)).Index(1);
            builder.Add(a => a.ProductName).Type(typeof(string)).Index(2);


        }, false, ',', orderItemLines);



        var customers = CsvFactory.Parse<Customer>();


    }
}

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.