🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

2回答

1692閲覧

JSで「#xxx」などを抽出する

DiningKitchen

総合スコア14

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2019/09/20 10:15

編集2019/09/21 15:16

###実現したいこと
twitterのハッシュタグのように「#xxx」という文字列をタグとして抽出したいです。

#keywordの入力値を#cloneにコピーする際に、抽出したタグをspanで囲みたいのですが、その過程で次の3点に行き詰っています。

###発生している問題
➀改行を入れても1つのタグとして取得してしまう。
➁取得できたタグのうち最後のものにしかspanがつかない。
➂最後の#canが取得できない。

このような問題です。

上の➀がわかりにくいので具体的に言いますと、

「#hello」

「#hell」改行「o」

のように入力すると、
「#hell o」という風にスペースが入って取得されてしまうという問題です。

このとき取得したいのは「#hell」だけなのです。

###該当のソースコード

html

1<textarea type="text" id="keyword" class="box" value="">#hello world #yes we #can</textarea> 2<div id="clone" class="box"></div> 3<button id="btn">clone</button>

css

1.box { 2 border: 1px solid black; 3 padding: 5px; 4 border-radius: 5px; 5 resize: none; 6 height: 100px; 7 width: 200px; 8 white-space: pre-wrap; 9 font-family: unset; 10} 11span {color:blue;} 12
function hash( str ){ var regexp = new RegExp( /#+[^  ]+(\s| )/ ); var result = regexp.test( str ); if ( regexp.test( str ) ) { // 取得 var tags = str.match( /#+[^  ]+(\s| )/g ); console.log( 'tags;', tags ); // タグにspanをつけて全文をコピー tags.forEach(function( value ) { if ( str.match( value ) ) { var target = str.match( value ); console.log( 'target:',target ); var span = '<span class="tag">' + target + '</span>'; var replaced = str.replace( target, span ); $( '#clone' ).html( replaced ); } }); }else{ $( '#clone' ).html( str ); } } $( '#btn' ).click( function(){ hash( $( '#keyword' ).val() ); });

###試したこと
なんとなく➁については原因がわかっていて、ループの中で$( '#clone' ).html( replaced );を書いているために毎回上書きされてしまい、だから最後にしかspanがつかないのだと思うのですが、ループの外に出してみればコピー自体生じず、解決策がわかりません。
そして➀と➂についてはそもそも処理がわからない状況です。

###ソースコードのサンプル
https://jsfiddle.net/udwzey7v/

ご意見、ご回答、宜しくお願い致します。

###補足
twitterのタグ抽出とほぼ同じなので、詳しい抽出条件は次の通りです。

■基本的には、以下3つを満たしたときにタグ化する
・文字列の先頭が、「#」か「#」のようなシャープであること
・シャープ直前が、半角か全角のスペースであること
・文字列の直後が、半角か全角のスペースであること

■例外として、スペースがなくてもタグ化する
・シャープ直前が、記号、行頭、textarea先頭の場合、シャープ直前のスペースはがなくてもタグ化
・文字列がtextarea末尾の場合、直後のスペースがなくてもタグ化

(ただしtwitterでは記号が除外され、「#tag!」のタグは「#tag」と抽出されますが、今回は「#tag!」で構いません。)

以上の条件の具体例を以下に列挙致しましたので、ご参照ください。
https://jsfiddle.net/04awdpu1/

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2019/09/20 10:21

textareaの中の#xxxを<span>#xxx</span>に変えるということ?
DiningKitchen

2019/09/20 10:30 編集

はい、仰る通りです。 textarea の中の #xxx を <span class="tag">#xxx</span> に変えて、それを #clone にコピーする。というのが目的になります。
guest

回答2

0

・シャープ直前が記号の場合、シャープ直前のスペースは不要

この「記号」の定義がわかりませんが、

js

1function hash(str) { 2 // ・文字列がtextarea先頭の場合、直前のスペースは不要 3 // ・文字列がtextarea末尾の場合、直後のスペースは不要 4 // の処理を簡単にするために前後に半角スペースを入れる 5 const haystack = ` ${str} `; 6 7 // タグの開始直前に許容する記号の一覧 8 const prefixChars = ['、', '。']; 9 const reg = new RegExp(`([  ${prefixChars.join('')}])([##].+?)([  ])`, 'g'); 10 const replaced = haystack.replace(reg, (match, prefix, tagging, suffix) => `${prefix}<span class="tag">${tagging}</span>${suffix}`); 11 $('#clone').html(replaced.substring(1, replaced.length - 2)); 12}

未検証ですがこんな感じではいかがでしょう


Sep 21, 2019 19:00追記
出先なのでかんたんに画像で恐縮ですが、\rと\nを条件に出したら改行のところも動きませんでしょうか。
regex101


Sep 22, 2019 1:10追記

なぜか「#we」だけがタグ認定されない事態に…

なるほどーーーーー、
#yes改行#we改行#can に対して「前後に改行空白を持つ部分」で取っているので、まず1つ目で「 #yes改行」が取られて、次の#weは前に改行を持っていない(yesに取られた)状態になって、というような感じで、偶数個めが認識されなくなりますね。
仕様を満たすかどうかは要検証ですがこちらに変えると、ご提示の例では動くかと……

js

1function hash(str) { 2 // ・文字列がtextarea先頭の場合、直前のスペースは不要 3 // ・文字列がtextarea末尾の場合、直後のスペースは不要 4 // の処理を簡単にするために前後に半角スペースを入れる 5 const haystack = ` ${str} `; 6 7 // タグの開始直前に許容する記号の一覧 8 const prefixChars = ['、', '。']; 9 const reg = new RegExp(`([ \s${prefixChars.join('')}])([##][^\s ]+)`, 'g'); // 1:53修正→Sep 25 18:55再編集 10 const replaced = haystack.replace(reg, (match, prefix, tagging) => `${prefix}<span class="tag">${tagging}</span>`); 11 $('#clone').html(replaced.substring(1, replaced.length - 1)); // Sep 26, 2:51編集 12}

投稿2019/09/21 08:35

編集2019/09/25 17:52
thyda.eiqau

総合スコア2982

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DiningKitchen

2019/09/21 09:45 編集

先にスペースいれるのナイス発想ですね。唸りました。直前のタグを自由に指定できるご配慮も感謝です。ありがとうございます。 あとは、質問にある改行問題(hellをタグ化したい)と、そして改行直後の行頭(#can)もタグ化できれば…と思います。下記画像の2つです。 https://imgur.com/a/YylPOnQ
DiningKitchen

2019/09/21 10:40

>Sep 21, 2019 19:00追記 追記ありがとうございます。画像を拝見して「|」などを加えて【修正】としましたところ、惜しいところまでできました。 【最初のreg】 const reg = new RegExp(`([  ${prefixChars.join('')}])([##].+?)([  ])`, 'g'); 【修正】 const reg = new RegExp(`([  \r\n|${  prefixChars.join('')}])([##].+?)([  \r\n])`, 'g'); ですが、 #yes #we #can と入れると、なぜか「#we」だけがタグ認定されない事態に… https://jsfiddle.net/4nc9aLp8/ 正規表現ムズカシすぎます(笑)
DiningKitchen

2019/09/21 17:32 編集

>編集 2019/09/22 01:53 ご編集ありがとうございます。残念ながらそちらも動かずでした。
thyda.eiqau

2019/09/25 09:56

失礼、こちらコメント見落としていました。再編集しましたのでご確認ください。こちらではJSFiddleで確認済みです。
DiningKitchen

2019/09/25 17:49

捨てられてしまったかと思いましたwありがとうございます。 たびたび心苦しいのですが、そちら「18:55再編集」は最後の文字が切れてしまいますね…↓ https://jsfiddle.net/e21zsja6/
DiningKitchen

2019/09/27 00:18

最後の文字、ムズカシそうですね。ひとまず時間も経ってしまったので、ベストアンサーは質問の仕様を解決してくださったyambejpさんへ差し上げたいと思います。 でも文字のコピー方法はthyda.eiqau様のコードが参考になりました。 あとはタグリストの抽出方法で躓いていますが、お二方のコードを参考にしつつ、本を買ったので自力でなんとか目的のものに近づけるよう頑張りたいと思います。どうもありがとうございました。
thyda.eiqau

2019/09/27 00:21

最後の文字が切れる点は9/26 2:52の編集でも解決してないですか?
DiningKitchen

2019/09/27 00:23

申し訳ございません!そちらのご編集は未確認でした…。 なるほど、できています!お見事です。今見たら通知も来ていました。すみませんでした。
thyda.eiqau

2019/09/27 01:17

解決されたようで何よりです
DiningKitchen

2019/09/27 12:53

正規表現の部分はyambejp様のコードを使うと前後に半角を入れなくても済むので採用し、コピーする部分はthyda.eiqau様のコードを採用させて頂きました。生意気にいいとこどりしてすみません笑 あと今更の質問で恐縮です。replaceの第二引数の3つ(match, prefix, tagging)がよくわからないのですが、replaceというのは第二引数に3つの値をもつことができるのでしょうか?ほかにもありますか?調べてもそれが載っておらず、恐れながら質問させて頂きました。もしお目に留まりましたがご留意いただけたら幸いです。
guest

0

ベストアンサー

javascript

1<script> 2window.addEventListener('DOMContentLoaded', ()=>{ 3 document.querySelector('#btn').addEventListener('click',()=>{ 4 var txt=document.querySelector('#keyword').textContent; 5 var reg=/(#.+?)(?=\b|$)/g; 6 console.log(txt.replace(reg,'<span>$1</span>')); 7 }); 8}); 9</script> 10<textarea type="text" id="keyword" class="box" placeholder="#をつけるハッシュ検索" value="">#hello world #yes we #can</textarea> 11<div id="clone" class="box"></div> 12<button id="btn">clone</button>

調整

javascript

1<script> 2window.addEventListener('DOMContentLoaded', ()=>{ 3 document.querySelector('#btn').addEventListener('click',()=>{ 4 [].forEach.call(document.querySelectorAll('.box'),x=>{ 5 var txt=x.textContent; 6 var reg=/(^|[\s。!])(#.+?)(?=\s|$)/g; 7 console.log(txt.replace(reg,'$1<span>$2</span>')); 8 }); 9 }); 10}); 11</script> 12<textarea type="text" class="box">こんにちは#良い天気ですね。</textarea> 13<textarea type="text" class="box">こんにちは #良い天気ですね。</textarea> 14<textarea type="text" class="box">こんにちは #良い天気 ですね。</textarea> 15<textarea type="text" class="box">こんにちは。#良い天気 ですね。まったく!#その通り です。&#13;#明日 は雨かも。</textarea> 16<textarea type="text" class="box">#良い天気 ですね。今日のごはんはどうしましょうか。寒いから #鍋?</textarea> 17<input type="button" id="btn" value="btn">

※「記号」というのは任意で列挙が必要です
「[\s。!]」のところに追記してください(\sは空白文字)

配列に受ける

javascript

1<script> 2window.addEventListener('DOMContentLoaded', ()=>{ 3 document.querySelector('#btn').addEventListener('click',()=>{ 4 [].forEach.call(document.querySelectorAll('.box'),x=>{ 5 var txt=x.textContent; 6 var reg1=/(^|[\s。!])#.+?(?=\s|$)/g; 7 var reg2=/^[\s。!]+/g; 8 var arr=(txt.match(reg1)||[]).map(x=>x.replace(reg2,'')); 9 console.log(arr); 10 }); 11 }); 12}); 13</script> 14<textarea type="text" class="box">こんにちは#良い天気ですね。</textarea> 15<textarea type="text" class="box">こんにちは #良い天気ですね。</textarea> 16<textarea type="text" class="box">こんにちは #良い天気 ですね。</textarea> 17<textarea type="text" class="box">こんにちは。#良い天気 ですね。まったく!#その通り です。&#13;#明日 は雨かも。</textarea> 18<textarea type="text" class="box">#良い天気 ですね。今日のごはんはどうしましょうか。寒いから #鍋?</textarea> 19<textarea type="text" class="box">#hello world 20#yes we #can 21#abc</textarea> 22<input type="button" id="btn" value="btn"> 23

投稿2019/09/20 10:32

編集2019/09/27 01:35
yambejp

総合スコア116690

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DiningKitchen

2019/09/20 11:11 編集

twittetrをイメージして頂きたかったのですが、タグとして認識したい条件をお伝えし忘れておりましたので、質問文に補足しておきました。申し訳ございませんでした。
yambejp

2019/09/20 11:09 編集

ご指摘の例を網羅した適用前後(○○→××のような変化がわかるもの)のtextを提示ください
DiningKitchen

2019/09/20 11:10

たしかに、文章ではわかりにくいですね。いろいろすみません。数分お待ちくださいませ。列挙させて頂きます。
yambejp

2019/09/20 11:28

ごめん、連休なので火曜まで回答できないかも あしからず
DiningKitchen

2019/09/20 11:49

>ごめん、連休なので火曜まで回答できないかも わかりました。またのご返答をお待ちしております。お忙しい中ありがとうございます。m(_ _)m
yambejp

2019/09/24 01:07

例示された分は対応しました。 挙動を確認の上、別途対処が必要なものは追加で再提示ください
DiningKitchen

2019/09/27 00:24 編集

どうもありがとうございます! 1つだけ、改行時に改行やスペースが混じってしまうという問題がございました。 自分なりに . map() を使って解消を試みた(9行目)のですが… https://jsfiddle.net/q9v1wfLk/ この改行などをタグリストの配列から削除するにはどのようにすべきでしょうか? 12行目のコンソールを [ "#hello", "\n#yes", " #can" ] でなく [ "#hello", "#yes", "#can" ] にしたい。という意味です。
DiningKitchen

2019/09/27 00:20

遅ればせながらベストアンサーにさせて頂きました。上のタグリストの問題はもう少し頑張ってみます。連休明けのお忙しい中どうもありがとうございました。
yambejp

2019/09/27 01:36 編集

JSの正規表現は肯定後読みが無いので一度ヒットさせて該当箇所を取り除く処理が必要です 「配列に受ける」を追記しておきました。動作確認ください
DiningKitchen

2019/09/27 12:47

配列に受ける版まで、ありがとうございます。頂戴したコードは大変すっきりしていますね。 実はあれから自分でも挑戦していたのですが(https://jsfiddle.net/tunrL9bz/)、この16行目で「ここが null になってしまう」のはなぜなのか、もし、よろしければ…教えていただけませんでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問