「半角空白」が検索できない場合がある問題
「ver.0.5」のチェックをしていると、運良く前ページに例があったので気付く事ができました。 これまでにも何度か問題になった「 」(ノーブレイクスペース)が、検索にかからなかったのです。
「 」は、アメーバのPC編集画面で記事を書いていると、比較的頻繁に書き込まれます。「通常表示」から見ると普通の「半角空白」と同じで、ユーザーは単なる空白と思ってしまいますが、文字コードが違います。「HTML表示」で見ると下の様に違いがはっきりします。
とりたてて「半角空白」に訂正する必要はないのですが、今回の様に「 」が問題になる事があります。
それでは「 」を書けと言われても「?」となりますね。「Abema」「 TV」と2行に書き、TVの行頭で「BackSpace」を押すと「 」が間に入ります。 空白の改行は「 」だらけなので、ちょっとした編集操作で紛れ込むのでしょう。
で、「ver.0.5」までの検索コードでは、「半角空白」「全角空白」「 」は検索上で別物として扱われます。 これは、検索機能として理想的なのですが、実用上で「半角空白」に見えるものは同じ物として扱えないと困るわけです。
前ページの「Abema TV」に「 」が混ざっていたので、「厳密な検索」で検索語「Abema TV」を指定すると、ヒット数が合いません。 最初は理由が判らず焦りました。
対策
「空白が混ざった文字列」を検索できる事は大きな強みですから、絶対に譲れない問題です。 ネットには「半角空白」「 」の両方を検索するには「空白文字」を「\s」に置換えるという情報があります。 これを最初に試したのですが、確かにそれで「 」にもヒットする様になりますが、今度は「全角空白」がヒットしてしまいます。「半角空白」「全角空白」の区別も出来なくなるのです。
ここで再び色々なページを当たり、「半角空白」「 」をそれぞれの文字コードに置き換えて検索するという方法に辿り着きました。
▪「半角空白」の文字コード(unicode)は「u0020」 文字列上では「\u0020」
▪「 」の文字コード(unicode)は「u00A0」 文字列上では「\u00A0」
「A」と「B」の両方にヒットする正規表現の書き方は「 (A|B) 」ですから、これに当てはめた書式を作りました。「 ( | ) 」をエスケープする「\」を付けています。
検索語に「半角空白」があれば、上の書式に置き換えて検索を行う様にしました。
以下は、エスケープ処理の後に、この置換え処理を追加したコードです。
「Ameba Search Tools」 ver.0.6 376行~
▪ 検索窓に書き込まれる「検索語」は「半角空白」しか受付けない様で、「半角空白」の入力で「半角空白」「 」の両方にヒットさせるコードにしています。
▪ 文字コードのエスケープは「\\u~」が正しいと思えるのですが、テストすると「\u~」でないと動作しません。 正規表現は難しいです。
実証テスト
下は、「半角空白」「 」「全角空白」を含んだ「ABEMA」のサンプルです。
検索ヒットの違いが判る様に、サンプル数を変えています。
① ABEMA TV (半角空白)
➁ ABEMA TV ABEMA TV ( )
➂ ABEMA TV ABEMA TV ABEMA TV (全角空白)
①「検索語」➂「除外語」の指定で「厳密な検索」を実証テストしてみました。
① を検索できますが ➁の「 」を検索できません。
また全角空白と半角空白は区別できています。
①「半角空白」と ➁「 」を検索して、検索語のヒットが「3」です。
また全角空白と半角空白は区別できています。
これで「 」が混入している場合も、問題なく検索が行えます。
「Ameba Search Tools」の操作マニュアル
操作マニュアルは以下のページにあります。
「Ameba Search Tools」を利用するには
このツールは Chrome / Edge / Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。
❶「Tampermonkey」を導入します
◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。
既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。
拡張機能の導入については、以下のページに簡単な説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
◎「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Ameba Search Tools 〕 ver. 0.6
// ==UserScript== // @name Ameba Search Tools // @namespace http://tampermonkey.net/ // @version 0.6 // @description アメーバ検索の環境ツール+厳密な記事検索 // @author Ameba Blog User // @match https://ameblo.jp/* // @match https://search.ameba.jp/* // @icon https://www.google.com/s2/favicons?sz=64&domain=ameblo.jp // @grant none // ==/UserScript== // 以下は検索ページで動作 ========================== if(window.location.hostname=='search.ameba.jp'){ let target=document.querySelector('head title'); let monitor=new MutationObserver(page_select); monitor.observe(target, { childList: true }); page_select(); function page_select(){ if(document.querySelector('.PcResultPagination')){ // 検索ページャーのある画面でのみ動作 let now; let now_u; let now_s; let q; let now_s_q; let now_s_pre; let now_s_next; let pre_url; let next_url; function get_pre_url(){ now=location.href; now_u=now.split('?')[0]; now_s=now.split('?')[1]; if(now_s){ now_s=now_s.replace('&sbs=0', ''); q=now_s.split('&'); for(let k=0; k<q.length; k++){ if(q[k].indexOf('p=')!=-1){ now_s_q=q[k]; }} let now_page; if(now_s_q){ now_page=now_s_q.substr(2); if(now_page/1==1){ now_s_pre='p=1'; } else{ now_s_pre='p='+ (now_page/1 -1); } if(now_s_pre){ for(let k=0; k<q.length; k++){ if(q[k].indexOf('p=')!=-1){ q[k]=now_s_pre; }} pre_url=now_u +'?'+ q.join('&'); }} else{ pre_url=now +'&p=1'; }} else{ pre_url=now +'?p=1'; } } // get_pre_url() function get_next_url(){ now=location.href; now_u=now.split('?')[0]; now_s=now.split('?')[1]; if(now_s){ now_s=now_s.replace('&sbs=0', ''); q=now_s.split('&'); for(let k=0; k<q.length; k++){ if(q[k].indexOf('p=')!=-1){ now_s_q=q[k]; }} let now_page; if(now_s_q){ now_page=now_s_q.substr(2); if(now_page/1==100){ now_s_next='p=100'; } else{ now_s_next='p='+ (now_page/1 +1); } if(now_s_next){ for(let k=0; k<q.length; k++){ if(q[k].indexOf('p=')!=-1){ q[k]=now_s_next; }} next_url=now_u +'?'+ q.join('&'); }} else{ next_url=now +'&p=1'; }} else{ next_url=now +'?p=1'; } } // get_next_url() document.addEventListener("keydown", check_arrow); function check_arrow(event){ if(event.keyCode==37){ //「⇦」 if(is_able()){ event.preventDefault(); go_pre(); }} if(event.keyCode==39){ //「⇨」 if(is_able()){ event.preventDefault(); go_next(); }} if(event.keyCode==38){ //「⇧」 if(is_able()){ event.preventDefault(); select_up(); }} if(event.keyCode==40){ //「⇩」 if(is_able()){ event.preventDefault(); select_down(); }} if(event.keyCode==13){ //「Enter」 event.preventDefault(); select_open(event); } if(event.keyCode==32){ //「Space」 if(is_able()){ event.preventDefault(); severe_search(); }} if(event.keyCode==27){ //「ESC」 if(is_able()){ clear_select(); }}} function go_pre(){ if(go_check(0)){ get_pre_url(); if(pre_url){ location.href=pre_url; }}} function go_next(){ if(go_check(1)){ get_next_url(); if(next_url){ location.href=next_url; }}} function go_check(n){ if(n==0){ let edge=document.querySelector('.PcResultPagination_MoreLink .s-triangle-left'); if(edge){ return true; } else{ return false; }} if(n==1){ let edge=document.querySelector('.PcResultPagination_MoreLink .s-triangle-right'); if(edge){ return true; } else{ return false; }}} function go_check2(url){ if(url.includes('/news/')){ return false; } else{ return true; }} let order=-1; function select_up(){ let items=get_items(); if(order>0){ for(let k=0; k<items.length; k++){ items[k].style.outline=''; } order=order-1; items[order].style.outline='2px solid red'; }} function select_down(){ let items=get_items(); if(order<items.length-1){ for(let k=0; k<items.length; k++){ items[k].style.outline=''; } order=order+1; items[order].style.outline='2px solid red'; }} function select_open(event){ let items=get_items(); for(let k=0; k<items.length; k++){ if(items[k].style.outlineWidth=='2px'){ let link=items[k].querySelector('a'); if(link){ let url=link.getAttribute('href'); if(event.ctrlKey){ window.open(url, '_blank'); } else{ window.location.href=url; }}}}} let s_input=document.querySelector('.PcSuggestForm_Input'); if(s_input){ s_input.onclick=function(){ clear_select(); }} function clear_select(){ let items=get_items(); for(let k=0; k<items.length; k++){ items[k].style.outline=''; }} function is_able(){ let s_input=document.querySelector('.PcSuggestForm_Input'); if(s_input && s_input==document.activeElement){ return false; } else{ return true; }} function get_items(){ let PcBL=document.querySelectorAll('.PcBloggerListItem'); let PcAN=document.querySelectorAll('.PcAmebaNewsListItem'); let PcEL=document.querySelectorAll('.PcEntryListItem'); if(PcBL.length!=0){ return PcBL; } else if(PcAN.length!=0){ return PcAN; } else if(PcEL.length!=0){ return PcEL; } } // get_items() function severe_search(){ let ok=confirm("💢 このページの全記事の厳密な検索をします"); if(ok){ let items=get_page_items(); for(let k=0; k<items.length; k++){ let link=items[k].querySelector('a'); if(link){ let url=link.getAttribute('href'); window.open(url+'?sbs', '_blank'); }}} function get_page_items(){ let PcBL=document.querySelectorAll('.PcBloggerListItem'); let PcEL=document.querySelectorAll('.PcEntryListItem'); if(PcBL.length!=0){ return PcBL; } else if(PcEL.length!=0){ return PcEL; } } // get_page_items() } // severe_search() let pagination=document.querySelector('.PcResultPagination'); if(pagination){ let help= '<div id="astool_help">'+ '<div class="upper">'+ '⇦ ⇨:リスト移動<br>'+ '⇩ ⇧:記事の選択<br>'+ 'Enter :選択記事へ<br>'+ 'Ctrl+Enter:別タブ<br>'+ 'Ctrl+Tab:タブ移動<br>'+ 'Space:顕密な検索<br>'+ '</div>'+ '<p class="lower">Search Tools '+ '<a href="https://ameblo.jp/personwritep/entry-12845478988.html" '+ 'rel="noopener noreferrer" target="_blank">'+ '<span class="help">?</span></a></p>'+ '<style>'+ '#astool_help { position: absolute; top: -4px; left: -180px; '+ 'font: normal 14px Meiryo; text-align: left; width: 138px; '+ 'border: 1px solid #aaa; background: #fff; } '+ '.upper { padding: 4px 0 4px 5px; } '+ '.lower { padding: 2px 2px 0 10px; color: #fff; background: #bcbfc3; } '+ '.help { display: inline-block; height: 17px; padding: 1px 2px 2px 2px; '+ 'font: bold 16px/21px Meiryo; color: #fff; '+ 'border-radius: 30px; background: #666; cursor: pointer; }'+ '</style></div>'; if(!pagination.querySelector('#astool_help')){ pagination.insertAdjacentHTML('afterbegin', help); }} } // if('.PcResultPagination') } // page_select() } // if('search.ameba.jp') // 以下は個別ブログページで動作 ========================== if(window.location.hostname=='ameblo.jp'){ let word; let read_json=localStorage.getItem('SBS'); // ローカルストレージ保存名 word=JSON.parse(read_json); if(word==null || word.length!=5){ word=['','','','', 0]; } // 0検索語/1除外語/2除外語/3除外語/4パネル幅 let retry=0; let interval=setInterval(wait_target, 500); function wait_target(){ retry++; if(retry>8){ // 制限 4sec clearInterval(interval); main_sub(); } let entrybody=document.querySelector('#entryBody'); // 監視 target if(entrybody){ clearInterval(interval); main(); }} function main_sub(){ // アメンバー記事や記事ページでない場合 if(window.location.search=='?sbs'){ window.close(); }} function main(){ function call_h(){ let header; if(document.querySelector('#app header')){ header=document.querySelector('#app header'); } // 新タイプスキン・旧タイプスキン else if(document.querySelector('#app #header')){ header=document.querySelector('#app #header'); } // レトロタイプスキン return header; } function call_t(){ let title; let article=document.querySelector('.js-entryWrapper'); //記事全体 if(article){ if(article.querySelector('h1')){ title=article.querySelector('h1'); } // 新タイプスキン・旧タイプスキン else if(article.querySelector('h3')){ title=article.querySelector('h3'); }} // レトロタイプスキン return title; } let entrybody=document.querySelector('#entryBody'); if(entrybody){ // リスト・タイルのトップページ、アメンバーページ 等は検索しない let count0; let count1; let count2; let count3; count_do(); function count_do(){ let entrybody=document.querySelector('#entryBody'); let page_text=entrybody.textContent; if(call_h()){ page_text+=call_h().textContent; } if(call_t()){ page_text+=call_t().textContent; } if(word[0]!=''){ let word0_es=escape_exs(word[0]); count0=(page_text.match(new RegExp(word0_es, 'g')) || []).length; } else{ count0=0; } if(word[1]!=''){ let word1_es=escape_exs(word[1]); count1=(page_text.match(new RegExp(word1_es, 'g')) || []).length; } else{ count1=0; } if(word[2]!=''){ let word2_es=escape_exs(word[2]); count2=(page_text.match(new RegExp(word2_es, 'g')) || []).length; } else{ count2=0; } if(word[3]!=''){ let word3_es=escape_exs(word[3]); count3=(page_text.match(new RegExp(word3_es, 'g')) || []).length; } else{ count3=0; } function escape_exs(string){ let reRegExp=/[\\^$.*+?()[\]{}|]/g; let reHasRegExp=new RegExp(reRegExp.source); string= (string && reHasRegExp.test(string)) ? string.replace(reRegExp, '\\$&') : string; string=string.replace(' ', '\(\u0020\|\u00A0\)'); return string; } } // count_do() if(window.location.search=='?sbs'){ if(count0==count1+count2+count3){ window.close(); }} // 手動で開いたページでは閉じず、スクリプトで開いた場合は閉じる let set_word_box= '<div id="set_word_box">'+ '検索:<input id="w_set0" class="w_set" type="text">'+ '<span id="result0" class="result"> </span>'+ '除外:<input id="w_set1" class="w_set" type="text">'+ '<span id="result1" class="result"> </span>'+ '<input id="w_set2" class="w_set" type="text">'+ '<span id="result2" class="result"> </span>'+ '<input id="w_set3" class="w_set" type="text">'+ '<span id="result3" class="result"> </span>'+ '<input id="set" type="button" value="Set">'+ '<input id="hide" type="button" value="◁">'+ '</div>'+ '<style>'+ '#set_word_box { display: flex; align-items: center; justify-content: flex-end; '+ 'position: fixed; top: 60px; left: 20px; padding: 6px; font: normal 16px Meiryo; '+ 'color: #000; overflow: hidden; white-space: nowrap; border: 1px solid #aaa; '+ 'background: #e6f3f9; box-shadow: 10px 20px 50px rgb(0 0 0 /20%); z-index: 9; } '+ '#set_word_box input {font: normal 16px Meiryo; } '+ '.w_set { width: 120px; height: 24px; padding: 4px 6px 2px; margin-right: 4px; } '+ '#w_set1, #w_set2, #w_set3 { filter: brightness(0.97); } '+ '.result { display: inline-block; min-width: 12px; padding: 4px 4px 2px; height: 26px; '+ 'margin-right: 12px; text-align: center; border: 1px solid #666; border-radius: 2px; } '+ '#result0 { margin-right: 25px; background: #fff; } '+ '#set { padding: 4px 4px 2px; margin-left: 20px; } '+ '#hide { padding: 4px 4px 2px; margin-left: 10px; } '+ '</style>'; if(!document.querySelector('#set_word_box')){ document.body.insertAdjacentHTML('beforeend', set_word_box); } disp_count(); panel_width(); function disp_count(){ let w_set0=document.querySelector('#w_set0'); let w_set1=document.querySelector('#w_set1'); let w_set2=document.querySelector('#w_set2'); let w_set3=document.querySelector('#w_set3'); w_set0.value=word[0]; w_set1.value=word[1]; w_set2.value=word[2]; w_set3.value=word[3]; let result0=document.querySelector('#result0'); let result1=document.querySelector('#result1'); let result2=document.querySelector('#result2'); let result3=document.querySelector('#result3'); result0.textContent=count0.toString(); result1.textContent=count1.toString(); result2.textContent=count2.toString(); result3.textContent=count3.toString(); } let set=document.querySelector('#set'); set.onclick=function(){ let w_set0=document.querySelector('#w_set0'); let w_set1=document.querySelector('#w_set1'); let w_set2=document.querySelector('#w_set2'); let w_set3=document.querySelector('#w_set3'); word[0]=w_set0.value; word[1]=w_set1.value; word[2]=w_set2.value; word[3]=w_set3.value; let write_json=JSON.stringify(word); localStorage.setItem('SBS', write_json); // ローカルストレージ保存 count_do(); // ページの再検索 disp_count(); alert("「検索語」と「検索結果から排除する検索語」を登録しました"); } let target=document.querySelector('head title'); let monitor=new MutationObserver(page_count); monitor.observe(target, { childList: true }); function page_count(){ count_do(); disp_count(); } let hide=document.querySelector('#hide'); hide.onclick=function(){ if(word[4]==0){ word[4]=1; let write_json=JSON.stringify(word); localStorage.setItem('SBS', write_json); } // ローカルストレージ保存 else{ word[4]=0; let write_json=JSON.stringify(word); localStorage.setItem('SBS', write_json); } // ローカルストレージ保存 panel_width(); } function panel_width(){ let set_box=document.querySelector('#set_word_box'); let hide=document.querySelector('#hide'); if(word[4]==0){ set_box.style.width=''; hide.value='◁'; } else{ set_box.style.width='28px'; hide.value='▷'; }} } // if(entrybody) } // main() } // if('ameblo.jp')
アメーバ検索のページデザインについて
このページの「アメーバ検索画面」のスクリーンショットは、「Stylus」を使ったアレンジを適用しています。 以下のアレンジは、検索画面を大変に使い易くします。
これらのアレンジを検索画面に適用するには、拡張機能「Stylus」の導入が必要です。「Stylus」の導入やスタイルの取得については、以下のページを参照ください。
「Ameba Search Tools」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Ameba Search Tools」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。