混合テキストでイタリックを反転させる正しいアルゴリズムは何ですか?


8

質問の動機は、以下のセクションに描かれています。テキストをイタリックにする方法たくさんあるので、おそらく、「イタリックスワップアルゴリズム」は複数あるでしょう。この問題は、XHTMLコードの追加の難しさ、および<i>タグの使用を明らかにします。例:

 <!-- original text: -->
 <p id="p1"><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
 <!-- same text, swapping italics: -->
 <p id="p2">Several more <i>Homo sapiens</i> fossils were discovered.</p>

このように見えます

  1. さらにいくつかのヒトの化石が発見されました

  2. さらにいくつかのヒトの化石が発見されました。


アルゴリズムの紹介と議論

レイアウトソリューション」の場合、最も簡単なアルゴリズムはfont-style、すべてのテキストブロックのCSSプロパティをチェックし、jQueryで反転します。

$('#myFragment *').each(function(){
   if ($(this).css('font-style')=='italic')
       $(this).css('font-style','normal')
    else
       $(this).css('font-style','italic')        
}); 

しかし、このアルゴリズムはもう少し複雑なテストには耐えられません。

 <p id="p3"><b><i>F</i>RAGMENT <big><i>with italics</i> and </big> withOUT.</b></p>

2番目に単純なアルゴリズムは具体的なソリューションであり、「例」セクションで使用されました。2つのステップがあります。

  1. XHTMLフラグメントをイタリック体で囲みます。
  2. イタリックタグの開閉を反転します(例:</i>から<i>)。

つまり、Javascriptで書く、

var s = '... a fragment of XHTML content ...';
s = '<i>'+
   s.replace(/<(\/?)i>/mg, 
          function (m,p1){
              return p1? '<i>': '</i>';
          }
   ) +
   '</i>';  

しかし、タグのバランスを失い、2番目のテストにも耐えられません...「修正された」アルゴリズムは実行されますが(!)、移植性がなく、高速でもエレガントでもありません。それは 、ここでdemonstred、および以下の例のセクションで。

ポイント!

だから問題は、

シンプルで優れた一般的な(任意のブラウザーで使用可能で、他の言語に移植可能な)アルゴリズムはありますか? あなたは別の「スワップイタリックアルゴリズム」を知っていますか?

PS:私があなたのアルゴリズムをXSLTに変換するという意味での「一般的な」。アルゴリズム、直接バランスのとれたXHTMLコードを生成する必要があります(Tidyのような中間ブラックボックスなしで)。


動機

「イタリックスワップアルゴリズム」をテキストエディター、サーバーパーサーなどに移植する必要があります。すべてのケースで、標準のXHTMLと<i>タグによって「入力(および出力)を正規化」できます。

散文の本や科学記事のXHTMLテキストを解析しています。さまざまな出所やスタイルからエクスポートされています...ほとんどのテキストは「通常のテキスト」としてエクスポートされますが、タイトル(例:記事のタイトル、章のタイトル)が多く、場合によっては、完全な章または完全なテキストボックス(記事の要約など)は、イタリック体で様式化されています。これらの「イタリック体で様式化された」すべてを逆にする必要があります。典型的なケース:

  • 元の「すべての章の斜体」を「すべての章の通常のテキスト」に変換します。このケースを参照してください。約300ページの本では、25の章のうち8つの章を反転する必要があります。

  • 斜体の引用符、要約など。この例を参照してください。通常に戻す必要がありますが、強調の言葉を失うことはありません。

  • ライティング種の二項名前を、科学的な文章で、通常(「通常のテキスト」のために使用されたものからフォント異なる中で、または反転)、イタリックでタイプセットされています。XHTMLでエクスポートされた記事の(記事および記事セクションの)イタリック体の何百ものタイトルを私の職場で反転させる必要があります。PS:質問の冒頭の例を参照してください(「さらにいくつかのホモサピエンス ...」)。

(答えの)汎用アルゴリズムをXSLTライブラリ変換する必要もあります。この場合、「タグバランシング修正」は存在しません。

JavaScriptとPHPで非一般的な「スワップイタリックアルゴリズム」を実装します。一般的なものには、一般的な「XMLインターリーブアルゴリズム」が必要です...ここでは、「インターリーブ」の代わりに、ブラウザー(DOM)とTidyの修正を使用しています。

Javascript

複雑な入力(!)で実行されます。jQuery実装による説明

 var s = $('#sample1').html(); // get original html text fragment

 // INVERSION ALGORITHM: add and remove italics.
 s = "<i>"+
     s.replace(/<(\/?)i>/mg, 
               function (m,p1){
                   return p1? '<i>': '</i>';
               }
     ) +
     "</i>";  // a not-well-formed-XHTML, but it is ok...
 $('#inverted').html(s); // ...the DOM do all rigth!
 // minor corrections, for clean empties:
 s = $('#inverted').html();
 s = s.replace(/<([a-z]+)>(\s*)<\/\1>/mg,'$2'); // clean
 s = s.replace(/<([a-z]+)>(\s*)<\/\1>/mg,'$2'); // clean remain
 $('#inverted').html(s);  
 // END ALGORITHM

 alert(s);

PHP、Tidy

PHPに「変換」されたJavascriptと同じ—自然な変換はDOMDocument()クラスとloadHTML/ saveXMLメソッドを使用しますが、ブラウザの対応するものと同じ動作をするのはtidyクラスです。同じ結果を表示します(!)

 $sample1='<b><i>O</i>RIGINAL <big><i>with italics</i> and </big> withOUT</b>';
 $inverted = '... inverted will be here ...';
 echo $sample1;
 // Tidy correction
 $s = $sample1; // get original html text fragment
  // INVERSION ALGORITHM: add and remove italics.
  $s = "<i>".
      preg_replace_callback('/<(\/?)i>/s', function ($m){
       return $m[1]? '<i>': '</i>';}, $s) .
      "</i>";  // a not-well-formed-XHTML, but it is ok...
  $config = array('show-body-only'=>true,'output-xhtml'=>true);
  $tidy = new tidy;
  $tidy->parseString($s, $config, 'utf8');
  $s = $tidy;  // ... because Tidy corrects!     
  // minor corrections, for clean empties:
  $s = preg_replace('/<([a-z]+)>(\s*)<\/\1>/s', '$2', $s); // clean
  $s = preg_replace('/<([a-z]+)>(\s*)<\/\1>/s', '$2', $s); // clean remain
  // END ALGORITHM
  echo "\n\n$s";

この質問の表と裏は作れません。分かりますか?多分それを本質的なポイントに短くしますか?
ボブソン2013年

重要なポイントは、ビュレットとボールドにあります...編集して、質問の最初に置くか、より強調することができますか?
Peter Krauss 2013年

質問文全体を書き直し、具体的な問題により焦点を当てました。
Peter Krauss

これがディスプレイ(?)だけの場合は、ページのCSSを変更して、デフォルトをイタリックにし、タグ内の部分をイタリックにしませんか?

ハム...「表示用」ではなく、最終的な出力はPMCのような最終的なデータベースです。「やる気」のセクションを編集しました。
Peter Krauss 2013年

回答:


2

更新(2013年6月18日):この回答を使用してアルゴリズムを説明し、結論を要約します。


jQueryトラバースと「レイアウトソリューション」の回避策について。

@Wilbertのコメントの後check .prop().each()反復によって変化するの動的な動作を回避するために、「最も単純なアルゴリズム」を採用し、を削除しましたelse。すべての反復の後、「親イタライザ」が解決します。ここまたは以下のコードを参照してください

$('#myFragment *').each(function(){
   if ($(this).css('font-style')=='italic')
       $(this).css('font-style','normal');
});
$('#myFragment').parent().css('font-style','italic');

動的な振る舞いを処理する別の方法はprop('tagName')、変更されない静的プロパティをでチェックすることです。 ここまたは以下のコードを参照してください

$('#myFragment').parent().css('font-style','italic');
$('#myFragment *').each(function(){
   if ($(this).prop('tagName')=='I')  // not changes with parent
       $(this).css('font-style','normal');
});

より多くのテストが必要であり、スタイルプロパティを具象<i>タグに変更するには、最終的な解析が必要です。アルゴリズムを2回適用するには、注意が必要です。


レイアウトソリューション

これは現在の質問の解決策ではありませんが、いくつかの良い手がかりを生み出し、「レイアウト問題」の最良の(少なくとも最小!)解決策です!

このtoggleClass()メソッドは、「イタリック体のクラス」から「通常のテキストクラス」にスワップするために使用できます。 ここまたは以下のコードを参照してください

 $('#myFragment *').each(function(){
     $(this).toggleClass( "original change");
 });

そして、この小さなアルゴリズムを2回、そして何度でも適用できます...これは良い解決策です!しかし、これは「書き換えXMLアルゴリズム」ではなく、CSSが重要です

 .original { font-style:normal; } /* use class="original" in your XHTML fragment */
i.original { font-style:italic; }

 .change { font-style:italic; }
i.change{ font-style:normal; }

...したがって、<i>タグを変換するアルゴリズムの場合、問題は未解決のままです...

具体的な解決策

「100%の溶液は、純粋なXSLT1に」(多くの場合でテスト!)に基づいて、@ DanielHaleyさんの適応。効果的な<i>タグ変換です。

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="p"/>

<xsl:template match="@*|node()"> <!-- copy all -->
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="i"> <!-- remove tag i -->
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="text()[not(ancestor::i)]"> <!-- inlcude tag i -->
    <i><xsl:copy-of select="."/></i>
</xsl:template>
 </xsl:stylesheet>

コピープロセスの「ドライブバイイベントアルゴリズム」としての概要:

  • 削除iタグ:「の任意のものをコピー<i> ものを </i>」と「もの」。

  • iタグを含める:テキストがイタリックの親のコンテキストにない場合、テキストを「<i> テキスト </i>」としてコピーします。PS:テキストはDOMツリーのターミナルノードです。

結論

「レイアウトソリューション」はテキストエディタに適していますが、いくつかのトリックと厳密でないソリューションを使用しています(オーバーラップ、パフォーマンスなどは関係ありません)。XMLプロセスでは、<i>タグ変換を処理する必要があります...したがって、アルゴリズムを表現するための自然言語はXSLTまたはxQueryです。

XSLTで実装されたアルゴリズムは、フレームワークの必要性を示しています。

  1. 祖先が「斜体コンテキスト」であるかどうチェックの(親、祖父母、等)の選択、。

  2. テキストノード(DOM text())アクセス。

  3. iタグを削除して含めます。

したがって、各フレームワークの問題を確認できます。

  • DOM(W3C標準フレームワーク):DOMDocument::renameNode()項目3のはまだ実装されていません(PHP、Javascriptなどを参照)。

  • jQuery:項目2には便利な関数がありません。この回答を参照してください。

  • XSLT:アルゴリズムを表現するのに最適ですが、JavaScriptなどのコンテキストでは使用できません。

私(またはあなたが言いました!)は、「純粋なDOM2」メソッドでXSLTアルゴリズムを表現しようとします。そのDOMバージョンは「一般的なアルゴリズム」になります...さて:変換がDOM3に対してのみ有効である場合(renameNodeおよびその他のトリックを使用)、現時点での結論は「一般的な/翻訳可能なアルゴリズムは存在しない」ということです。


1

https://stackoverflow.com/a/17156452/317052からのXSLT試行...

これがすべてのケースをカバーするかどうかはわかりませんが、これを行うことができます:

XML入力

<html>
    <!-- original text: -->
    <p id="p1"><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
    <!-- same text, swapping italics: -->
    <p id="p2">Several more <i>Homo sapiens</i> fossils were discovered.</p>
    <p>Leave me alone!</p>
    <p><b><i>O</i>RIGINAL <big><i>with italics</i> and </big> withOUT</b></p>
</html>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[i]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()" mode="swapItal"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="text()" mode="swapItal" priority="1">
        <i><xsl:value-of select="."/></i>
    </xsl:template>

    <xsl:template match="i" mode="swapItal">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="@*|node()" mode="swapItal">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" mode="swapItal"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML出力

<html>
   <!-- original text: -->
   <p id="p1">Several more<i> Homo sapiens </i>fossils were discovered<i>.</i></p>
   <!-- same text, swapping italics: -->
   <p id="p2"><i>Several more </i>Homo sapiens<i> fossils were discovered.</i></p>
   <p>Leave me alone!</p>
   <p><b>O<i>RIGINAL </i><big>with italics<i> and </i></big><i> withOUT</i></b></p>
</html>

入力レンダリング

さらにいくつかのヒトの化石が発見されました

さらにいくつかのヒトの化石が発見されました。

ほっといて!

O RIGINAL イタリック体でとせずに


レンダリングされた出力

さらにいくつかのヒトの化石が発見されました

さらにいくつかのヒトの化石が発見されました。

ほっといて!

O RIGINALイタリック体でせずに


こんにちは、どうもありがとう!Stackoverflowでは、「完全なXSLT」にいくつかの小さな修正を加える必要があることをすでに説明したので、私の答えにXSLTの適応を追加します。ここでも、XSLTは「アルゴリズムの描写」または一般的な翻訳の手がかりがない限り「最終的な回答」ではありません(「要点」セクションを参照)...したがって、すべての賞金を受け取ることはできません。このサイトのバウンティルールにより、バウンティの50%を受け取ることができることを理解して、あなたに1票を追加します...このルールについて私が間違っていないかどうか確認してください。
Peter Krauss 2013年

-1

私は単に:

  1. すべての変換<i></i>複数可
  2. すべての変換</i><i>複数可
  3. <i>先頭にを追加
  4. </i>最後にを追加

そう

 <p id="p1"><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
 <!-- converts to: -->
 <i><p id="p2">Several more </i>Homo sapiens<i> fossils were discovered.</p></i>

1
はい、例(「例」のセクションを参照)がJavascriptおよびPHPで「正規表現置換」関数を使用して行っていることとまったく同じです。jsfiddle.net/rdfJ5というリンクもあります...しかし、残念ながら、これは一般的な解決策ではありません<b><i>O</i>RIGINAL <big><i>with italics</i> and </big> withOUT</b>。このケースで段階的にテストしてください...不均衡な(禁止された)コードと空のブロックが生成されます。
Peter Krauss 2013年

@PeterKraussなので、これはあなたにとって十分ではありませんか?どうしたの?
Morons 2013年

1
(私はコメントを編集しました。ステップバイステップが失敗する例を参照してください!)「要点」のセクションを参照してください。一般的ではなく、XSLTで使用したり、ライブラリで再利用したりすることはできません。
Peter Krauss 2013年

<i><b></i>O<i>RIGINAL <big></i>with italics<i> and </big> withOUT</b></i>プリティではないかもしれませんが、すべてのブラウザで機能します
Morons

1
「バランス」または「整形式」とは何かを理解しているかどうかを確認してください。一部のリンク:ウィキペディアW3C ... ルールの合成:「すべてのタグはバランスを取る必要があります」。<i><b></i>そうではなく、ALL DISCUSSION HEREは「バランスの取れた結果を生成するアルゴリズム」に関するものです。
Peter Krauss 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.