テキスト ファイルを変換して辞書を提供する C#

okwaves2024-01-25  10

私の問題に対する最善の解決策は何ですか?次のようなテキスト ファイルを開きたいとします。

[1 (100, 100, name)]
[2 (200, 200, name)]
[3 (300, 300, name)]

このテキスト ファイルを使用して、Dictionary<int, Tuple<double, double, string>> に提供したいと考えています。

私が試したこと:

Dictionary<int, Tuple<double, double, string>> text_to_dictionary = new Dictionary<int, Tuple<double, double, string>>();
    
    foreach(var item TextFileToSupplyDictionary())
    {
     text_to_dictionary.add(item)
    }
    
    public Dictionary<int, Tuple<double, double, string>>  TextFileToSupplyDictionary()
            {
                var res = File
                    .ReadLines("textFile")
                    .Select(line => line.Split(','))
                    .GroupBy(item => Convert.ToInt32(item[0]))
                    .ToDictionary(groupValues => groupValues.Key, groupValues => groupValues.ToDictionary(item => Convert.ToDouble(item[1]), item => Convert.ToDouble(item[2])));
    
                return res;
            }

これをどこに行こうとしているのか本当にわかりませんでした...

また、次のエラーがあります。

テキスト ファイルの形式を制御できますか?それとも、「これが得られるものです、それに対処しましょう」でしょうか?

– フィルドール

2020 年 9 月 3 日 11:48

foreach に in キーワードがありません

– エドゥアルド・コルトリ

2020 年 9 月 3 日 11:49

辞書内の値は他の辞書ではなくタプルである必要があります。これがエラーが発生する理由です。

– モン・ジュウ

2020 年 9 月 3 日 11:50

2

^^ dotnetfiddle.net/hIe4iv

– フィルドール

2020 年 9 月 3 日 12:11

2

@Fildor いいですね、回答者として投稿してください :)

– モン・ジュウ

2020 年 9 月 3 日 12:12



------------------------

1 つの方法は、他のチャンネルを削除するか分割することです。文字列内の不要な文字を削除し、最初の項目をキーとして選択し、他の項目から作成されたタプルを値として選択します。

var dictionary = File
    .ReadLines("textFile")
    .Select(line => line.Split(new[] {'[', '(', ',', ')', ']'},
        StringSplitOptions.RemoveEmptyEntries))
    .ToDictionary(x => int.Parse(x[0]),
        x => new Tuple<double, double, string>(
            double.Parse(x[1]), double.Parse(x[2]), x[3].Trim()));

6

これで助かる! :)

– レッドビーフ

2020 年 9 月 3 日 12:32

お役に立ててうれしいです。 int.Parse と double.Parse を盲目的に使用していることに注意してください。ファイルのこれらの部分を適切な型に解析できない場合は、例外をスローします。各行に検証を追加することでより安全にすることができますが、内容が適切に形成されている場合は、そのままで機能するはずです。

– ルーファス L

2020 年 9 月 3 日 12:34

@Rufus、クエリが 1 つあります。「名前」を指定した場合、これは機能しますか?つまり、テキスト ファイルには ( 、 、 [ など?] のような文字が含まれています。

– ヴィカス・ガーグ

2020 年 9 月 3 日 12:52

いいえ、それはこれも壊れてしまいます。それは有効なシナリオですか?

– ルーファス L

2020 年 9 月 3 日 12:54

はい、壊れます。@redbeef、「名前」は壊れると思いますか?これらの文字を含むデータが存在することはありませんか?いいえの場合は、私が提供した正規表現ソリューションを使用することをお勧めします。何か見逃した場合はお知らせください。

– ヴィカス・ガーグ

9月2020 年 3 月 13:00



------------------------

通常、私は正規表現を最後に提案するところですが、ここでは...

免責事項: Regex を使用する場合は、過剰なテスト (パフォーマンス、負荷、メモリなど) を実行してください。

これは最初のアプローチです:

using System;
using System.Text.RegularExpressions;
                    
public class Program
{
    public static void Main()
    {
        string dummyfile = "[1 (100, 100, name)]\n[2 (200, 200, name)]\n[3 (300, 300, name)]\n";
        
        var regex = new Regex(@"^\[(?<index>\d*)\s+\((?<num1>\d+),\s+(?<num2>\d+),\s+(?<name>.+)\)\]$", RegexOptions.Multiline );
        
        MatchCollection matches = regex.Matches(dummyfile);
        
        Console.WriteLine("Matches: {0}", matches.Count);
        foreach( Match match in matches )
        {
            Console.WriteLine("Found {0}: {1} | {2} | {3}", match.Groups["index"], match.Groups["num1"], match.Groups["num2"], match.Groups["name"]);
        }
    }
}

dotnetfiddle で実行されたもの: https://dotnetfiddle.net/Jbob0S

特定の状況に合わせた例:

using System;
using System.Linq;
using System.Text.RegularExpressions;
                    
public class Program
{
    public static void Main()
    {
        string dummyfile = "[1 (100, 100, name)]\n[2 (200, 200, name)]\n[3 (300, 300, name)]\n";
        var regex = new Regex(@"\[(?<index>\d*)\s+\((?<num1>\d+),\s+(?<num2>\d+),\s+(?<name>.+)\)\]" );
        
        var result = dummyfile.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select( l => DoTheMatch( l, regex )).ToList();
    
        foreach( var item in result )
        {
            Console.WriteLine("Found {0}: {1} | {2} | {3}", item.Index, item.Num1, item.Num2, item.Name);
        }
    }
    
    public static Data DoTheMatch( string line, Regex regex )
    {
        Match match = regex.Match(line);
        if( match.Success )
        {
            return new Data(){Index = int.Parse(match.Groups["index"].Value), Num1 = int.Parse(match.Groups["num1"].Value), Num2 = int.Parse(match.Groups["num2"].Value), Name= match.Groups["name"].Value};
        }
        throw new Exception( string.Format("Invalid line '{0}'", line) );
    }
}

public class Data
{
    public int Index {get; set;}
    public int Num1 {get; set;}
    public int Num2 {get; set;}
    public string Name {get; set;}
}

https://dotnetfiddle.net/z8BLEM を参照してください



------------------------

私の理解に基づくと、以下の解決策は正規表現で機能します。 "name" の場合、String.Split は失敗します。テキスト ファイルには "[",",","(" などの文字が含まれています。何か見逃した場合はお知らせください。

static void Main(string[] args)
    {
        var regex = new Regex(@"^\[(?<DicIndex>\d*)\s+\((?<FirstNumber>\d+),\s+(?<SecondNumber>\d+),\s+(?<name>.+)\)\]$", RegexOptions.Multiline);

        var res = File
          .ReadLines(@"C:\TEST\Dictionary.txt")
          .Select(item => regex.Matches(item))
          .Select(a => new { key = a[0].Groups[1].Value, value = new Tuple<double, double, string>(Convert.ToDouble(a[0].Groups[2].Value), Convert.ToDouble(a[0].Groups[3].Value), Convert.ToString(a[0].Groups[4].Value)) })
          .ToDictionary(key => key.key, value => value.value);
        Console.ReadKey();
    }



------------------------

このコードを使用できると思います。コード内でタイプを作成するのを忘れたので、辞書を使用してください。そのため、エラーが発生しました。

var dictionary = File
            .ReadLines("textFile")
            .Select(e => e.Split("[(,)]".ToCharArray() , StringSplitOptions.RemoveEmptyEntries))
            .ToDictionary(key => int.Parse(key[0]), values => new Tuple<double, double, string>(
                Convert.ToDouble(values[1]), Convert.ToDouble(values[2]), values[3]));

1

1

[ ] 四角ブレーキを処理するのを忘れました。これは実行時に壊れます。変換できません

– モン・ジュウ

2020 年 9 月 3 日 12:11

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。