5

解析する必要がある不適切な形式の XML があります。上流で問題を修正することはできません。

(現在の) 問題は、アンパサンド文字が常に適切にエスケープされるとは限らないため、次のように変換する必要があることです&&

が既にある場合&amp;は、に変更したくありません&amp;amp;。一般に、整形式のエンティティが既にそこにある場合、それを破棄したくありません。一般に、特定の XML 文書に現れる可能性のあるすべてのエンティティーを知ることは不可能だと思います&<characters>;

<characters>イニシャル&とクロージングの間のエンティティを定義する文字のセットはどこにありますか;。特に、<and>は、そうでなければ XML 要素を表すリテラルではありません。

ここで、解析中に&<characters>;a (スペース)、行末、または別の&. <characters>なので原作をどうするか教えてくれるキャラクターを先を見ながら覚えておかなければいけないと思います&

これを行うには、プッシュ ダウン オートマトンの力が必要だと思います。メモリ要件があると考えられるため、Finite State Machine が機能するとは思いません。それは正しいですか? PDA が必要な場合、呼び出しの正規表現は機能しString.replaceAll(String, String)ません。または、この問題を解決できる Java 正規表現はありますか?

注意: 1 行に複数の置換がある可能性があります。

(私はこの質問を認識していますが、私が探している答えを提供していません。)

4

6 に答える 6

8

探している正規表現は次のとおりです。&([^;\\W]*([^;\\w]|$))、対応する置換文字列は。になります&amp;$1。に一致し&、その後にゼロ個以上の非セミコロンまたは単語区切り(スタンドアロンのアンパサンドに一致するようにゼロを許可する必要があります)が続き、その後にセミコロン(または行末)ではない単語区切りが続きます。&amp;キャプチャグループを使用すると、探しているものと置き換えることができます。

これを使用したサンプルコードは次のとおりです。

String s = "&amp; & &nsbp; &tc., &tc. &tc";
final String regex = "&([^;\\W]*([^;\\w]|$))";
final String replacement = "&amp;$1";
final String t = s.replaceAll(regex, replacement);

これをサンドボックスで実行した後、tに対して次の結果が得られます。

&amp; &amp; &nsbp; &amp;tc., &amp;tc. &amp;tc

ご覧のとおり、オリジナル&amp;と変更はあり&nbsp;ません。ただし、「&&」で試してみると、が得られ&amp;&、「&&&」で試してみると、が得られます&amp;&&amp;。これは、ほのめかしていた先読み問題の兆候だと思います。ただし、行を置き換える場合:

final String t = s.replaceAll(regex, replacement);

と:

final String t = s.replaceAll(regex, replacement).replaceAll(regex, replacement);

それはそれらのすべての文字列と私が考えることができる他の文字列で動作します。replaceAll(完成品では、おそらく、この2回の呼び出しを行う単一のルーチンを作成します。)

于 2011-07-11T23:41:14.827 に答える
5

先読みを使用して、&文字の後に文字とセミコロンが続くかどうかを確認することもできると思います (例: &(?!\w+;))。次に例を示します。

import java.util.*;
import java.util.regex.*;

public class HelloWorld{
    private static final Pattern UNESCAPED_AMPERSAND =
        Pattern.compile("&(?!(#\\d+|\\w+);)");
     public static void main(String []args){
        for (String s : Arrays.asList(
            "http://www.example.com/?a=1&b=2&amp;c=3/",
            "Three in a row: &amp;&&amp;",
            "&lt; is <, &gt; is >, &apos; is ', etc."
        )) {
            System.out.println(
                UNESCAPED_AMPERSAND.matcher(s).replaceAll("&amp;")
            );        
        }
     }
}

// Output:
// http://www.example.com/?a=1&amp;b=2&amp;c=3/
// Three in a row: &amp;&amp;&amp;
// &lt; is <, &gt; is >, &apos; is ', etc.
于 2014-04-14T21:47:05.920 に答える
2

エンティティに関する文法を理解することから始めます: http://www.w3.org/TR/xml/#NT-EntityRef

次に、JavaDoc を参照してくださいFilterInputStream: http://download.oracle.com/javase/6/docs/api/java/io/FilterInputStream.html

次に、実際の入力を 1 文字ずつ読み取るものを実装します。アンパサンドが検出されると、「エンティティ モード」に切り替わり、有効なエンティティ参照 ( & Name ;) を探します。で許可されていない最初の文字の前に 1 つ見つかった場合はName、それをそのまま出力に書き込みます。それ以外の場合は&amp;、アンパサンドの後にすべてが続きます。

于 2011-07-11T18:29:19.443 に答える
1

考えられるすべての不良データに対して一般的に何かをしようとするのではなく、不良データの発生を一度に1つずつ処理します。XMLを生成しているものはすべて、1文字または2文字を台無しにしている可能性がありますが、すべてのemを台無しにしているわけではありません。もちろんこれは前提です。

&の後にamp;が続く場合を除いて、すべての&を&に置き換えてみてください。次に遭遇する不適切にエンコードされた文字が<の場合は、それらをすべて<に置き換えます。ルールセットを小さく管理しやすくし、間違っていることがわかっていることだけを処理します。

多くのことを行おうとすると、意図していなかったものを置き換えて、自分でデータを台無しにしてしまう可能性があります。

また、最善の解決策は、XMLを作成している人に、自分の側でエンコーディングを修正するように勧めることです。これは質問するのが難しいかもしれませんが、専門的に、彼らが有効なXMLを生成していないことを彼らに説明すると、彼らはバグを修正することをいとわないかもしれません。これには、ソースで解決する必要のある問題を回避するためにクレイジーなカスタムコードを実行する必要がなく、それを消費しなければならない次の人の追加の利点があります。少なくともそれを考慮してください。起こりうるさらに悪いことは、あなたが尋ねると、彼らはノーと言い、あなたは今いる場所にいるということです。

于 2011-07-11T18:22:10.173 に答える
0

上記のソリューションを使用しましたUNESCAPED_AMPERSANDが、正規表現を次のように変更する必要がありました

private static final Pattern UNESCAPED_AMPERSAND =
        Pattern.compile("&(?!(#\\d+|#x[0-9a-fA-F]+|\\w+);)");

|#x[0-9a-fA-F]+16 進文字参照を考慮して追加します。

(その解決策についてコメントしたかったのですが、明らかにできません。)

于 2020-09-17T20:11:56.363 に答える