-1

I have input file (.txt) including lots of numbers. I have a code to read it and modify it, but I don't succeed to remove unnecessary decimals.

Please, help me to round these numbers to 2 decimals.

My code:

const string FILE_SOURCE = @"Text.txt";

const string FILE_RESULT = @"Text2.txt";

List<TextModification> Rules = new List<TextModification>
{
new SimpleSplitLongLine(),
new SimpleModifyTextLine("string", ""),
new RegexModifyLine("LOAD [0-9]{3,}", "PERFORM ANALYSIS", "LOAD ([0-9]{3,})", "LOAD COMB $1"),
};

const bool DUMP_MODS = true;

const string STD_ENCODING = "iso-8859-1";

void Main()
{


var stdEncoding = Encoding.GetEncoding(STD_ENCODING);
int lines = File.ReadLines(FILE_SOURCE).Count();
int currentLine = 0;

var progress = new Util.ProgressBar();
progress.Caption = "Käsitellään tiedostoa";
progress.Dump();

using (TextReader r = new StreamReader(FILE_SOURCE, stdEncoding))
{
    using (TextWriter w = new StreamWriter(FILE_RESULT, false, stdEncoding))
    {           
        string line;
        while ((line = r.ReadLine()) != null)
        {
            if (++currentLine % 1000 == 0)
                progress.Percent = Math.Min(100, (currentLine* 100) / lines);

            bool handled = false;

            foreach (var rule in Rules)
            {
                if (rule.CanHandle(line, currentLine))
                {
                    rule.Handle(line, currentLine, w);
                    handled = true;                     
                }
            }

            if (!handled)
                w.WriteLine(line);
        }           
    }
}

progress.Percent = 100;
progress.Caption = "Valmis";
}

public abstract class TextModification
{
public string Name { get; set; } = String.Empty;

public abstract bool CanHandle(string line, int lineNumber);
public virtual void Handle(string line, int lineNumber, TextWriter w) {}
}

public class SimpleModifyLine : TextModification
{
public string Text { get; }
public string Replace { get; }

public SimpleModifyLine(string text, string replace)
{
    Text = text;
    Replace = replace;
}

public override bool CanHandle(string line, int lineNumber) => line.Contains(Text);

public override void Handle(string line, int lineNumber, TextWriter w)
{
    $"{lineNumber} {Name}: Modified '{line} --> {line.Replace(Text,Replace)}'".Dump();
    w.WriteLine(line.Replace(Text, Replace));       
}
}


public class SimpleSplitLongLine : TextModification
{
public int MaxLength { get; set; } = 79;
public string LineContinueSymbols { get; set;} = "-";

public override bool CanHandle(string line, int lineNumber)
{
    if (line.Length > MaxLength)
    {
        $"Katkaistaan rivi {lineNumber} (pituus: {line.Length})".Dump();
        return true;
    }       

    return false;
}


public override void Handle(string line, int lineNumber, TextWriter w)
{
    string [] data = line.Split(' ');

    string newLine = string.Empty;
    int lineLength = MaxLength - LineContinueSymbols.Length;

    for (int i = 0; i < data.Length; i++)
    {

        if (newLine.Length + data[i].Length + 1 > lineLength)
        {
            w.Write(newLine);
            w.WriteLine(LineContinueSymbols);

            newLine = data[i] + " ";
        }

        else
        {
            newLine += data[i] + " ";
        }       
    }

    if (newLine.Length > 0)
        w.WriteLine(newLine);
}
}


public class SimpleModifyTextLine : TextModification
{
public string Text { get; }
public string Replace { get; }

private List<string> buffer = new List<string>();
private const string LINE_CHANGE = "-";

public SimpleModifyTextLine(string text, string replace)
{
    Text = text;
    Replace = replace;
}

public override bool CanHandle(string line, int lineNumber)
{
    if (buffer.Count > 0)
        return true;

    return line.Contains(Text);
}

public override void Handle(string line, int lineNumber, TextWriter w)
{
    //w.WriteLine(line);

    if (line.EndsWith(LINE_CHANGE))
    {
        buffer.Add(line.Replace(Text, Replace));
    }
    else
    {           
        buffer.ForEach(w.WriteLine);            
        w.WriteLine(line.Replace(Text, Replace));
        buffer.Clear();
    }
}
}

public class RegexModifyLine : TextModification
{
public Regex StartRegex { get; }
public Regex EndRegex { get; }
public Regex ReplaceRegex { get; }
public string ReplaceString { get; }
public bool Modify { get; private set; }

public RegexModifyLine(string startRegex, string endRegex, string replaceRegex, string replaceString)
{
    StartRegex = new Regex(startRegex);
    EndRegex = new Regex(endRegex);
    ReplaceRegex = new Regex(replaceRegex);
    ReplaceString = replaceString;
}

public override bool CanHandle(string line, int lineNumber)
{
    if (!Modify && StartRegex.IsMatch(line))
    {
        Modify = true;
        return ReplaceRegex.IsMatch(line);
    }

    else if (Modify && EndRegex.IsMatch(line))
    {
        Modify = false;
        return ReplaceRegex.IsMatch(line);
    }

    if (Modify) return ReplaceRegex.IsMatch(line);

    else return false;      
}

public override void Handle(string line, int lineNumber, TextWriter w)
{
    string newLine = ReplaceRegex.Replace(line, ReplaceString);

    $"{lineNumber} {Name}: Modified '{line} --> {newLine}'".Dump();

    if (newLine != string.Empty)        
        w.WriteLine(newLine);
}
}

My text file:

172.800000 45.000000 0.800000 35.000000 2.000000 69309.733333 14293.416000 -
194.005333 36.000000 140.000000
WI800-16-20X350
261.600000 80.000000 1.600000 35.000000 2.000000 271470.133333 14317.608000 -
293.162667 128.000000 140.000000
132.800000 45.000000 0.800000 25.000000 2.000000 50819.733333 5210.082667 -
140.672000 36.000000 100.000000
18 1.000 33 -1.000 1 1.000 26 1.000 6 -1.000 14 1.000 20 1.000 19 1.000 25 1.000 13 1.000
15 0.667 8 0.333 18 0.667 1 0.667 26 0.667 14 0.667 20 0.667 19 0.667 25 0.667 13 0.667
15 0.667 8 0.333 18 0.667 1 0.667 14 0.667 25 0.667 13 0.667
18 0.667 9 0.333 23 0.667 1 0.667 26 0.667 14 0.667 20 0.667 19 0.667 25 0.667 13 0.667
18 0.667 9 0.333 23 0.667 1 0.667 14 0.667 25 0.667 13 0.667
18 0.667 22 0.667 1 0.667 26 0.667 14 0.667 20 0.667 19 0.667 25 0.667 13 0.667 2 0.333
18 0.667 22 0.667 1 0.667 14 0.667 25 0.667 13 0.667 2 0.333
33 0.667 9 0.667 18 0.667 26 0.667 1 0.667 14 0.667 20 0.667 19 0.667 25 0.667 13 0.667

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
Tuomas
  • 3
  • 3
  • 1
    can you please reduce your code to the essential part. Only where you read, convert, round and write the numbers?=! – Mong Zhu Aug 21 '17 at 09:44
  • It is impossible to always get exactly two decimal places with floating point numbers. The floating point number is store in Net as a power of base 2 while converting to a string you are showing results as base 10. A base to and base 10 number will have slightly different LSBs. – jdweng Aug 21 '17 at 09:45
  • @jdweng Well, it depends on the value. For instance, 0.25 is exactly representable as binary floating point. In any case, the asker doesn't necessarily need to represent the value exactly in a binary floating point value. For instance, choosing a decimal representation would avoid the issue of representability. Or perhaps it's enough to convert directly to a string if text output is all that is required. – David Heffernan Aug 21 '17 at 09:46
  • 1
    Hi, welcome to SO. Please narrow down your question to a specific call that's giving you a problem. Your question, as it currently is will probably not receive a good answer. Please see [how to create a minimal, verifiable example](https://stackoverflow.com/help/mcve) for better results using this site. Good luck! – kenny_k Aug 21 '17 at 09:48

3 Answers3

0

Math.Round will do this for you.

var rounded= Math.Round(0.123456789, 2);

will give you

0.12

Have a read at MSDN Math.Round Method for more information.

Mighty Badaboom
  • 6,067
  • 5
  • 34
  • 51
0

Although your code looks quite convoluted, you seem to handle the numbers as strings. So there is not actual rounding of numbers as I see it. So here is a solution how you take 2 decimal places after the comma in strings:

string s = "18.123456";

string rounded = s.Substring(0, s.IndexOf(".")+3);

I hope you can addapt it to your code. One oportunity seems to be in the Handle method:

newLine += data[i].Substring(0, data[i].IndexOf(".")+3) + " ";

all other lines that don't fit the if (rule.CanHandle(line, currentLine)) criterion you have to split by hand and take the substring from each number.

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
0

Use Math.Round can do what you want. But there are also one factor that quite important, the MidPointRounding

 Math.Round( 3.45, 1, MidpointRounding.ToEven) // = 3.4

 Math.Round( 3.45, 1, MidpointRounding.AwayFromZero) // = 3.5

Check this out for the explanation MSDN

Feli Wen
  • 41
  • 3