6

見出しでごめんなさい...

クリップボードからテキストを抽出したいと思います。このテキストは、(ブラウザの)Webページからコピーされます。私の場合、それはいくつかのデータを含むテーブルです。

だから私は次のコードでデータ(文字列として来る)を抽出しました:

IDataObject iData = Clipboard.GetDataObject();

if (iData.GetDataPresent(DataFormats.Html))
{
    string s = (string)iData.GetData(DataFormats.Html);
}

そして、私がそこから得たもの(sに含まれているもの)は次のとおりです。

Version:0.9
StartHTML:0000000397
EndHTML:0000004086
StartFragment:0000000433
EndFragment:0000004050
SourceURL:Bla Bla Bla
<html>
<body>
<!--StartFragment--><table class="listing tickets">Bla Bla Bla</table><!--EndFragment-->
</body>
</html>

だから、もう一度。このデータを解析する標準クラスはありますか、それとも自分で作成する必要がありますか?

4

2 に答える 2

8

OK、それで答えはノーのようです!びっくりしました...

ともかく。私はあなたを助けることができるかもしれない私自身のヘルパークラスを作りました。これは、考えられる多くの解決策の1つにすぎません。私のアプリケーションでは、何も見つからない場合にnullを返すとうまく機能します。代わりに、例外が必要な場合があります。また、これはサイドプロジェクトとして作成しているため、コードの広範なテストは行われず、したがって、これが機能することを保証するものではないことにも注意してください。

public class ClipboardHtmlOutput
{
    public Double Version { get; private set; }
    public String Source { get; private set; }
    public String Input { get; private set; }
    //public String Html { get { return Input.Substring(startHTML, (endHTML - startHTML)); } }
    public String Html { get { return Input.Substring(startHTML, Math.Min(endHTML - startHTML, Input.Length - startHTML)); } }
    public String Fragment { get { return Input.Substring(startFragment, (endFragment - startFragment)); } }

    private int startHTML;
    private int endHTML;
    private int startFragment;
    private int endFragment;

    public static ClipboardHtmlOutput ParseString(string s)
    {
        ClipboardHtmlOutput html = new ClipboardHtmlOutput();

        string pattern = @"Version:(?<version>[0-9]+(?:\.[0-9]*)?).+StartHTML:(?<startH>\d*).+EndHTML:(?<endH>\d*).+StartFragment:(?<startF>\d+).+EndFragment:(?<endF>\d*).+SourceURL:(?<source>f|ht{1}tps?://[-a-zA-Z0-9@:%_\+.~#?&//=]+)";
        Match match = Regex.Match(s, pattern, RegexOptions.Singleline);

        if (match.Success)
        {
            try
            {
                html.Input = s;
                html.Version = Double.Parse(match.Groups["version"].Value, CultureInfo.InvariantCulture);
                html.Source = match.Groups["source"].Value;
                html.startHTML = int.Parse(match.Groups["startH"].Value);
                html.endHTML = int.Parse(match.Groups["endH"].Value);
                html.startFragment = int.Parse(match.Groups["startF"].Value);
                html.endFragment = int.Parse(match.Groups["endF"].Value);
            }
            catch (Exception fe)
            {
                return null;
            }
            return html;
        }
        return null;
    }
}

使用法は次のようになります。

IDataObject iData = Clipboard.GetDataObject();

if (iData.GetDataPresent(DataFormats.Html))
{
    ClipboardHtmlOutput cho = ClipboardHtmlOutput.ParseString((string)iData.GetData(DataFormats.Html));
    XmlDocument xml = new XmlDocument();
    xml.LoadXml(cho.Fragment);
}
于 2013-01-31T07:25:46.467 に答える
4

次の方法は、Microsoftのアプローチです。このメソッドは、 https://code.msdn.microsoft.com/windowsdesktop/XAML-to-HTML-Conversion-ed25a674/view/SourceCodeからダウンロードできるサンプル「XAMLからHTMLへの変換デモ」のクラスHtmlParserに含まれています。

「HTMLクリップボード形式」に関する追加情報は、https ://msdn.microsoft.com/en-us/library/aa767917(v = vs.85).aspxにあります。

/// <summary>
/// Extracts Html string from clipboard data by parsing header information in htmlDataString
/// </summary>
/// <param name="htmlDataString">
/// String representing Html clipboard data. This includes Html header
/// </param>
/// <returns>
/// String containing only the Html data part of htmlDataString, without header
/// </returns>
internal static string ExtractHtmlFromClipboardData(string htmlDataString)
{
    int startHtmlIndex = htmlDataString.IndexOf("StartHTML:");
    if (startHtmlIndex < 0)
    {
        return "ERROR: Urecognized html header";
    }
    // TODO: We assume that indices represented by strictly 10 zeros ("0123456789".Length),
    // which could be wrong assumption. We need to implement more flrxible parsing here
    startHtmlIndex = Int32.Parse(htmlDataString.Substring(startHtmlIndex + "StartHTML:".Length, "0123456789".Length));
    if (startHtmlIndex < 0 || startHtmlIndex > htmlDataString.Length)
    {
        return "ERROR: Urecognized html header";
    }

    int endHtmlIndex = htmlDataString.IndexOf("EndHTML:");
    if (endHtmlIndex < 0)
    {
        return "ERROR: Urecognized html header";
    }
    // TODO: We assume that indices represented by strictly 10 zeros ("0123456789".Length),
    // which could be wrong assumption. We need to implement more flrxible parsing here
    endHtmlIndex = Int32.Parse(htmlDataString.Substring(endHtmlIndex + "EndHTML:".Length, "0123456789".Length));
    if (endHtmlIndex > htmlDataString.Length)
    {
        endHtmlIndex = htmlDataString.Length;
    }

    return htmlDataString.Substring(startHtmlIndex, endHtmlIndex - startHtmlIndex);
}

2015年2月25日追加

私の実装に続いて。UTF-8に注意する必要がありました(メソッドのatとを参照)

/// <summary>
/// Extracts selected Html fragment string from clipboard data by parsing header information 
/// in htmlDataString
/// </summary>
/// <param name="htmlDataString">
/// String representing Html clipboard data. This includes Html header
/// </param>
/// <returns>
/// String containing only the Html selection part of htmlDataString, without header
/// </returns>
internal static string ExtractHtmlFragmentFromClipboardData(string htmlDataString)
{
    // HTML Clipboard Format
    // (https://msdn.microsoft.com/en-us/library/aa767917(v=vs.85).aspx)

    // The fragment contains valid HTML representing the area the user has selected. This 
    // includes the information required for basic pasting of an HTML fragment, as follows:
    //  - Selected text. 
    //  - Opening tags and attributes of any element that has an end tag within the selected text. 
    //  - End tags that match the included opening tags. 

    // The fragment should be preceded and followed by the HTML comments <!--StartFragment--> and 
    // <!--EndFragment--> (no space allowed between the !-- and the text) to indicate where the 
    // fragment starts and ends. So the start and end of the fragment are indicated by these 
    // comments as well as by the StartFragment and EndFragment byte counts. Though redundant, 
    // this makes it easier to find the start of the fragment (from the byte count) and mark the 
    // position of the fragment directly in the HTML tree.

    // Byte count from the beginning of the clipboard to the start of the fragment.
    int startFragmentIndex = htmlDataString.IndexOf("StartFragment:");
    if (startFragmentIndex < 0)
    {
        return "ERROR: Unrecognized html header";
    }
    // TODO: We assume that indices represented by strictly 10 zeros ("0123456789".Length),
    // which could be wrong assumption. We need to implement more flrxible parsing here
    startFragmentIndex = Int32.Parse(htmlDataString.Substring(startFragmentIndex + "StartFragment:".Length, 10));
    if (startFragmentIndex < 0 || startFragmentIndex > htmlDataString.Length)
    {
        return "ERROR: Unrecognized html header";
    }

    // Byte count from the beginning of the clipboard to the end of the fragment.
    int endFragmentIndex = htmlDataString.IndexOf("EndFragment:");
    if (endFragmentIndex < 0)
    {
        return "ERROR: Unrecognized html header";
    }
    // TODO: We assume that indices represented by strictly 10 zeros ("0123456789".Length),
    // which could be wrong assumption. We need to implement more flrxible parsing here
    endFragmentIndex = Int32.Parse(htmlDataString.Substring(endFragmentIndex + "EndFragment:".Length, 10));
    if (endFragmentIndex > htmlDataString.Length)
    {
        endFragmentIndex = htmlDataString.Length;
    }

    // CF_HTML is entirely text format and uses the transformation format UTF-8
    byte[] bytes = Encoding.UTF8.GetBytes(htmlDataString);
    return Encoding.UTF8.GetString(bytes, startFragmentIndex, endFragmentIndex - startFragmentIndex);
}
于 2015-02-21T06:57:23.297 に答える