要約:ページタイトルをサイトタイトルと文書タイトルに分離する試み using PHP
タイトル名とサイト名って書式が決まっているようでバランバランなので、これらを分けてみようととなるとちょっとしんどい。
例えば title タグの中身がほげほげ日記ー××について:○○シリーズその1だったとしよう。この場合は、サイト名は「ほげほげ日記」で文書名は「××について:○○シリーズその1」なのだけど、上記の通りサイト名と文書名をつなぐデリミタ(区切り記号)はバラバラな上、デリミタが複数ある場合を考慮すると単純にデリミタでぶった切るわけにもいかん。本来的には<title><span class="site">サイト名</span><span class="delimeter"> - </span><span class="document">文書名</span>とかセマンティックを意識して書ければよいのだけど1 。
なので、分離の際には2つ以上のタイトルが必要になる。つまり、
- ほげほげ日記ー××について:○○シリーズその1
- ほげほげ日記(トップページのタイトル)
この場合、「ほげほげ日記」が2つのタイトルに共通の文字列なので、そこを抜き出してやればよい。で、残りの文字列が文書名になるわけだ(デリミタはいらない子なので消す)。
で、この「2つのタイトルに共通の文字列を探す」をどう機械語に訳すか。なんとなく思いつくのは、1文字ずつぶった切った後に配列に格納して、双方を比較していくというもの。
でも、もっといい方法ないかなと思って、はてなで質問したら、お二方にお答えいただきました。
ID:KeyKeyさんのお答えは片方の文字列を段階的に切り出していってもう片方と一致するかどうか見るというもの。ID:yoneto164さんは私の考えているところに近い気がします。最後の方はよく分かりませんでしたが^-^;
で、お二人の回答を元にしたテストコードが以下。コメントは一部勝手に書き加えたりしてます、解釈が間違っていたらごめんなさい。
header("Content-Type: text/html;charset=utf-8");
$s1 = "Liner Note - はてなブックマークの各エントリを見やすく表示する「はてなブックマークビューワ」を作った";
$s2 = "Liner Note";
echo "<h1 id="t7266e0">「{$s1}」と「{$s2}」</h1>";
echo "<h2 id="tff8ebf">[1]の結果</h2>";
echo getCommonString1($s1, $s2);
echo "<h2 id="t695b26">[2]の結果</h2>";
echo getCommonString2($s1, $s2);
echo "<h2 id="t0ac35b">[3]の結果</h2>";
echo getCommonString3($s1, $s2);
// 処理時間を測定
function getmicrotime(){
list($msec, $sec) = explode(" ", microtime());
return ((float)$sec + (float)$msec);
}
// ID:KeyKeyさんのコード
function getCommonString1($s1, $s2){
$t[] = getmicrotime();
$k = 0;
//片方の文字列の長さを取得
$len = mb_strlen($s1, "utf-8");
for ($i=0; $i<$len; $i++){
for ($j=1; $j<=$len-$i; $j++){
//$i文字目から$j文字目までを切り出す
$rest = mb_substr($s1, $i, $j, "utf-8");
//$s2に含まれていれば配列に格納
if (preg_match("/" . $rest . "/", $s2, $match)) {
$results[] = $rest;
}
}
}
$longest = 0;
foreach ($results as $result){
$len = mb_strlen($result, "utf-8");
if ($len > mb_strlen($longest, "utf-8")){
$longest = $result;
}
}
$t[] = getmicrotime();
echo "<p>処理時間:". round($t[1] - $t[0], 7) . "秒</p>";
return $longest;
}
// ID:yoneto164さんのコード2
function getCommonString2($s1, $s2){
$t[] = getmicrotime();
$al = mb_strlen($s1,"utf-8");
$bl = mb_strlen($s2,"utf-8");
for ($i=0; $i<$al; $i++){
$aa[$i] = mb_substr($s1,$i,1,"utf-8");
}
for ($i=0; $i<$bl; $i++){
$bb[$i] = mb_substr($s2,$i,1,"utf-8");
}
for ($i=0; $i<$al; $i++){
for ($j=0; $j<$bl; $j++){
// 文字が一致
if ($aa[$i] == $bb[$j]){
if ($match){
// 以前にマッチした文字なら配列に加えない
foreach ($match as $str){
if ($aa[$i] == $str){
$ng = 1;
}
}
}
if ($ng != 1){
$match[$num] = $aa[$i];
}
$ng = 0;
$num++;
}
}
}
foreach($match as $print){
$msg .= $print;
}
$t[] = getmicrotime();
echo "<p>処理時間:". round($t[1] - $t[0], 7) . "秒</p>";
return $msg;
}
// ID:yoneto164さんのコード3
function getCommonString3($s1, $s2){
$t[] = getmicrotime();
$al = mb_strlen($s1, "utf-8");
$bl = mb_strlen($s2, "utf-8");
for ($i=0; $i<$al; $i++){
$aa[$i] = mb_substr($s1,$i,1,"utf-8");
}
for ($i=0; $i<$bl; $i++){
$bb[$i] = mb_substr($s2,$i,1,"utf-8");
}
for ($i=0, $num=0; $i<$al; $i++){
for ($j=0; $j<$bl; $j++){
if ($matchnum[$i][$j] != 1){
// 文字が一致
if ($aa[$i] == $bb[$j]){
$match[$num] = $aa[$i];
$matchnum[$i][$j] = 1;
// さらに文字が一致したら追加
for ($k=1; $k<= $al-$i-1 && $k <= $bl-$j-1; $k++){
if ($aa[$i+$k] == $bb[$j+$k]){
$match[$num] .= $aa[$i+$k];
$matchnum[$i+$k][$j+$k] = 1;
} else{
$j = $j + $k - 1;
break;
}
}
$num++;
}
}
}
}
$longest = 0;
foreach ($match as $result){
$len = mb_strlen($result, "utf-8");
if ($len > mb_strlen($longest, "utf-8")){
$longest = $result;
}
}
$t[] = getmicrotime();
echo "<p>処理時間:". round($t[1] - $t[0], 7) . "秒</p>";
return $longest;
}
実際に実行してみると、勝手に書き加えたコードの影響もあるでしょうが、ID:yoneto164さんのコードがより速かった2 ので、そちらを元に構成することにしました。それがこちら。
// ID:yoneto164さんのコード2を元に構成
function getTitle($s1, $s2){
$al = mb_strlen($s1, "utf-8");
$bl = mb_strlen($s2, "utf-8");
for ($i=0; $i<$al; $i++){
$aa[$i] = mb_substr($s1,$i,1,"utf-8");
}
for ($i=0; $i<$bl; $i++){
$bb[$i] = mb_substr($s2,$i,1,"utf-8");
}
for ($i=0, $num=0; $i<$al; $i++){
for ($j=0; $j<$bl; $j++){
if ($matchnum[$i][$j] != 1){
// 文字が一致
if ($aa[$i] == $bb[$j]){
$match[$num] = $aa[$i];
$matchnum[$i][$j] = 1;
// さらに文字が一致したら追加
for ($k=1; $k<= $al-$i-1 && $k <= $bl-$j-1; $k++){
if ($aa[$i+$k] == $bb[$j+$k]){
$match[$num] .= $aa[$i+$k];
$matchnum[$i+$k][$j+$k] = 1;
} else{
$j = $j + $k - 1;
break;
}
}
$num++;
}
}
}
}
$longest = 0;
foreach ($match as $result){
$len = mb_strlen($result, "utf-8");
if ($len > mb_strlen($longest, "utf-8")){
$longest = $result;
}
}
$site = preg_replace("/[:-<>\/\|ー|:]/", "", chop($longest));
$title = str_replace($longest, "", $s1);
return array($site, $title);
}
ちなみに比較に使うタイトルですが、一方は「サイト名と文書」のもの、もう一方は「サイト名」のみのものでないといけません。この処理だと共通する文字列の一番長いものを「サイト名」にしていますから。
これで、トップページが「無題ドキュメント」だとか「Welcome to Adobe GoLive 5」とかでない限り大丈夫なはず。あ、あともう1つありましたね。昔流行ったらしい短縮タイトルです、この文書ならば「[L] 2つのタイトルからタイトル名とサイト名を分離するPHPスクリプト」と記述するような。
この場合、先頭に[*](*は任意の1文字)が来ているかチェックして、あった場合に例外処理するのがよいのかな。
Popularity: 1% [?]
- キーワード:



読者のコメント
4件