c# - قراءة القيم المزدوجة من ملف نصي




(5)

إذا كنت أرى ذلك صحيحًا ، فسيكون لديك تنسيق "بيانات العرض الثابت". مما يمكنك ببساطة تحليل هذه الحقيقة.

أي بافتراض أن القيم موجودة في ملف d:\temp\doubles.txt :

void Main()
{
    var filename = @"d:\temp\doubles.txt";
    Func<string, string[]> split = (s) =>
    {
        string[] res = new string[7];
        res[0] = s.Substring(0, 2);
        for (int i = 0; i < 6; i++)
        {
            res[i + 1] = s.Substring(2 + (i * 19), 19);
        }
        return res;
    };
    var result = from l in File.ReadAllLines(filename)
                 let la = split(l)
                 select new
                 {
                    i = int.Parse(la[0]),
                     d1 = double.Parse(la[1]),
                     d2 = double.Parse(la[2]),
                     d3 = double.Parse(la[3]),
                     d4 = double.Parse(la[4]),
                     d5 = double.Parse(la[5]),
                     d6 = double.Parse(la[6])

                 };
    foreach (var e in result)
    {
        Console.WriteLine($"{e.i}, {e.d1}, {e.d2}, {e.d3}, {e.d4}, {e.d5}, {e.d6}");
    }
}

المخرجات:

33, 0.0573140941467, 0.00011291426239, 0.00255553577735, 4.97192659486E-05, 0.0141869181079, -0.000147813598922
34, 0.0570076593453, 0.000100112550891, 0.00256427138318, -8.68691490164E-06, 0.0142821920093, -0.000346011975369
35, 0.0715507714946, 0.000316132133031, -0.0106581466521, -9.205137369E-05, 0.0138018668842, -0.000212219497066

ملاحظة: مع البيانات الدقيقة الخاصة بك ، يجب أن تخصص int مساحة أكبر.

محاولة قراءة البيانات من ملف نصي باستخدام تطبيق C #. هناك سطور متعددة من البيانات يبدأ كل منها بحساب صحيح ثم يتبعه مجموعة من القيم المزدوجة. جزء من الملف النصي يشبه هذا ،

   33 0.573140941467E-01 0.112914262390E-03 0.255553577735E-02 0.497192659486E-04 0.141869181079E-01-0.147813598922E-03
   34 0.570076593453E-01 0.100112550891E-03 0.256427138318E-02-0.868691490164E-05 0.142821920093E-01-0.346011975369E-03
   35 0.715507714946E-01 0.316132133031E-03-0.106581466521E-01-0.920513736900E-04 0.138018668842E-01-0.212219497066E-03

هنا 33 ، 34 ، 35 هي قيم عدد صحيح ويتبعها 6 قيم مزدوجة. وهذه القيم المزدوجة غير مضمونة بوجود مساحة أو بعض الحدود الأخرى بينهما. أي ، إذا كانت المضاعفة سالبة ، فستكون أمامها "-" قبلها وسيشغل ذلك المساحة. لذلك ، من الممكن أن تكون القيم المزدوجة الستة معًا.

الآن يكمن التحدي في كيفية استخراج هذا بأمان؟

ما حاولت:

String.Split(' ');

لن يعمل هذا حيث أن المساحة غير مضمونة بين قيم الأعداد الصحيحة الأولية ثم بقية القيم المزدوجة.

يمكن حل هذا بسهولة في C ++ باستخدام sscanf .

double a, b, c, d, e, f;

sscanf(string, "%d %lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &e, &f);
// here string contains a line of data from text file.

يتم إنشاء الملف النصي الذي يحتوي على قيم مزدوجة بواسطة أداة تابعة لجهة خارجية وليس لدي أي تحكم في إخراجها.

هل هناك طريقة يمكن استخراج القيم الصحيحة والمزدوجة بها خطًا تلو الآخر؟


إذا لم نتمكن من استخدام string.Split فيمكننا محاولة الانقسام باستخدام التعبيرات Regex.Split بمساعدة Regex.Split ؛ line معين

string line = @"  33 0.573140941467E-01 0.112914262390E-03 0.255553577735E-02 0.497192659486E-04 0.141869181079E-01-0.147813598922E-03";

يمكننا المحاولة

// Split either
//   1. by space
//   2. zero length "char" which is just after a [0..9] digit and followed by "-" or "+"
var items = Regex
  .Split(line, @" |((?<=[0-9])(?=[+-]))")
  .Where(item => !string.IsNullOrEmpty(item)) // we don't want empty parts 
  .Skip(1)                                    // skip 1st 33
  .Select(item => double.Parse(item));        // we want double

Console.WriteLine(string.Join(Environment.NewLine, items));

واحصل على

0.573140941467E-01
0.112914262390E-03
0.255553577735E-02
0.497192659486E-04
0.141869181079E-01
-0.147813598922E-03

في حالة وجود ملف نصي ، يجب تقسيم كل سطر:

Regex regex = new Regex(@" |((?<=[0-9])(?=[+-]))");

var records = File
  .ReadLines(@"c:\MyFile.txt") 
  .Select(line => regex
     .Split(line)
     .Where(item => !string.IsNullOrEmpty(item))
     .Skip(1)
     .Select(item => double.Parse(item))
     .ToArray());

عرض:

  string[] test = new string[] {
     // your examples
     "  33 0.573140941467E-01 0.112914262390E-03 0.255553577735E-02 0.497192659486E-04 0.141869181079E-01-0.147813598922E-03",
     "  34 0.570076593453E-01 0.100112550891E-03 0.256427138318E-02-0.868691490164E-05 0.142821920093E-01-0.346011975369E-03",
     " 35 0.715507714946E-01 0.316132133031E-03-0.106581466521E-01-0.920513736900E-04 0.138018668842E-01-0.212219497066E-03",

     // Some challenging cases (mine)
     "    36 123+456-789    123e+78 9.9e-95 0.0001", 
  };

  Regex regex = new Regex(@" |((?<=[0-9])(?=[+-]))");

  var records = test
    .Select(line => regex
      .Split(line)
      .Where(item => !string.IsNullOrEmpty(item))
      .Skip(1)
      .Select(item => double.Parse(item))
      .ToArray());

  string testReport = string.Join(Environment.NewLine, records
    .Select(record => $"[{string.Join(", ", record)}]"));

  Console.WriteLine(testReport);

النتيجة:

[0.0573140941467, 0.00011291426239, 0.00255553577735, 4.97192659486E-05, 0.0141869181079, -0.000147813598922]
[0.0570076593453, 0.000100112550891, 0.00256427138318, -8.68691490164E-06, 0.0142821920093, -0.000346011975369]
[0.0715507714946, 0.000316132133031, -0.0106581466521, -9.205137369E-05, 0.0138018668842, -0.000212219497066]
[123, 456, -789, 1.23E+80, 9.9E-95, 0.0001]

حل آخر ، يعالج كل سطر بمفرده ويتضمن القيمة int:

    static void Main(string[] args) {
        string[] fileLines = {
            "33 0.573140941467E-01 0.112914262390E-03 0.255553577735E-02 0.497192659486E-04 0.141869181079E-01-0.147813598922E-03",
            "34 0.570076593453E-01 0.100112550891E-03 0.256427138318E-02-0.868691490164E-05 0.142821920093E-01-0.346011975369E-03",
            "35 0.715507714946E-01 0.316132133031E-03-0.106581466521E-01-0.920513736900E-04 0.138018668842E-01-0.212219497066E-03"
        };

        var rex = new Regex(@"\b([-+]?\d+(?:\.\d+(?:E[+-]\d+)?)?)\b", RegexOptions.Compiled);
        foreach (var line in fileLines) {

            var dblValues = new List<double>();
            foreach (Match match in rex.Matches(line)) {
                string strVal = match.Groups[1].Value;
                double number = Double.Parse(strVal, NumberFormatInfo.InvariantInfo);
                dblValues.Add(number);
            }

            Console.WriteLine(string.Join("; ", dblValues));
        }

        Console.ReadLine();
    }
}

النتيجة / الإخراج هو:

33; 0,0573140941467; 0,00011291426239; 0,00255553577735; 4,97192659486E-05; 0,0141869181079; -0,000147813598922
34; 0,0570076593453; 0,000100112550891; 0,00256427138318; -8,68691490164E-06; 0,0142821920093; -0,000346011975369
35; 0,0715507714946; 0,000316132133031; -0,0106581466521; -9,205137369E-05; 0,0138018668842; -0,000212219497066

حل هذا مع تعبير منتظم. أول طلقة لي هي:

"[\s-+]\d+\.\d+E[+-]\d\d"

لقد جربته بهذه الطريقة:

using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace ConsoleApp1 {

    class Program {
        static void Main(string[] args) {
            var fileContents =
                  "33 0.573140941467E-01 0.112914262390E-03 0.255553577735E-02 0.497192659486E-04 0.141869181079E-01-0.147813598922E-03"
                + "34 0.570076593453E-01 0.100112550891E-03 0.256427138318E-02-0.868691490164E-05 0.142821920093E-01-0.346011975369E-03"
                + "35 0.715507714946E-01 0.316132133031E-03-0.106581466521E-01-0.920513736900E-04 0.138018668842E-01-0.212219497066E-03";

            var rex = new Regex(@"[\s-+]\d+\.\d+E[+-]\d\d", RegexOptions.Multiline);
            foreach (Match match in rex.Matches(fileContents)) {
                double d = double.Parse(match.Value.TrimStart(), NumberFormatInfo.InvariantInfo);
                Console.WriteLine("found a match: " + match.Value.TrimStart() + " => " + d);
            }

            Console.ReadLine();
        }
    }
}

باستخدام هذا الإخراج (الترجمة الألمانية ، مع الفاصلة كفاصل عشري):

found a match: 0.573140941467E-01 => 0,0573140941467
found a match: 0.112914262390E-03 => 0,00011291426239
found a match: 0.255553577735E-02 => 0,00255553577735
found a match: 0.497192659486E-04 => 4,97192659486E-05
found a match: 0.141869181079E-01 => 0,0141869181079
found a match: -0.147813598922E-03 => -0,000147813598922
found a match: 0.570076593453E-01 => 0,0570076593453
found a match: 0.100112550891E-03 => 0,000100112550891
found a match: 0.256427138318E-02 => 0,00256427138318
found a match: -0.868691490164E-05 => -8,68691490164E-06
found a match: 0.142821920093E-01 => 0,0142821920093
found a match: -0.346011975369E-03 => -0,000346011975369
found a match: 0.715507714946E-01 => 0,0715507714946
found a match: 0.316132133031E-03 => 0,000316132133031
found a match: -0.106581466521E-01 => -0,0106581466521
found a match: -0.920513736900E-04 => -9,205137369E-05
found a match: 0.138018668842E-01 => 0,0138018668842
found a match: -0.212219497066E-03 => -0,000212219497066

يمكنك القيام بذلك:

public void ParseFile(string fileLocation)
{
   string[] lines = File.ReadAllLines(fileLocation);

   foreach(var line in lines)
   {
       string[] parts = var Regex.Split(line, "(?((?<!E)-)| )");

       if(parts.Any())
       {
          int first = int.Parse(parts[0]);

          double[] others = parts.Skip(1).Select(a => double.Parse(a)).ToArray();
       }
   }
}   



c#  

c#