如何解析文本中的多级“节点”?

时间:2009-07-25 01:03:44

标签: c# parsing text

我的配置格式类似于* .sln格式,因此请以下面的示例为例:

DCOM Productions Configuration File, Format Version 1.0

BeginSection:Global
    GlobalKeyA = AnswerOne

    .: Stores the global configuration key
    :: for the application. This key is used
    :: to save the current state of the app.
    :: as well as prevent lockups
    GlobalKey3 = AnswerTwo

    .: Secondary Key. See above setting
    GlobalKeyC = AnswerThree

    BeginSection: UpdateSystem
        NestedKeyA = One
        NestedKeyB = Two
        NestedKeyC = { A set of multiline data
                      where we will show how
                      to write a multiline
                      paragraph }
        NestedKeyD = System.Int32, 100
    EndSection
EndSection

BeginSection:Application
    InstallPath = C:\Program Files\DCOM Productions\BitFlex
EndSection

我知道我需要一个递归函数,可能需要将一段文本作为参数,例如,将整个部分传递给它,并以这种方式递归解析。

我似乎无法理解如何做到这一点。每个部分都可能包含更多子部分。它就像一个Xml文档..我不是真的在这里要求代码,只是一个关于如何解析这样的文档的方法。

我正在考虑使用制表符(指定索引)来确定我正在使用哪个部分,但如果文档没有正确选项卡(格式化),则会失败。还有更好的想法吗?

2 个答案:

答案 0 :(得分:2)

也许您可以在此格式和XML之间绘制并行。 即 BeginSection< ==> “< opening>” EndSection< ==> “< / closing>”

将其视为具有许多根元素的XML文件。 例如,BeginSection和EndSection中的内容将是您的内部xml节点 NestedKeyA =作为节点名称,“One”作为值。

:似乎是评论,所以你可以跳过它。 System.Int32,100-可以是属性和节点的值

{一组多行数据    我们将在哪里展示如何    写一条多线    段落} - 你也可以用算法来解析它。

答案 1 :(得分:0)

好的,我做到了。 * phew *

/// <summary>
/// Reads and parses xdf strings
/// </summary>
public sealed class XdfReader {
    /// <summary>
    /// Instantiates a new instance of the DCOMProductions.BitFlex.IO.XdfReader class.
    /// </summary>
    public XdfReader() {
        //
        // TODO: Any constructor code here
        //
    }

    #region Constants

    /// <devdoc>
    /// This regular expression matches against a section beginning. A section may look like the following:
    /// 
    ///     SectionName:Begin
    ///     
    /// Where 'SectionName' is the name of the section, and ':Begin' represents that this is the
    /// opening tag for the section. This allows the parser to differentiate between open and
    /// close tags.
    /// </devdoc>
    private const String SectionBeginRegularExpression = @"[0-9a-zA-Z]*:Begin";

    /// <devdoc>
    /// This regular expression matches against a section ending. A section may look like the following:
    /// 
    ///     SectionName:End
    ///     
    /// Where 'SectionName' is the name of the section, and ':End' represents that this is the
    /// closing tag for the section. This allows the parser to differentiate between open and
    /// close tags.
    /// </devdoc>
    private const String SectionEndRegularExpression = @"[0-9a-zA-Z]*:End";

    /// <devdoc>
    /// This regular expression matches against a key and it's value. A key may look like the following:
    /// 
    ///     KeyName=KeyValue
    ///     KeyName = KeyValue
    ///     KeyName =KeyValue
    ///     KeyName= KeyValue
    ///     KeyName    =       KeyValue
    ///                 
    /// And so on so forth. This regular expression matches against all of these, where the whitespace
    /// former and latter of the assignment operator are optional.
    /// </devdoc>
    private const String KeyRegularExpression = @"[0-9a-zA-Z]*\s*?=\s*?[^\r]*";

    #endregion

    #region Methods

    public void Flush() {
        throw new System.NotImplementedException();
    }

    private String GetSectionName(String xdf) {
        Match sectionMatch = Regex.Match(xdf, SectionBeginRegularExpression);

        if (sectionMatch.Success) {
            String retVal = sectionMatch.Value;
            retVal = retVal.Substring(0, retVal.IndexOf(':'));
            return retVal;
        }
        else {
            throw new BitFlex.IO.XdfException("The specified xdf did not contain a valid section.");
        }
    }

    public XdfFile ReadFile(String fileName) {
        throw new System.NotImplementedException();
    }

    public XdfKey ReadKey(String xdf) {
        Match keyMatch = Regex.Match(xdf, KeyRegularExpression);

        if (keyMatch.Success) {
            String name = keyMatch.Value.Substring(0, keyMatch.Value.IndexOf('='));
            name = name.TrimEnd(' ');

            XdfKey retVal = new XdfKey(name);

            String value = keyMatch.Value.Remove(0, keyMatch.Value.IndexOf('=') + 1);
            value = value.TrimStart(' ');

            retVal.Value = value;
            return retVal;
        }
        else {
            throw new BitFlex.IO.XdfException("The specified xdf did not contain a valid key.");
        }
    }

    public XdfSection ReadSection(String xdf) {
        if (ValidateSection(xdf)) {
            String[] rows = xdf.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            XdfSection rootSection = new XdfSection(GetSectionName(rows[0])); System.Diagnostics.Debug.WriteLine(rootSection.Name);

            do {
                Match beginMatch = Regex.Match(xdf, SectionBeginRegularExpression);
                beginMatch = beginMatch.NextMatch();

                if (beginMatch.Success) {
                    Match endMatch = Regex.Match(xdf, String.Format("{0}:End", GetSectionName(beginMatch.Value)));

                    if (endMatch.Success) {
                        String sectionXdf = xdf.Substring(beginMatch.Index, (endMatch.Index + endMatch.Length) - beginMatch.Index);
                        xdf = xdf.Remove(beginMatch.Index, (endMatch.Index + endMatch.Length) - beginMatch.Index);

                        XdfSection section = ReadSection(sectionXdf); System.Diagnostics.Debug.WriteLine(section.Name);

                        rootSection.Sections.Add(section);
                    }
                    else {
                        throw new BitFlex.IO.XdfException(String.Format("There is a missing section ending at index {0}.", endMatch.Index));
                    }
                }
                else {
                    break;
                }
            } while (true);

            MatchCollection keyMatches = Regex.Matches(xdf, KeyRegularExpression);

            foreach (Match item in keyMatches) {
                XdfKey key = ReadKey(item.Value);
                rootSection.Keys.Add(key);
            }

            return rootSection;
        }
        else {
            throw new BitFlex.IO.XdfException("The specified xdf did not contain a valid section.");
        }
    }

    private Boolean ValidateSection(String xdf) {
        String[] rows = xdf.Split(new String[] { "\r\n" }, StringSplitOptions.None);

        if (Regex.Match(rows[0], SectionBeginRegularExpression).Success) {
            if (Regex.Match(rows[rows.Length - 1], SectionEndRegularExpression).Success) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }

    #endregion
}

}