

テキストファイルの内容を読み込み、フォーマットを変更して別のファイルに出力したいです。

下記のコードで全文の読み込みと新しいテキストファイルへの書き込みまではできるようになったのですが、フォーマットを変えるにはどのようなコードを書けばいいのでしょうか？

* * *

**元のテキストファイル**

[code]

    116
    11/2/2012 18:22
    N9 45.483 E10 30.495
    416 m
    117
    11/2/2012 18:22
    N9 45.483 E10 30.495
    415 m
    
[/code]

**書き換え後のテキストファイル**

[code]

    116,11/2/2012 18:22,N9 45.483 E10 30.495,416 m
    117,11/2/2012 18:22,N9 45.483 E10 30.495,415 m
    
[/code]

**ソースコード**

[code]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace Reading_textfile
    {
        class Program
        {
            static void Main(string[] args)
            {
                string filePath = @"C:\Users\ryuma\Downloads\Elephantread.txt";
    
                //string[] Lines = File.ReadAllLines(filePath);
    
                List<string> lines = new List<string>();
                lines = File.ReadAllLines(filePath).ToList();
    
                foreach (String line in lines)
                {
                    Console.WriteLine(line);
                }
    
                string filePath2 = @"C:\Users\ryuma\OneDrive\Desktop\WriteFile.txt";
                File.WriteAllLines(filePath2, lines);
                Console.ReadLine();
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2019-12-12T07:03:01.277
61370
2020-02-29T05:01:10.093
2019-12-12T08:30:17.013
76
37030
question
c#
テキストファイルの読み込みと書き込み


単に変換するだけなら、`List<string>`よりも`string[]`を使った方がメソッド呼び出しが減って良さそうです。  
これを：

[code]

    List<string> lines = new List<string>();
    lines = File.ReadAllLines(filePath).ToList();
    
[/code]

こうします：

[code]

    string[] lines = File.ReadAllLines(filePath);
    char[] nl = { '\n' };
    lines = string.Join(",", lines).Replace(" m,", " m\n").Split(nl, StringSplitOptions.RemoveEmptyEntries);
    
[/code]

以下の処理を分割用コードの定義は別にして1行にまとめます。  
(やり方によってはそれも1行に含められるかも)

  * いったん全部の行をカンマで連結
  * 最後の列が空白と`m`で終わることを利用して`m`の直後のカンマを改行コードに変更
  * 改行コードを指定して`string[]`に分割

`StringSplitOptions`が不要ならこちらで変換は1行になりますね。

[code]

    lines = string.Join(",", lines).Replace(" m,", " m\n").Split('\n');
    
[/code]

* * *

**追記**  
その後英語サイトの方に出された質問(+こちらで勝手に追加した想定)の条件に対応してみました。  
[Reading and writing textfile](https://stackoverflow.com/q/59300674/9014308)

  * 英語サイトではデータ間に空白行が存在する可能性が追加されていました。
  * それに関連すれば、データの前後にも空白が付く可能性が考えられます。
  * また英語の回答の中に改行コードの動作中プラットフォーム対応があったので取り入れました。
  * そして書き込む時に行を区切る必要がないので`Split()`は取り止め、書き込みメソッドも変更。

以下のようになります。

[code]

    string line = string.Join(",", lines.Where( // 有効なデータを全てカンマで連結
       s => !string.IsNullOrWhiteSpace(s))      // 事前に空白行ではないものを抽出
          .Select(s => s.Trim()))               // 事前に文字列前後の空白を除去
             .Replace(" m,", " m" + System.Environment.NewLine) // " m"後のカンマを改行へ変換
       + System.Environment.NewLine;            // 最後に改行を付加
    
    string filePath2 = @"C:\Users\ryuma\OneDrive\Desktop\WriteFile.txt";
    File.WriteAllText(filePath2, line); // 分割せず1つの文字列なので WriteAllText
    
[/code]


CC BY-SA 4.0
2019-12-12T07:44:11.367
61372
2019-12-12T15:15:54.257
2019-12-12T15:15:54.257
26370
26370
61370
answer


次のような`ChunkUntil`拡張メソッドを定義するときれいに書けます。

[code]

    public static class Extensions {
        public static IEnumerable<IList<T>> ChunkUntil<T>(this IEnumerable<T> source, Func<T, bool> endChunk) {
            var list = new List<T>();
            foreach (var item in source) {
                list.Add(item);
                if (endChunk(item)) {
                    yield return list;
                    list = new List<T>();
                }
            }
            if (0 < list.Count)
                yield return list;
        }
    }
    
[/code]

呼び出すコードは

[code]

    var filePath = @"C:\Users\ryuma\Downloads\Elephantread.txt";
    var filePath2 = @"C:\Users\ryuma\OneDrive\Desktop\WriteFile.txt";
    var allLines = File.ReadLines(filePath)
        .ChunkUntil(line => Regex.IsMatch(line, " m$"))
        .Select(lines => String.Join(",", lines));
    File.WriteAllLines(filePath2, allLines);
    
[/code]


CC BY-SA 4.0
2019-12-12T07:56:18.577
61373
2019-12-12T09:00:40.990
2019-12-12T09:00:40.990
4236
4236
61370
answer


> テキストファイルの内容を読み込み、フォーマットを変更して別のファイルに出力したいです。  
>  教授からListをできれば使ってくれと言われていた

要件を愚直に実装すると次のようになります。

[code]

    using System;
    using System.IO;
    using System.Text;
    using System.Collections.Generic;
    
    namespace console1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string inFile = @"Elephantread.txt";
                string outFile = @"WriteFile.txt";
    
                using(StreamReader sr = new StreamReader(inFile))
                using(StreamWriter sw = new StreamWriter(outFile))
                {
                    while(! sr.EndOfStream) {
                        StringBuilder sb = new StringBuilder();
                        var list = new List<string>();
                        list.Add(sr.ReadLine());
                        list.Add(sr.ReadLine());
                        list.Add(sr.ReadLine());
                        list.Add(sr.ReadLine());
                        sw.WriteLine(string.Join(",", list));
                    }
                }
            }
        }
    }
    
[/code]

入力ファイルを出力ファイルに変換する場合の仕様が明確になっていないので

[code]

    入力された行を 4行単位に カンマ区切りで １行に変換して出力する
    
[/code]

という前提の実装になっています。

`m` が 行末にある場合が 行の最後になると言う 仕様はどこにも提示されていなかったので `m` の 行末判定は入れていません。

入力行数が ４行で割り切れない場合には

`117,,,`

のように カンマ区切りで出力されます。

この実装の特徴は 入力ファイルが 超 大きなファイル（４G 以上）でも、メモリ不足にならずに変換できることです。


CC BY-SA 4.0
2019-12-13T00:22:39.460
61390
2019-12-13T00:22:39.460
18851
61370
answer


ちょっと書いてみました。こんな感じでどうでしょうか？  
テストはしていません。改行文字がCR/LFの場合は適時変更してください。

[code]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace Reading_textfile
    {
        class Program
        {
            static void Main(string[] args)
            {
                string filePath = @"C:\Users\ryuma\Downloads\Elephantread.txt";
    
                //string[] Lines = File.ReadAllLines(filePath);
    
                List<string> lines = new List<string>();
                lines = File.ReadAllLines(filePath).ToList();
    
                foreach (String line in lines)
                {
                    Console.WriteLine(line);
                }
    
                List<string> lines2 = new List<string>();　　// 出力用のList作成
    
                string a = "";　　　　　　　　　　　　　　　　// 出力用文字列用変数
                foreach(string line in lines)
                {
    
                    if (line.Contains("m") == true)          // mが含まれていたら１行終了
                    {
                        a += line;
                        lines2.Add(a);                       // line2に追加
                        a = "";                              // 次の行のためにクリアする。
                    } else
                    {
                        a += line.Replace("\n", ",");        // mが含まれていなければ改行文字を,に変更し、追加
                    }
                }
    
                string filePath2 = @"C:\Users\ryuma\OneDrive\Desktop\WriteFile.txt";
                File.WriteAllLines(filePath2, lines2);
                Console.ReadLine();
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2019-12-13T08:30:09.807
61408
2019-12-13T08:36:03.433
2019-12-13T08:36:03.433
24490
24490
61370
answer