ツイートに含まれるハッシュタグや URL の情報を取得する方法 (日本語ハッシュタグへの対応などの仕様変更に自動で対応できるように)

先日、twitter が日本語のハッシュタグに対応 して、何かと便利になったような気がします。 ただ、残念ながら twitter クライアントや twitter 関係の web サービスではまだ日本語のハッシュタグに対応できていないところもあるようです。 例えば とぅぎゃったー とかもそうですね。 (PHP あるあるのとぅぎゃったーまとめ を見ていて日本語ハッシュタグへの非対応に気づきました。)

Entities 情報を利用してハッシュタグや URL 情報を取得する

さて、日本語ハッシュタグに対応できていないのは、それぞれのサービスが独自にツイート内容からハッシュタグを抽出するようにしているからだと思います。 日本語ハッシュタグも抽出できるようにそれぞれのサービスがハッシュタグ抽出の方法を変更すれば今回は対応できますが、twitter の仕様が変更されればまたそのつど対応していかなければいけません。

そのような方法をとるのではなく、twitter が提供している twitter entities (詳しくは後述) の情報を利用して、ツイート内容に含まれるハッシュタグや URL の情報を取得しましょう! というのがこの記事の内容です。

続きを読む

スクロール位置を維持しつつ web ページ全体のスクロールをできないようにする方法 (web ページのスクロール位置固定)

最近は Ajax などによって web ページを動的に変更するという手法も一般的になって、ページの中にさらにサブページのようなものをポップアップする、ということがしばしば行われます。 例えば Facebook の Theater mode のようなものです。

さて、「ページの中にサブページのようなものをポップアップして表示する」 場合、サブページがスクロール可能であれば、もともとのページ全体はスクロール不可能にしておく方がユーザーにとっては使いやすいデザインであると思います。 実際、Facebook でも Theater mode の際には Theater 側にスクロールバーがあるのみで、ページ全体はスクロール不可になります。

本記事では、そのような用途に用いるための 「スクロール位置を維持しつつ web ページ全体のスクロール可否性を変更する関数」 を紹介します。

ページ全体をスクロール不可能にする方法

さて、まずはページ全体をスクロールする方法を説明します。 一般的なブラウザにおいては、表示領域として viewport があります。 ブラウザの描画領域のことだと考えてください。 Web ページ全体のコンテンツが描画される領域よりも viewport が小さい場合は、ページ全体をスクロールする機構が viewport に与えられる、というのが一般的です。

つまり、ページ全体のスクロールを不可にするというのは、すなわち viewport のスクロールを不可にする、ということです。 スクロールの可否に関わる CSS のプロパティといえば overflow ですが、CSS 2.1 勧告の overflow の項 に次のように書かれています。

UAs must apply the 'overflow' property set on the root element to the viewport.

HTML 文書であれば、ルート要素である html 要素に overflow: hidden と設定をすると、それが viewport に適用される、ということです。

つまり、ページ全体をスクロール不可能にする方法は、html 要素に overflow: hidden と設定する ということになります。

スクロール位置がリセットされてしまう

しかし、html 要素に overflow: hidden と設定すると、Firefox 5 などではスクロール位置が元のままではなく、ページ上部に戻ってしまいます。 この挙動が仕様で規定されているものなのか実装依存なのかはよくわかりませんが、現実問題としてスクロール位置がリセットされてしまうのでなんとかする必要があります。

スクロール位置の取得と設定

この問題の対応策として、html 要素に overflow: hidden を設定する前のスクロール位置を予め取得しておいて、overflow: hidden の設定後に元のスクロール位置を設定しなおす、という方法があります。

Web ページ全体の (viewport の?) スクロール位置を取得したり設定したりするメソッドは、CSSOM View Module の ScreenView インターフェイス に定義されています。 まだ Working Draft 段階ですが、FirefoxOperaSafari などのブラウザでは既に実装されています。 ScreenView インターフェイスが実装されている実行環境であれば、次のような JavaScript コードで、ページのスクロール位置を取得できます。

// x 方向のスクロール位置
var xos = document.defaultView.pageXOffset;
// y 方向のスクロール位置
var yos = document.defaultView.pageYOffset;

また、IE 6 以降では、次のコードで同様に取得できます。

// x 方向のスクロール位置
var xos = document.documentElement.scrollLeft;
// y 方向のスクロール位置
var yos = document.documentElement.scrollTop;

ページのスクロール位置の変更は、次のようなコードで実行できます。

// ScreenView インターフェイスが実装されている場合
document.defaultView.scrollTo( xoffset, yoffset );
// IE の場合
window.scrollTo( xoffset, yoffset );

スクロール位置を維持しつつ web ページ全体のスクロール可否性を変更する関数

というわけで、まとめ代わりにスクロール位置を維持しつつ web ページ全体のスクロール可否性を変更する JavaScript 関数をおいておきます。

Firefox 5、Opera 11.50、Safari 5、IE 6, 7, 8, 9 では期待通りに動くことを確認しました。

var setPageScrollable = function setPageScrollable( scrollable ) {
    var dv = window;
    var xOffset, yOffset, de;
    if( document.defaultView ) {
        dv = document.defaultView;
        xOffset = dv.pageXOffset;
        yOffset = dv.pageYOffset;
    } else {
        de = document.documentElement;
        xOffset = de.scrollLeft;
        yOffset = de.scrollTop;
    }
    document.documentElement.style.overflow = ( scrollable ? "auto" : "hidden" );
    dv.scrollTo( xOffset, yOffset );
}

サンプルページを置いておきますのでご覧ください。

Java のローカル内部クラスや無名内部クラスから外部のローカル変数にアクセスする

Java で Swing を使ってると無名内部クラス (anonymous inner class) をしばしば用いることになると思います。 例えば SwingUtilities.invokeLater メソッド に渡す Runnable オブジェクト は無名内部クラスとして生成することが多いのではないでしょうか?

そのような無名内部クラスやローカル内部クラス (local inner class) からは、そのクラスが定義されているスコープ内のローカル変数 (局所変数) やメソッドパラメータにアクセスできないものだと思っていまして、「アクセスできれば便利なのになー」 とずっと思っていました。 が、実はローカル変数へのアクセスはできるということを知ったのでメモ書きしておきます。

public class Test {
    
    public static void main( String[] args ) {
        // 無名内部クラスからアクセスされるローカル変数
        final int extVar = 100;
        // 無名内部クラス
        new Runnable() {
            @Override
                public void run() {
                    // 無名内部クラスの外部で、かつ無名内部クラスが定義されて
                    // いるスコープ内のローカル変数にアクセスする
                    System.out.println( extVar );
                }
        }.run();
    }

}

ただし、アクセスできるのは final 修飾子が付けられた変数だけ です。 final 修飾子が付けられていない変数へのアクセスは以下のようなコンパイルエラーを引き起こします。

Cannot refer to a non-final variable variableName inside an inner class defined in a different method

参考文献

プログラミング言語Java (The Java Series)

プログラミング言語Java (The Java Series)

  • 作者: ケン・アーノルド,ジェームズゴスリン,デビッドホームズ,柴田芳樹
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/04
  • メディア: 単行本
  • 購入: 38人 クリック: 1,044回
  • この商品を含むブログ (71件) を見る

Amazon.co.jp では 「翻訳がひどい」 ということであまり評価は高くありません。 実際、翻訳がひどくて全く意味を理解できない箇所もないことはないのですが、まあ読み辛いものの意味は理解できるのが大部分ですし、内容的には良いと思います。

CSS の position: fixed により描画領域全体を覆う要素を IE 6 でエミュレーションする

Lightbox のように、ブラウザの描画領域全体に何らかの要素を表示したいような場合、おそらくは CSSposition: fixed を指定すると思います。

しかしながら、Internet Explorer 6position: fixed をサポートしていないので、IE6 で同じ事をするには別の方法を採らなければいけません。 IE6 で position: fixed と似たような動きを行わせる方法は、例えば以下のようなものがあります。

自分の web ページ上で使うのであればこの方法でいいと思うのですが、Lightbox のようにライブラリとして配布するものの内部で使うには多少物足りない部分があります。 例えば、指定の要素が position: relative を指定されている要素の子孫である場合、期待する位置に固定されない可能性があります。

そんなわけでもうちょっと詳しく位置計算を行うようなものを考えてみました。

<!-- IE 6 にだけ適用されるように, 条件コメントを使用 -->
<!--[if IE 6]>
<script>
    // 残念ながら HTML 要素に border がついてる場合は fixed とは同じにはならない
    function _ie_getOffsetOfParentFromPageTop( elem ) {
        var e = elem.offsetParent;
        var offset = 0;
        while( e && e.tagName !== "HTML" ) {
            offset += e.clientTop + e.offsetTop;
            e = e.offsetParent;
        }
        return offset;
    }
    function _ie_getOffsetOfParentFromPageLeft( elem ) {
        var e = elem.offsetParent;
        var offset = 0;
        while( e && e.tagName !== "HTML" ) {
            offset += e.clientLeft + e.offsetLeft;
            e = e.offsetParent;
        }
        return offset;
    }
</script>
<style>
    /* border などをつけるときは, それに応じて width と height を調整すること */
    #fixed-box {
        position: absolute;
        top: expression( ( document.documentElement.scrollTop  
              - _ie_getOffsetOfParentFromPageTop( this )  ) + "px" );
        left: expression( ( document.documentElement.scrollLeft 
              - _ie_getOffsetOfParentFromPageLeft( this ) ) + "px" );
        width:  expression( ( document.documentElement.clientWidth )  + "px" );
        height: expression( ( document.documentElement.clientHeight ) + "px" );
    }
</style>
<![endif]-->

サンプルページは以下においてあるので見てみてください。

参考文献

ダイクストラ法による最短経路探索と任意距離の移動が可能な場合の変法

何回か前の TopCoder SRM (SRM509) で出題された最短経路探索問題 (Div2 Hard) が解けなかったので、後から考えた解法をメモしておきます。 実際の問題とは異なりますが、大体こんな感じ、ということで。 実際に出題された問題は、ダイクストラ法で解ける最短経路問題をちょっと難しくしたようなものだったのですが、ここでは、簡単なものと難しいものの 2 つの問題を考えてみます。

まず単純なダイクストラ法で解ける最短経路問題。

M × 横 N のマス目がある。 縦方向には 0 から M - 1 までの数字が、横方向には 0 から N - 1 までの数字が順に振られており、各マスは (x, y) 形式で位置を指定することができる (x, y は 0 ≦ x < M, 0 ≦ y < N の整数) とする。

このマス目上を、初期位置 s から目標位置 e まで移動することを考える。 各マスには正の整数が書かれており、自分がいるマスに書かれた数字のマス目数だけ離れた上下左右のいずれかのマスにのみ移動できるとする。 1 回の移動を 1 ステップと考えるとき、s から e への移動にかかる最小のステップ数はいくらか求めよ。 もし移動できない場合は移動できないという結果を出すこと。

次に、TopCoder SRM で出題されたものに近い、ちょっと難しい問題。 任意距離のマス目移動が可能となっています。

先の問題と同じ設定でマス目が存在するとする。

そのマス目上を、初期位置 s から目標位置 e まで移動することを考える。 各マスは正の整数が書かれているか空欄であり、数字が書かれている場合はその数字のマス目数だけ離れた上下左右のいずれかのマスにのみ移動できるとする。 数字が書かれていない場合は、1 から 9 までの任意の距離だけ離れたマスに移動できるとする。 1 回の移動を 1 ステップと考えるとき、s から e への移動にかかる最小のステップ数はいくらか求めよ。 もし移動できない場合は移動できないという結果を出すこと。
ただし、任意距離の移動は S 回しか行うことができないとする。

続きを読む