0

我有 2 个文本文件 default.txt 和 current.txt。

默认.txt:

ab_abcdefghi_EnInP005M3TSub.csv FMR: 0.0009 FNMR: 0.023809524 SCORE: -4  Conformity: True
ab_abcdefghi_EnInP025M3TSub.csv FMR: 0.0039 FNMR: 0 SCORE: -14  Conformity: True
ab_abcdefghi_EnInP050M3TSub.csv FMR: 0.01989 FNMR: 0 SCORE: -18  Conformity: True
ab_abcdefghi_EnInP075M3TSub.csv FMR: 0.0029 FNMR: 0 SCORE: -17  Conformity: True
ab_abcdefghi_EnInP090M3TSub.csv FMR: 0.0002 FNMR: 0 SCORE: -7  Conformity: True

current.txt 看起来像这样

ab_abcdefghi_EnUsP005M3TSub.csv FMR: 0.0041 FNMR: 0 SCORE: -14  Conformity: True
ab_abcdefghi_EnUsP025M3TSub.csv FMR: 0.00710000000000001 FNMR: 0 SCORE: -14  Conformity: True
ab_abcdefghi_EnUsP050M3TSub.csv FMR: 0.0287999999999999 FNMR: 0 SCORE: -21  Conformity: True
ab_abcdefghi_EnUsP090M3TSub.csv FMR: 0.0113 FNMR: 0 SCORE: -23  Conformity: True

我需要做的是从默认值(默认电流)中减去电流值。

例如:

FMR_DIFF = FMR(default) - FMR(test)
FNMR_DIFF = FNMR(default) - FNMR(test)
SCORE_DIFF = SCORE(default) - SCORE(test)

我需要在一个文本文件中输出它,输出看起来像这样

输出/输出:

result:   005M3TSub FMR_DIFF: -0.0032 FNMR_DIFF: 0.023809524 SCORE_DIFF: 10

我正在尝试在 C# 中执行此操作。到目前为止,我已经尝试在两个文件中读取行。我能够比较它们。我无法理解我需要实现的逻辑。我对编程很陌生。任何帮助表示赞赏。

4

3 回答 3

1

为了比较这些值,您首先必须解析它们。您可以创建一个代表单行(假/非假)匹配率的类:

public class MatchRateLine
{
    public int LineNumber { get; set; }

    public decimal FMR { get; set; }
    public decimal FNMR { get; set; }
    public int Score { get; set; }
    public bool Conformity { get; set; }
}

然后在您的解析器中,您可以使用如下方法:

public List<MatchRateLine> ParseFile(string filename)
{
    var result = new List<MatchRateLine>();

    using (var reader = new StreamReader(filename))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            result.Add(ParseLine(line));
        }
    }

    return result;
}

进行实际解析的一种方法是:

public MatchRateLine ParseLine(string line)
{
    var result = new MatchRateLine();

    int fmrPosition = line.IndexOf("FMR: ");
    int fmnrPosition = line.IndexOf("FMNR: ");

    string fmrValueString = line.Substring(fmrPosition, fmnrPosition - fmrPosition);
    decimal fmrValue;
    if (decimal.TryParse(fmrValueString, out fmrValue))
    {
        result.FMR = fmrValue;
    }

    // repeat for other values

    return result;
}

在解析器中,我将“A line's FMR value”定义为“'FMR:'和'FMNR:'之间的文本,解析为十进制”。您必须为要提取的每个值应用此逻辑。

现在,当您有两个集合时,您可以遍历它们并比较它们的值等等:

var defaultLines = Parser.ParseFile("default.txt");
var currentLines = Parser.ParseFile("current.txt");

尽管您的实际问题似乎是您可能想要比较 and 中的特定行defaultcurrent但是您在识别属于彼此的行时遇到了麻烦。如ab_abcdefghi_EnInP090M3TSub您在default第 5 行和第 4 行(注)中所见。ab_abcdefghi_EnUsP090M3TSubcurrentIn/Us

为此,您可以MatchRateLine使用属性扩展类,在其中按含义存储文件名或其子字符串,以便您可以通过该值在两个列表中找到唯一行。

您可以再次使用该Substring()方法,在ParseLine()方法中:

// Position:  0123456789012345678901234567890
// Filename: "ab_abcdefghi_EnInP090M3TSub.csv"

result.ReportCode = line.Substring(17, 6);

这将导致结果MatchRateLine具有ReportCode值为 的属性P090M3

再次给出两个行列表:

var p090m3DefaultLine = defaultLines.First(l => l.ReportCode == "P090M3");
var p090m3CurrentLine = currentLines.First(l => l.ReportCode == "P090M3");

var fmrDiff = p090m3DefaultLine.FMR - p090m3CurrentLine.FMR;

请注意,这段代码对格式做了很多假设,当被解析的行与该格式不匹配时,可能会抛出异常。

于 2013-12-30T11:13:56.877 回答
1

这是一个有趣的问题。请检查解决方案。它没有正确优化。

首先,我们创建一个简单的 FileStructure 类来表示字符串:

public class DefaultFileStructure
    {
        public string FileId;
        public decimal FMR;
        public decimal FNMR;
        public int Score;
        public bool Conformity;
    }

定义用于解析的常量键名。

private static string DEFAULT_KN = "tv_rocscores_DeDeP";
private static string TEST_KN    = "tv_rocscores_FrFrP";

现在,解析文件并将数据存储在列表结构中。

    private List<DefaultFileStructure> GetFileStructure(string filePath, string keyName)
            {
                List<DefaultFileStructure> _defaultFileStructure = new List<DefaultFileStructure>();

                if(!File.Exists(filePath))
                {
                    Console.WriteLine("Error in loading the file");               
                }else{
                    string[] readText = File.ReadAllLines(filePath);
                    foreach (string s in readText)
                    {
                        _defaultFileStructure.Add(ParseLine(s, keyName));                    
                    }
                }

                return _defaultFileStructure;
            }

private DefaultFileStructure ParseLine(string Line, string Keyname)
        {
            DefaultFileStructure _dFileStruc = new DefaultFileStructure();

            string[] groups = Line.Split(new[] { ' ', ' ' },StringSplitOptions.RemoveEmptyEntries);

            /* -- Format Strucure, if the log provide same format always..
               Can also implement Expando concepts of C# 5.0 ***
                0[tv_rocscores_DeDeP005M3TSub.csv]
                1[FMR:]
                2[0.0009]
                3[FNMR:]
                4[0.023809524]
                5[SCORE:]
                6[-4]
                7[Conformity:]
                8[True]
             */

            _dFileStruc.FileId = groups[0].Replace(Keyname, "");
            _dFileStruc.FMR = decimal.Parse(groups[2]);
            _dFileStruc.FNMR = decimal.Parse(groups[4]);
            _dFileStruc.Score = int.Parse(groups[6]);
            _dFileStruc.Conformity = bool.Parse(groups[8]);

            return _dFileStruc;
        }

根据您的问题匹配差异并获得定义的结果。

 public void getDiff(String FirstFile, string SecondFile, string ResultFile)
        {
            try
            {
                //check if file exits....
                if (!File.Exists(FirstFile)) { return; }
                if (!File.Exists(SecondFile)) { return; }

                //Keep the result String..
                StringBuilder ResultBuilder = new StringBuilder();

                //Get the List of default file.
                List<DefaultFileStructure> DefaultList = GetFileStructure(FirstFile, DEFAULT_KN);

                //Get the List of test file.
                List<DefaultFileStructure> TestList = GetFileStructure(SecondFile, TEST_KN);


                //Get the diff and save in StringBuilder.
                foreach (DefaultFileStructure defFile in DefaultList)
                {
                    bool checkALL = false;
                    foreach (DefaultFileStructure testFile in TestList)
                    {
                        //Compare the file for diff.
                        if (defFile.FileId == testFile.FileId)
                        {
                            checkALL = false;
                            ResultBuilder.AppendLine(String.Format("result: {0} FMR_DIFF: {1} FNMR_DIFF: {2} SCORE_DIFF: {3}", defFile.FileId, defFile.FMR - testFile.FMR, defFile.FNMR - testFile.FNMR, defFile.Score - testFile.Score));
                            break;
                        }
                        else
                        {
                            checkALL = true;                      
                        }                        
                    }
                    if (checkALL == true)
                    {
                        ResultBuilder.AppendLine(String.Format("result: {0} FMR_DIFF: {1} FNMR_DIFF: {2} SCORE_DIFF: {3}", defFile.FileId, "N/A", "N/A", "N/A"));

                    }
                }

                //File processing completed.
                using (StreamWriter outfile = new StreamWriter(ResultFile))
                {
                    outfile.Write(ResultBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

调用以下方法。

 getDiff(@"I:\Default_DeDe_operational_points_verbose.txt",
         @"I:\FrFr_operational_points_verbose.txt", 
         @"I:\Result.txt");

谢谢,阿吉特

于 2014-01-12T23:00:27.180 回答
0

您必须指定哪些行必须在输出中:默认的每个“文件”.csv?每个来自当前?两者(如果两个文件之一中缺少一个,则输出仍必须包含此 csv)?

一旦你知道了,你就可以实现你的逻辑:

  • 用一行的属性创建一个类(例如命名为 FileLine),也就是说:一个字符串代表名称(这个字符串的名称:CsvName),一个小数代表 FMR(比如 FmrValue),一个小数代表 FNMR(FnmrValue) , SCORE (ScoreValue) 的 int
  • 为该过程创建一个方法。它会:

  • 检查当前文件的结构:如果无效,停止进程

  • 创建一个名为 defaultLines 的新列表
  • 创建一个名为 currentLines 的新列表
  • 创建一个名为 processesLine 的字符串(将在以后的步骤中使用)
  • 读取默认文件:foreach 行,创建一个 FileLine,解析该行并实现您的 FileLine 的属性,并将 fileLine 添加到列表中(defaultLines)
  • 读取当前文件:foreach 行,创建 FileLine,解析行并实现 FileLine 的属性,并将 fileLine 添加到列表(currentLines)
  • 然后处理比较(见后)

    公共无效比较生成器(){

    // HERE: add currentFile check
    
    // Initialization
    List<FileLine> defaultLines = new List<FileLine>();
    List<FileLine> currentLines = new List<FileLine>();
    
    // HERE: add file reading to populate defaultLines and currentLines 
    
    
    // Comparison
    foreach(FileLine item in defaultLines)
    {
        // for the item with the same name (using Linq, you could do it easily):
        FileLine cLine = currentLines.Single(l => l.CsvName.Equals(item.CsvName));
        if(cLine != null)
        {
            processedLine = String.Format("result: {0} FMR_DIFF: {1} FNMR_DIFF: {2} SCORE_DIFF: {3}", item.CsvName, item.FmrValue - cLine.FmrValue, item.FnmrValue - cLine.FnmrValue, item.ScoreValue - cLine.ScoreValue);
            // HERE: add this line to future output
        }
    }
    
    // When all lines are processed, write the output to a file using FileStream
    

    }

于 2013-12-30T11:24:00.467 回答