c# - Doppelte Werte aus einer Textdatei lesen




(5)

Es wurde versucht, mit einer C # -Anwendung Daten aus einer Textdatei zu lesen. Es gibt mehrere Datenzeilen, von denen jede mit einer Ganzzahl beginnt, gefolgt von einer Reihe von Doppelwerten. Ein Teil der Textdatei sieht folgendermaßen aus:

   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

Hier sind 33, 34, 35 ganzzahlige Werte und es folgen 6 doppelte Werte. Und es ist nicht garantiert, dass zwischen diesen Doppelwerten ein Leerzeichen oder ein anderes Trennzeichen steht. dh wenn ein double negativ ist, wird es ein "-" vor sich haben und dies wird den Raum einnehmen. Grundsätzlich ist es also möglich, dass alle 6 Doppelwerte zusammen sind.

Nun ist die Herausforderung, wie man dies anmutig extrahiert?

Was ich versucht habe:

String.Split(' ');

Dies funktioniert nicht, da kein Leerzeichen zwischen den anfänglichen Integer-Werten und den restlichen Double-Werten garantiert ist.

Dies kann in C ++ mit sscanf leicht gelöst werden.

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.

Die Textdatei, die doppelte Werte enthält, wird von einem Drittanbieter-Tool generiert, und ich habe keine Kontrolle über die Ausgabe.

Gibt es eine Möglichkeit, die Integer- und Double-Werte zeilenweise zu extrahieren?


Die Antworten, die ich bisher gesehen habe, sind so komplex. Hier ist eine einfache ohne zu überdenken

Laut @ Veljko89's Kommentar habe ich den Code mit unbegrenzter Nummernunterstützung aktualisiert

    List<double> ParseLine(string line)
    {
        List<double> ret = new List<double>();

        ret.Add(double.Parse(line.Substring(0, line.IndexOf(' '))));
        line = line.Substring(line.IndexOf(' ') + 1);

        for (; !string.IsNullOrWhiteSpace(line); line = line.Substring(line.IndexOf('E') + 4))
        {
            ret.Add(double.Parse(line.Substring(0, line.IndexOf('E') + 4)));
        }

        return ret;
    }

Ich wurde einfach nicht optimal und ersetzte die "E-" Zeichenfolge durch etwas anderes, während ich das gesamte negative Vorzeichen durch ein Leerzeichen und ein negatives Vorzeichen ("-") ersetzte und dann alle "E-" Werte zurücksetzte.

Dann konnte ich die Werte mit split extrahieren.

private static IEnumerable<double> ExtractValues(string values)
{
    return values.Replace("E-", "E*").Replace("-", " -").Replace("E*", "E-").Split(' ').Select(v => double.Parse(v));
}

Noch eine andere Lösung, die jede Zeile für sich verarbeitet und den int-Wert enthält:

    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();
    }
}

Das Ergebnis / die Ausgabe ist:

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

Sie könnten dies tun:

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();
       }
   }
}   

Wenn wir string.Split nicht verwenden string.Split , können wir versuchen, mit Hilfe von Regex.Split durch reguläre Ausdrücke zu Regex.Split . für eine bestimmte line

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

Wir können es versuchen

// 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));

und bekomme

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

Im Falle einer Textdatei sollten wir jede Zeile teilen:

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());

Demo:

  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);

Ergebnis:

[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]



c#  

c#