自定义标记解析器不处理换行符

时间:2017-03-05 21:50:19

标签: c# .net parsing

我一直在创建一个自定义标记解析器,以便在我的应用程序中使用。 除非打开和关闭标签位于不同的行上,否则它可以完美运行。

示例:

<test>This is a test</test>

完美无缺,但

<test>
    this
    is
    a
    test
</test>

返回一个空白字符串。

我目前的解决方法是使用[-n]作为字符串中的换行符,并以编程方式将其替换为\n\r。然而,这非常不方便。

using System;
using System.Collections.Generic;

using System.Text.RegularExpressions;

namespace AsysEditor.Classes
{
    /// <summary>
    /// Contains the methods needed to parse a simple XML file
    /// </summary>
    class XMLParser
    {
        /// <summary>
        /// Parses a simple XML file.
        /// </summary>
        /// <remarks>
        /// Does NOT support nested tags.
        /// </remarks>
        /// <param name="xml">The file to parse</param>
        /// <param name="tag">The wanted value</param>
        /// <param name="clean">Remove whitespace</param>
        /// <param name="replaceNewLines">Replace "[-n]" with "\n\r"</param>
        /// <returns></returns>
        public static string Parse(string xml, string tag, bool clean, bool replaceNewLines)
        {
            if (xml == String.Empty || tag == String.Empty) { return "error"; }
            if (!(xml.Contains("<" + tag + ">"))) { return "error"; }

            // Get all XML tags: <tag>
            string _tag = "\\<(.*?)\\>";
            MatchCollection tagMatches = new Regex(_tag).Matches(xml);

            List<string> tags = new List<string>();

            // Add the tag to a list
            foreach (Match m in tagMatches)
            {
                // Clean the tag and add it to the list
                tags.Add(m.Groups[1].Value.Replace("<", string.Empty).Replace(">", string.Empty));
            }

            // Get the value of the tag
            foreach (string h in tags)
            {
                if (!h.Equals(tag)) continue;

                string head = "\\<" + h + "\\>";
                string foot = "\\</" + h + "\\>";

                string contents = new Regex(head + "(.*?)" + foot).Match(xml).Groups[1].Value;

                // Clean the result if nessesary
                if (clean) return contents.Trim();
                else if (replaceNewLines) return contents = Regex.Replace(contents, "\\[-n\\]", "\r\n");
                else return contents;
            }

            return "error";
        }

    }
}

(如果它做了很多不必要的事情,那是因为我以后会扩展功能)

如果有人可以在这里解释我的错误,那将会非常有帮助。

(Also, the entire project is on GitHub)

2 个答案:

答案 0 :(得分:2)

我已将其分解为最简单的形式,即只匹配您要查询的标签内的文字。

以下是示例代码:

const string TAG_REGEX_PATTERN = @"(?:<{0}>)([^<]+?)(?:<\/{0}>)";

public static string Parse(string xml, string tag, bool clean, bool replaceNewLines)
{
    if (xml == String.Empty || tag == String.Empty) { return "error"; }

    MatchCollection tagMatches = new Regex(string.Format(TAG_REGEX_PATTERN, tag), RegexOptions.Multiline | RegexOptions.IgnoreCase).Matches(xml);

    IList<string> tags = new List<string>();

    // Add the tag to a list
    foreach (Match m in tagMatches)
    {
        // Add the tag to the list
        tags.Add(m.Groups[1].Value);
        break; //break as only interested in first result.
    }

    string result = tags.Count == 0 ? null : tags[0];
    if (!string.IsNullOrWhiteSpace(result))
    {
        if (clean)
            result = result.Trim();
        if (replaceNewLines)
            result = result.Replace("\r\n", " ");
    }
    else
        result = "error";
    return result;
}

现在,这将匹配您要查找的标记内的文本,并忽略实际标记。

使用相关标签(使用string.Format())直接格式化正则表达式,并在下面生成正则表达式。

(?:<test>)([^<]+?)(?:<\/test>)

现在我已经将循环留在那里,以防你希望返回所有标签的值。

答案 1 :(得分:1)

RegEx是面向行的。

由于您已经拥有适用于单行输入的内容,请考虑清理输入:

public static string Parse(string xml, string tag, bool clean, bool replaceNewLines)
{
   xml = xml.Replace("\r", "").Replace("\n", " ");
   ...

}