2017-03-05 2 views
2

私のアプリケーションで使用するカスタムマークアップパーサーを作成しています。 開始タグと終了タグが別々の行になければ、完璧に動作します。カスタムマークアップパーサーが改行を処理していません

例:

<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)

+3

カスタムxmlプロセッサを使用する理由は何ですか? [Linq to Xml](https://msdn.microsoft.com/en-au/library/mt693072.aspx)は非常に高速で、信頼性が高く、使い方も簡単です。 – Nico

+2

準拠のXMLパーサを書くことはこれよりはるかに難しいですが、それは解決された問題です。ホイールを再構築しないでください。実績のあるXML解析ライブラリを使用します。 – kjhughes

+0

@Nico実際にはXMLではなく、構文タイプを使用しているためです。私が読んでいるファイルは次のとおりです:https://dl.dropboxusercontent.com/u/276558657/Asys/asys.txt正規表現を使うのは簡単なファイルなので、これは簡単です – criticaldiamonds

答えて

1

正規表現は、行指向です。

すでに単一行入力のために働く何かを持っているので、あなたの入力清掃考える:私はその最も単純な形式にこれを分解していると、それはタグ内のテキストだけを照合することによってである

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

} 
+0

私は、私はそれを認識していないことを確認します。ありがとう。これを少し修正し、 '\ n'を' [-n] 'に置き換えました。結果は' \ n'に変換され、結果が確定した後に '\ n'に戻されます。 – criticaldiamonds

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>) 

ここでは、すべてのタグの値を返す場合に備えてループを残しました。

+0

ありがとう!私は他の答えを使用して終了しましたが、私はこの問題にどのように取り組むべきかについていくつかの洞察を与えました。 :) – criticaldiamonds

関連する問題