2016-06-29 9 views
0

動的に作成された電子メールテンプレートのサムネイルに埋め込みのYouTube動画を置き換えようとしています。埋め込まれた各URLから各YouTube IDを見つけようとしていて、ブロック全体をカスタムHTMLに置き換えようとしています。複数のビデオがある場合HTML(Ruby)でURLパラメータを検索するRegex

<span contenteditable="false" draggable="true" fr-original-class="fr-video\sfr-dvb\sfr-draggable"\s.*\ssrc="[a-z:]*?\/\/w{3}?.?youtube.com\/embed\/([a-zA-Z\d\-]*).*<\/iframe><\/span> 

問題は、ですが、それが唯一の最後のビデオからIDを検索します:私は、次の正規表現を持つ唯一の1つの埋め込み動画がある場合、それは働いています。私はこれを過度に複雑にしているように感じる。

埋め込みビデオが入っているスパンの属性は、常に同じであることに注意してください(contenteditable="false" draggable="true" fr-original-class="fr-video)。

サンプルのメールテンプレートは以下のとおりです。上記の正規表現は、最初のIDではなく、2番目のIDのみを取得します。私は両方を引っ張りたい。

これはRubyで行われています。

編集:私はおそらく残虐ですが、私はgsubのために複雑なRegExが必要なので、私はビデオとそれを囲むものではなく、コンテナで置き換える必要があります。

<!DOCTYPE html> 
<html> 
    <head> 
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'> 
    </head> 
    <body style='margin: 0px; font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 18px;'> 
    <table border='0' cellpadding='0' cellspacing='0' style='font-family: Helvetica Neue,Helvetica,Arial,sans-serif; width: 600px;' width='600'> 
     <tr> 
     <td> 
      FooBar 
      <br> 
      <br> 
      <span contenteditable="false" draggable="true" fr-original-class="fr-video fr-dvb fr-draggable" fr-original-style="-webkit-user-select: none;" style="-webkit-user-select: none; text-align: center; position: relative; display: block; clear: both;"> 
      <iframe src="//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&amp;url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&amp;image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube" width="600" height="338" scrolling="no" frameborder="0" allowfullscreen="" style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-class="embedly-embed"></iframe> 
      </span> 
      <br> 
      Foo Bar 
      <br> 
      <br> 
      <span contenteditable="false" draggable="true" fr-original-class="fr-video fr-dvb fr-draggable" fr-original-style="-webkit-user-select: none;" style="-webkit-user-select: none; text-align: center; position: relative; display: block; clear: both;"> 
      <iframe src="//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/skLz87ixE48?feature=oembed&amp;url=http://www.youtube.com/watch?v=skLz87ixE48&amp;image=https://i.ytimg.com/vi/skLz87ixE48/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube" width="600" height="338" scrolling="no" frameborder="0" allowfullscreen="" style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-class="embedly-embed"></iframe> 
      </span> 
      <br> 
     </td> 
     </tr> 
     <tr style='font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 12px; color: #656565; text-align: center;'> 
     <td style='padding: 10px 0px;'> 
     </td> 
     </tr> 
    </table> 
    </body> 
</html> 
+0

これを正しく理解すれば、正規表現で2つのことをしようとしていますか?そのうちの1つは、YouTube埋め込みを含む「 ...」を削除することですか?もう1つは、YouTube埋め込みのIDを取得することです。 – wpcarro

+0

@wcarrollは正しいです。 2つの操作を別々に行うのは問題ありません。埋め込みIDを一致させたいと思います。見つけたIDごとに、YouTubeの埋め込みコードを置き換えて、コンテナにカスタムHTMLを挿入します。私の現在のRegExは、最初の埋め込み( ' ')の開始点を見つけ、2番目の埋め込みの最後と一致します(' ')。 – tommybond

+1

HTMLやXMLを扱うときは、正規表現ではなくパーサーを使用することを強くお勧めします。歴史的な議論については、http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags?rq=1を参照してください。 Rubyのデファクトパーサーは[Nokogiri](http://www.nokogiri.org)です。 Nokogiriは、 'sub'や' gsub'を使わずに特定のノードを見つけたり、情報を抽出したり、DOMを変更したりするのを容易にします。 –

答えて

1

正規表現を使用しないでください。それははるかに容易にするために、既存のツールがあります。

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<!DOCTYPE html> 
<html> 
    <body> 
    <table> 
     <tr> 
     <td> 
      <span> 
      <iframe src="//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&amp;url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&amp;image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube" width="600" height="338" scrolling="no" frameborder="0" allowfullscreen="" style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-class="embedly-embed"></iframe> 
      </span> 
      <span> 
      <iframe src="//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/skLz87ixE48?feature=oembed&amp;url=http://www.youtube.com/watch?v=skLz87ixE48&amp;image=https://i.ytimg.com/vi/skLz87ixE48/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube" width="600" height="338" scrolling="no" frameborder="0" allowfullscreen="" style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-style="box-sizing: content-box; max-width: 100%; border: 0px;" fr-original-class="embedly-embed"></iframe> 
      </span> 
     </td> 
     </tr> 
    </table> 
    </body> 
</html> 
EOT 

この時点で、それは<span>タグのsearchに簡単です。ここでは最初のものです:

doc.search('span').first.to_html 
# => "<span>\n   <iframe src=\"//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&amp;url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&amp;image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-class=\"embedly-embed\"></iframe>\n   </span>" 

lastまたは規則的配列のインデックスが必要に応じて特定のインスタンスを見つけるために使用することができます。

代わりsearchfirstを使用して、我々はすでに内部でそれらをしており、代わりにatを使用することができますあなた一度

doc.at('iframe')['src'] 
# => "//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text/html&schema=youtube" 

doc.at('span').to_html 
# => "<span>\n   <iframe src=\"//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&amp;url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&amp;image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-class=\"embedly-embed\"></iframe>\n   </span>" 

は、我々はそのパラメータをつかむためにノードを掘り下げることができますURLを持っている場合は、それらを操作するためのツールもあります:

require 'uri' 
iframe = doc.at('iframe') 
uri = URI.parse('http:' + iframe['src']) 

私たちがクエリを抽出することができます。

uri.query # => "src=https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed&url=http://www.youtube.com/watch?v=e7zCqsjK1Vg&image=https://i.ytimg.com/vi/e7zCqsjK1Vg/hqdefault.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text/html&schema=youtube" 

我々はそれが簡単に離れてそれを選ぶために作り、ハッシュにそれを解析することができます

URI::decode_www_form(uri.query).to_h['src'] 
# => "https://www.youtube.com/embed/e7zCqsjK1Vg?feature=oembed" 

を...またはそれを変更します。

query = URI::decode_www_form(uri.query).to_h 
query['src'] = 'http://example.com' 

uri.query = URI::encode_www_form(query) 

uri.to_s 
# => "http://cdn.embedly.com/widgets/media.html?src=http%3A%2F%2Fexample.com&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3De7zCqsjK1Vg&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fe7zCqsjK1Vg%2Fhqdefault.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=youtube" 

あなたがいたら、必要に応じてHTMLを簡単に変更できます:

iframe['src'] = uri.to_s 
iframe.to_html 
# => "<iframe src=\"http://cdn.embedly.com/widgets/media.html?src=http%3A%2F%2Fexample.com&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3De7zCqsjK1Vg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fe7zCqsjK1Vg%2Fhqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text%2Fhtml&amp;schema=youtube\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-class=\"embedly-embed\"></iframe>" 

と:

doc.to_html 
# => "<!DOCTYPE html>\n<html>\n <body>\n <table>\n  <tr>\n  <td>\n   <span>\n   <iframe src=\"http://cdn.embedly.com/widgets/media.html?src=http%3A%2F%2Fexample.com&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3De7zCqsjK1Vg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fe7zCqsjK1Vg%2Fhqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text%2Fhtml&amp;schema=youtube\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-class=\"embedly-embed\"></iframe>\n   </span>\n   <span>\n   <iframe src=\"//cdn.embedly.com/widgets/media.html?src=https://www.youtube.com/embed/skLz87ixE48?feature=oembed&amp;url=http://www.youtube.com/watch?v=skLz87ixE48&amp;image=https://i.ytimg.com/vi/skLz87ixE48/hqdefault.jpg&amp;key=2aa3c4d5f3de4f5b9120b660ad850dc9&amp;type=text/html&amp;schema=youtube\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen=\"\" style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-style=\"box-sizing: content-box; max-width: 100%; border: 0px;\" fr-original-class=\"embedly-embed\"></iframe>\n   </span>\n  </td>\n  </tr>\n </table>\n </body>\n</html>\n" 

これは代わりに、それは仕様に基づいて既存のよくテストされたホイールがあることを思い出させるだと我々がすべき、まさにあなたが約求めている問題を解決する方法の例ではありませんそれらを使用してください。

+0

私は両方の方法のマッシュアップを使わなければならないかもしれません、私は ''ノードに埋め込まれたYouTubeビデオを持っているノードだけを取りたいと思っています。 – tommybond

+1

いいえ、NokogiriとURIを使って、複雑な正規表現を使わなくても可能です。 CSSセレクタと内部パラメータの検索方法、またはXPathについて学んでください。それらはここで何度も議論されています。 –

+0

さて、あなたは間違いありませんでした。ちょうどNokogiriを使用して、これを実際にエレガントに、そして単に働かせました。どうもありがとう! – tommybond

1

YouTube IDを取得するには、ルックアラウンドを使用することをおすすめします。次は動作するはずです。正規表現エンジンは、最初の一致を検出した後に停止しないように、ここで

(?<=embed\/)(.+?)(?=\?) 

は、「グローバル」フラグのregex101.com

ターンでlink to a demonstrationです。この正規表現はルック・バックを使用します。(?<=embed\/);ワイルドカード文字に貪欲でない方法で一致するキャプチャグループが続きます。(.+?);続いてリテラルの疑問符((?=\?))が表示されます。

これは、ビデオIDを取得するのに十分です。

HTMLを交換するとして、ここでは<span>...</span>ブロックマッチする正規表現です:.ワイルドカード文字が改行文字を一致させることができるように正規表現エンジンへsフラグを適用し、これが機能する

<span.*?>\s*<iframe.+?>.*?<\/iframe>\s*<\/span> 

は、 。また、前述の理由と同じ理由でgフラグを適用します。

注:これは、直接子供としてを持つ<span>グループをキャプチャします。あなたが働いているコンテンツに応じて、それらの属性をスキャンするために正規表現にさらに細部を追加する必要があるかもしれません。しかし、あなたがこの質問に提供した内容については、うまくいくように見えます。

説明や追加機能をご希望の場合はお知らせください。

ここにはregex101.comのlink to a demonstrationがあります。

+0

素晴らしいです、ありがとうございます。最初の正規表現は私の目的のためにすごくうまくいくようですが、2番目の正規表現は私が投稿した例ではうまくいかないようです。私は ' \ s * 。*に変更しました。<\/iframe> \ s * <\/span> 'は ''属性を考慮していますが、まだ動作していないようです。 – tommybond

+0

もう一度見てみましょう。 – wpcarro

+1

これはいかがですか? ' \ s * 。*? <\/iframe> \ s * <\/span>「これがうまくいくなら、私は自分の答えを編集します。フラグが 'g'と' s'に設定されていることを確認してください。これはここで働いています。 https://regex101.com/r/nF0bQ6/1これに失敗した追加のコンテンツがありますか? – wpcarro

関連する問題