Click here to Skip to main content
15,886,518 members
Articles / Programming Languages / C#

Text Parser for C#

Rate me:
Please Sign up or sign in to vote.
3.00/5 (8 votes)
26 Oct 20061 min read 83.7K   699   37   13
This class parses text data stored in String or TextReader objects, i.e., it is suitable for loading of text files.

Introduction

While .NET class BinaryReader provides many useful methods, e.g., ReadByte, ReadDouble, etc., there are no such methods in TextReader. As far as I know, there is neither a .NET class similar to good Java Scanner class (java.util.Scanner) nor a .NET class providing methods similar to C/C++ CRT function scanf. This means that the reading of text files may become, especially for beginners, a nightmare. The common way is to read the whole line, split it into tokens and convert these tokens into the required format (Byte, Double, Int32, ...) but it is not very convenient. Therefore I decided to program my own class to simplify text data processing.

Using the Code

ZCU.IO.TextParser is a small class written in C# 2.0 that is able to read text data from String or TextReader object. It provides methods for reading numbers, words, tokens matching the given pattern, etc. It also contains the method Scanf for formatted reading.

The following example, which can read 2D or 3D points from the text file, demonstrates the use of this class.

Input file 1

100
0.10330 0.00540
0.42320 0.49370
0.23690 0.56980

etc.

Input file 2

100
0.10330 0.00540 0.23690
0.42320 0.49370 0.23690
0.23690 0.56980 0.10330

etc.

The code for loading input files is as follows:

C#
StreamReader lReader = new StreamReader(new FileStream(strFilePath, 
		FileMode.Open, FileAccess.Read, FileShare.Read),Encoding.UTF8);

ZCU.IO.TextParser parser = new ZCU.IO.TextParser(lReader);

//loads the number of points in the file
uint nNumVert = parser.ReadUInt32();
m_TriData.Vertices = new TRS_VERTEX[nNumVert];

//reads the first point
string line = parser.ReadLine();
ZCU.IO.TextParser line_parser = new ZCU.IO.TextParser(line);

//buffer for objects retrieved by Scanf
object[] xyz = new object[3];
xyz[2] = new System.Single();        //0,1(x,y) are always created by Scanf
string format = "%f %f %f\n";
if (line_parser.Scanf(format, xyz) < 3)
    format = "%f %f\n";              //z-coordinate not in file

List<STRING> formatList = ZCU.IO.TextParser.ConstructFormatList(format);

m_TriData.Vertices[0].x = (float)xyz[0];
m_TriData.Vertices[0].y = (float)xyz[1];
m_TriData.Vertices[0].z = (float)xyz[2];

for(uint i = 1; i < nNumVert; i++)
{
    parser.Scanf(formatList, xyz);
    m_TriData.Vertices[i].x = (float)xyz[0];
    m_TriData.Vertices[i].y = (float)xyz[1];
    m_TriData.Vertices[i].y = (float)xyz[2];
}

Points of Interest

The source code can be used, modified and redistributed under the terms of the license agreement that is included in the deployment package.

History

  • 26.10.2006 - version 1.0

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Czech Republic Czech Republic
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralReading lrc file Pin
Megalan27-Feb-09 3:30
Megalan27-Feb-09 3:30 
GeneralLp,BP,HP filters design in C# [modified] Pin
Keleistein9-Apr-07 21:57
Keleistein9-Apr-07 21:57 
Guys I'm very stuck.I've searched the web for the past three weeks for a class written in C# that has low pass, high pass, Band pass filters which I could used for my third year project data analysis. I'm very desperate and my eyes are bloody red right now due to lack sleep; please help...

I believe there are alot of geniuses in this forum who cannot be stopped by anything..Looking forward to receiving your help...
Cheers
The followings are two classes that I found on the web but I don't understand where they get Series from. Please have a look to see if you can help me modify the classes...
<code//=================================================================
//  File:		FIRFilters.cs
//
//  Namespace:	Dundas.Charting.Utilities
//
//	Classes:	FIRFilters, FFT
//
//  Purpose:	Used to perform digital filters on charts
//
//===================================================================
// Dundas Chart Control .Net
// Copyright © Dundas Software 2001-2005, all rights reserved
//===================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Dundas.Charting.Utilities;//WinControl;

namespace Dundas.Charting.Utilities
{
    /// <summary>
    /// Helper class which implements the filtering functions. Currently Low Pass, High Pass and
    /// Band Pass are implemented.
    /// </summary>
    class FIRFilters
    {
        #region Members
        /// <summary>
        /// The number of samples is the same as the number of points
        /// </summary>
        private int mySamples;

        /// <summary>
        /// Holds the coefficient from the window function
        /// </summary>
        private float[] myCoeff;

        /// <summary>
        /// Holds the series which has the input data
        /// </summary>
        private Series myInputSeries;

        /// <summary>
        /// Holds the series which we are outputting to
        /// </summary>
        private Series myFilterSeries;

        /// <summary>
        /// FFT algorithm object
        /// </summary>
        private FFT myFFT;

        /// <summary>
        /// Holds the current algorithm selected. Enumeration type is drawn from the FFT object.
        /// </summary>
        public FFT.Algorithm CurrentAlgorithm;

        private float myFreqFrom;
        private float myFreqTo;
        private float myAttenuation;
        private float myBand;
        private float myAlpha;
        private int myTaps;
        private int myOrder;
        #endregion

        #region Properties
        /// <summary>
        /// The starting passband frequency, must be lower than ending frequency.
        /// </summary>
        public float FreqFrom
        {
            get { return myFreqFrom; }
            set { myFreqFrom = value; }
        }

        /// <summary>
        /// The ending passband frequency, must be higher than starting frequency.
        /// </summary>
        public float FreqTo
        {
            get { return myFreqTo; }
            set { myFreqTo = value; }
        }

        /// <summary>
        /// Stopband attenuation
        /// </summary>
        public float StopBandAttenuation
        {
            get { return myAttenuation; }
            set {
                    myAttenuation = value;
                    this.myFFT.StopBandAttenuation = myAttenuation;
                }
        }

        /// <summary>
        /// Transition band
        /// </summary>
        public float TransitionBand
        {
            get { return myBand; }
            set {
                    myBand = value;
                    this.myFFT.TransitionBand = myBand;
                }
        }

        /// <summary>
        /// Alpha value used for the Kaiser algorithm.
        /// </summary>
        public float Alpha
        {
            get { return myAlpha; }
            set {
                    myAlpha = value;
                    this.myFFT.Alpha = myAlpha;
                }
        }

        /// <summary>
        /// Number of taps to be used. Taps is the number of samples processed at any one time.
        /// </summary>
        public int Taps
        {
            get { return myTaps; }
            set { myTaps = value; }
        }

        /// <summary>
        /// Filter order. Must be an even number.
        /// </summary>
        public int Order
        {
            get { return myOrder; }
            set
            {
                //Assure value is even
                if ((value % 2) == 0)
                {
                    myOrder = value;
                    this.myFFT.Order = myOrder;
                }
                else
                    throw new ArgumentOutOfRangeException("Order", "Filter order must be an even number.");
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Main constructor. Resets all settings within the FFT algorithm object.
        /// </summary>
        public FIRFilters()
        {
            //Create a new FFT object
            this.myFFT = new FFT();

            //Default algorithm to Kaiser
            this.CurrentAlgorithm = FFT.Algorithm.Kaiser;

            //Default taps to 35
            this.myTaps = 35;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Performs a low pass filter. Output series will be cleared before being
        /// output to. If passband start and end frequencies are left at 0, defaults are used.
        /// </summary>
        /// <param name="iseries">Input series that contains input data. Input Y-Values must be contained in YValues[0] or unexpected output will occur</param>
        /// <param name="oseries">Output series to which filter will be written. Output Y-Values are written to YValues[0]</param>
        public void LowPassFilter(Series iseries, Series oseries)
        {
            //If no start and end frequencies are specified, default low pass frequency range to:
            //0 - 1000hz
            if (this.myFreqFrom == 0.0f && this.myFreqTo == 0.0f)
            {
                this.myFFT.FreqFrom = 0.0f;
                this.myFFT.FreqTo = 1000.0f;
            }
            else
            {
                this.myFFT.FreqFrom = this.myFreqFrom;
                this.myFFT.FreqTo = this.myFreqTo;
            }

            //Generate the actual coefficients
            this.myCoeff = this.myFFT.GenerateCoefficients(FFT.FilterType.LowPass, CurrentAlgorithm);

            //Filter the series based on the coefficients generated
            Filter(iseries, oseries);
        }

        /// <summary>
        /// Performs a high pass filter. Output series will be cleared before being
        /// output to. If passband start and end frequencies are left at 0, defaults are used.
        /// </summary>
        /// <param name="iseries">Input series that contains input data. Input Y-Values must be contained in YValues[0] or unexpected output will occur</param>
        /// <param name="oseries">Output series to which filter will be written. Output Y-Values are written to YValues[0]</param>
        public void HighPassFilter(Series iseries, Seriesoseries)
        {
            //If no start and end frequencies are specified, default high pass frequency range to:
            //2000 - 4000hz
            if (this.myFreqFrom == 0.0f && this.myFreqTo == 0.0f)
            {
                this.myFFT.FreqFrom = 2000.0f;
                this.myFFT.FreqTo = 4000.0f;
            }
            else
            {
                this.myFFT.FreqFrom = this.myFreqFrom;
                this.myFFT.FreqTo = this.myFreqTo;
            }

            //Generate the actual coefficients
            this.myCoeff = this.myFFT.GenerateCoefficients(FFT.FilterType.HighPass, CurrentAlgorithm);

            //Filter the series based on the coefficients generated
            Filter(iseries, oseries);
        }

        /// <summary>
        /// Performs a band pass filter. Output series will be cleared before being
        /// output to. If passband start and end frequencies are left at 0, defaults are used.
        /// </summary>
        /// <param name="iseries">Input series that contains input data. Input Y-Values must be contained in YValues[0] or unexpected output will occur</param>
        /// <param name="oseries">Output series to which filter will be written. Output Y-Values are written to YValues[0]</param>
        public void BandPassFilter(Series iseries, Series oseries)
        {
            //If no start and end frequencies are specified, default band pass frequency range to:
            //1000 - 1000hz
            if (this.myFreqFrom == 0.0f && this.myFreqTo == 0.0f)
            {
                this.myFFT.FreqFrom = 1000.0f;
                this.myFFT.FreqTo = 1000.0f;
            }
            else
            {
                this.myFFT.FreqFrom = this.myFreqFrom;
                this.myFFT.FreqTo = this.myFreqTo;
            }

            //Generate the actual coefficients
            this.myCoeff = this.myFFT.GenerateCoefficients(FFT.FilterType.BandPass, CurrentAlgorithm);

            //Filter the series based on the coefficients generated
            Filter(iseries, oseries);
        }
        #endregion

        #region Initialization
        /// <summary>
        /// Initializes the FIRFilters object by setting the input and output series members for use
        /// by the filter.
        /// </summary>
        /// <param name="iseries">Input series that contains input data</param>
        /// <param name="oseries">Output series to which filter will be written</param>
        private void SetIOSeries(Series iseries, Series oseries)
        {
            this.myInputSeries = iseries;
            this.myFilterSeries = oseries;

            //Samples is the number of points contained in the input
            this.mySamples = myInputSeries.count;
        }
        #endregion

        #region Filter
        /// <summary>
        /// Performs the actual filter. Coefficients should have already be generated by the calling
        /// function, this function merely applies them and physically adds the points to the output series.
        /// </summary>
        /// <param name="iseries">Input series that contains input data</param>
        /// <param name="oseries">Output series to which filter will be written</param>
        private void Filter(float[] iseries, List<float> oseries)
        {
            float[] x = new float[myTaps];
            float y;

            //Set the series
            SetIOSeries(iseries, oseries);
            
            //Clear series
            myFilterSeries.Clear();

            //Initialize x
            for (int i = 1; i < myTaps; i++)
                x[i] = 0.0f;

            //Loop through every data point
            for (int i = 0; i < mySamples; i++)
            {
                //Initialize y
                y = 0.0f;

                //Obtain the data value (Y value) at the specified X value (i)
                x[0] = Convert.ToSingle(myInputSeries[i]);

                //Loop through from 0 to number of taps and calculate the sum
                try
                {
                    for (int j = 0; j < myTaps; j++)
                        y = y + (x[j] * myCoeff[j]);
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine(e.Message + " Check filter order.");
                    throw;
                }

                //Shift all x values by 1 to the right
                for (int j = myTaps - 1; j > 0; j--)
                    x[j] = x[j - 1];

                //Add the y value to the output series at the current x value
                myFilterSeries.Add(new Dundas.Charting.DataPoint(i, y));
            }
        }
        #endregion
    }
}

<pre>
//=================================================================
//  File:		FFT.cs
//
//  Namespace:	Dundas.Charting.Utilities
//
//	Classes:	FFT
//
//  Purpose:	Used for the fast fourier transformation algorithm
//
//===================================================================
// Dundas Chart Control .Net
// Copyright © Dundas Software 2001-2005, all rights reserved
//===================================================================

using System;
using System.Collections.Generic;
using System.Text;

namespace Dundas.Charting.Utilities
{
    /// <summary>
    /// Helper class which implements the various window functions for determination of the filter
    /// coefficients.
    /// </summary>
    class FFT
    {
        #region Members
        /// <summary>
        /// Filter type enumeration for identification of what type of filter we want coefficients
        /// for.
        /// </summary>
        public enum FilterType { HighPass, LowPass, BandPass };

        /// <summary>
        /// Algorithm enumeration for choice of algorithm
        /// </summary>
        public enum Algorithm { Kaiser, Hann, Hamming, Blackman, Rectangular };

        private float myRate;
        private float myFreqFrom;
        private float myFreqTo;
        private float myAttenuation;
        private float myBand;
        private float myAlpha;
        private int myOrder;

        /// <summary>
        /// Shannon sampling frequency
        /// </summary>
        private float myFS;
        #endregion

        #region Properties
        /// <summary>
        /// Sampling rate
        /// </summary>
        public float Rate
        {
            get { return myRate; }
            set
            {
                myRate = value;
                myFS = 0.5f * myRate;
            }
        }

        /// <summary>
        /// Starting frequency for passband. Must be lower than the ending frequency.
        /// </summary>
        public float FreqFrom
        {
            get { return myFreqFrom; }
            set { myFreqFrom = value; }
        }

        /// <summary>
        /// Ending frequency for passband. Must be higher than the starting frequency.
        /// </summary>
        public float FreqTo
        {
            get { return myFreqTo; }
            set { myFreqTo = value; }
        }

        /// <summary>
        /// Stopband attenuation.
        /// </summary>
        public float StopBandAttenuation
        {
            get { return myAttenuation; }
            set { myAttenuation = value; }
        }

        /// <summary>
        /// Transition band.
        /// </summary>
        public float TransitionBand
        {
            get { return myBand; }
            set { myBand = value; }
        }

        /// <summary>
        /// Alpha value used for the Kaiser algorithm.
        /// </summary>
        public float Alpha
        {
            get { return myAlpha; }
            set { myAlpha = value; }
        }

        /// <summary>
        /// Filter order. Must be an even number.
        /// </summary>
        public int Order
        {
            get { return myOrder; }
            set { myOrder = value; }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Construct a FFT instance and initialize with default values.
        /// </summary>
        public FFT()
        {
            //default rate to 8000
            Rate = 8000;

            //default attenuation to 60db
            this.myAttenuation = 60;

            //default transition band to 500hz
            this.myBand = 500;

            //default order to 0 so that we'll know if it was changed by the user or not
            this.myOrder = 0;

            //default Alpha to 4
            this.myAlpha = 4;
        }
        #endregion

        #region Mathematical Functions
        /// <summary>
        /// Bessel is the zeroth order Bessel function which is used in the Kaiser window.
        /// This is a polynomial approximation of the zeroth order modified Bessel function found in:
        /// W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling.
        /// Numerical Recipes in C: The Art of Scientific Computing.
        /// Cambridge UP, 1988.
        /// P. 237
        /// </summary>
        /// <param name="x">Input number which the Bessel will be performed on</param>
        private float Bessel(float x)
        {
            double ax, ans;
            double y;

            ax = System.Math.Abs(x);
            if (ax < 3.75)
            {
                y = x / 3.75;
                y *= y;
                ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492
                    + y * (0.2659732 + y * (0.360768e-1 + y * 0.45813e-2)))));
            }
            else
            {
                y = 3.75 / ax;
                ans = (System.Math.Exp(ax) / System.Math.Sqrt(ax)) * (0.39894228 + y * (0.1328592e-1
                    + y * (0.225319e-2 + y * (-0.157565e-2 + y * (0.916281e-2
                    + y * (-0.2057706e-1 + y * (0.2635537e-1 + y * (-0.1647633e-1
                    + y * 0.392377e-2))))))));
            }

            return (float)ans;
        }
        #endregion

        #region Generate Coefficients
        /// <summary>
        /// Calculate the coefficients to be used by the filter function.
        /// </summary>
        /// <param name="filterType">Enum type which specifies the filter to be performed.</param>
        /// <param name="alg">Enum type which specifies which algorithm to be used for the window
        /// algorithm.</param>
        public float[] GenerateCoefficients(FilterType filterType, Algorithm alg)
        {
            //Calculate order if it hasn't been set
            if (this.myOrder == 0)
                this.myOrder = (int)(((this.myAttenuation - 7.95f) / (this.myBand * 14.36f / this.myFS) + 1.0f) * 2.0f) - 1;

            float[] window = new float[(this.myOrder / 2) + 1];
            float[] coEff = new float[this.myOrder + 1];
            float ps;
            float pe;
            const float PI = (float)System.Math.PI;
            int o2 = this.myOrder / 2;

            //Switch based on algorithm
            switch (alg)
            {
                case Algorithm.Kaiser:
                    //Kaiser Window function
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = Bessel(this.myAlpha * (float)System.Math.Sqrt(1.0f - (float)System.Math.Pow((float)i / o2, 2))) / Bessel(this.myAlpha);
                    }

                    //Stopband attenuation and transition band should be set by the user
                    break;

                case Algorithm.Hann:
                    //Hann window function
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = 0.5f + 0.5f * (float)System.Math.Cos((PI / (o2 + 1)) * i);
                    }

                    //Set the min stopband attenuation
                    this.StopBandAttenuation = 44.0f;

                    //Set the transition band
                    this.TransitionBand = 6.22f * this.myFS / this.myOrder;
                    break;

                case Algorithm.Hamming:
                    //Hamming window function
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = 0.54f + 0.46f * (float)System.Math.Cos((PI / o2) * i);
                    }

                    //Set the min stopband attenuation
                    this.StopBandAttenuation = 53.0f;

                    //Set the transition band
                    this.TransitionBand = 6.64f * this.myFS / this.myOrder;
                    break;

                case Algorithm.Blackman:
                    //Blackman window function
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = 0.42f + 0.5f * (float)Math.Cos((PI / o2) * i) + 0.08f * (float)Math.Cos(2.0f * (PI / o2) * i);
                    }

                    //Set the min stopband attenuation
                    this.StopBandAttenuation = 74.0f;

                    //Set the transition band
                    this.TransitionBand = 11.13f * this.myFS / this.myOrder;
                    break;

                case Algorithm.Rectangular:
                    //Rectangular window function
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = 1.0f;
                    }

                    //Set the min stopband attenuation
                    this.StopBandAttenuation = 21.0f;

                    //Set the transition band
                    this.TransitionBand = 1.84f * this.myFS / this.myOrder;
                    break;

                default:
                    //Zero all values if nothing was set (error)
                    for (int i = 1; i <= o2; i++)
                    {
                        window[i] = 0.0f;
                    }
                    break;
            }

            //Switch based on filtertype
            switch (filterType)
            {
                case FilterType.BandPass:
                    pe = PI / 2 * (this.FreqTo - this.FreqFrom + this.myBand) / this.myFS;
                    ps = PI / 2 * (this.FreqFrom + this.FreqTo) / this.myFS;
                    break;

                case FilterType.LowPass:
                    pe = PI * (this.FreqTo + this.myBand / 2) / this.myFS;
                    ps = 0.0f;
                    break;

                case FilterType.HighPass:
                    pe = PI * (1.0f - (this.FreqFrom - this.myBand / 2) / this.myFS);
                    ps = PI;
                    break;

                default:
                    pe = 0.0f;
                    ps = 0.0f;
                    break;
            }

            //Set first coefficient value
            coEff[0] = pe / PI;

            //Calculate coefficientsw
            for (int i = 1; i <= o2; i++)
            {
                coEff[i] = window[i] * (float)System.Math.Sin(i * pe) * (float)System.Math.Cos(i * ps)  / (i * PI);
            }

            //Shift Impulse
            for (int i = o2 + 1; i <= this.myOrder; i++)
            {
                coEff[i] = coEff[i - o2];
            }
            for (int i = 0; i <= o2 - 1; i++)
            {
                coEff[i] = coEff[this.myOrder - i];
            }
            coEff[o2] = pe / PI;

            return coEff;
        }
        #endregion
    }
}


kel

GeneralRe: Lp,BP,HP filters design in C# Pin
Keleistein12-Apr-07 14:29
Keleistein12-Apr-07 14:29 
GeneralReading text file Pin
kelvinic3-Apr-07 18:19
kelvinic3-Apr-07 18:19 
GeneralRe: Reading text file Pin
BeSoft3-Apr-07 21:17
BeSoft3-Apr-07 21:17 
GeneralRe: Reading text file Pin
kelvinic3-Apr-07 22:08
kelvinic3-Apr-07 22:08 
GeneralRe: Reading text file Pin
BeSoft3-Apr-07 22:56
BeSoft3-Apr-07 22:56 
GeneralRe: Reading text file Pin
kelvinic3-Apr-07 23:00
kelvinic3-Apr-07 23:00 
GeneralRe: Reading text file Pin
BeSoft3-Apr-07 23:29
BeSoft3-Apr-07 23:29 
GeneralRe: Reading text file Pin
kelvinic4-Apr-07 1:55
kelvinic4-Apr-07 1:55 
GeneralRe: Reading text file Pin
BeSoft4-Apr-07 2:36
BeSoft4-Apr-07 2:36 
GeneralRe: Reading text file Pin
Keleistein9-Apr-07 21:59
Keleistein9-Apr-07 21:59 
QuestionSample Question Pin
sides_dale1-Nov-06 18:09
sides_dale1-Nov-06 18:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.