質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

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

jQuery

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

Q&A

解決済

3回答

549閲覧

JavaScriptのreplaceで、連続したmatchを効かせたいです

mezamashiTV

総合スコア6

JavaScript

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

jQuery

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

0グッド

0クリップ

投稿2020/04/02 05:31

編集2020/04/02 06:15

###実現したいこと
テキストのタグ#タグとしたいです。

この条件がございまして、実は全てクリアできています。
・前にシャープをつける
・後ろにスペースをつける
・前がpattern.match()しなければ前にスペースをつける
・先頭なら前のスペースなし、末尾なら後ろのスペースなし
・タグが連続したあ間のスペースは1つ
・元からタグならそのまま

###問題
昨日から取り組んでいる内容で、教えて頂いたり改変したりでなんとか上の条件はクリアできました。

以下のようにstr
食パンあとジャムパンあとごまあんぱんのときは
#食パン あと #ジャムパン あと #ごまあんぱんとなり理想的なのですが、

しかしstr
食パンジャムパンごまあんぱんのときは
#食パン ジャムパン #ごまあんぱんとなってしまいます。

ジャムパンが抜けてしまうのです。

###コード
こちらは昨日yambejp様から頂戴したコードについて、is_tag()escapeRegExp()という関数を加えたものになります。

実行して頂くとジャムパンが抜けてしまうことがご覧いただけるかと思います。

JavaScript

1var ARR = [ 2 {name:'食パン',id:1}, 3 {name:'あんぱん',id:2}, 4 {name:'ごまあんぱん',id:3}, 5 {name:'食パン(はちみつ味)',id:4}, 6 {name:'ジャムパン',id:5} 7]; 8 9var str = "食パンジャムパンごまあんぱん"; 10console.log( get(str) ); // ジャムパンが抜けてしまう 11 12function get( str ){ 13 14 var pattern = ["","。","、","!","!"]; 15 16 var reg = new RegExp("(^|.)("+ARR.map(x=>escapeRegExp(x.name)).sort((x,y)=>x.length<y.length).join('|')+")(.|$)","g"); 17 18 var res = str.replace( 19 20 reg,x=>( ( r=x.match(new RegExp(reg.source)) ) ) && 21 22 // 元からタグの場合はそのまま 23 is_tag(r[1],r[3]) ? x : 24 25 // タグ化する 26 r[1] 27 + ( pattern.indexOf(r[1])>=0 ? "" : " " ) 28 + "#" 29 + r[2] 30 + ( r[3]=="" ? "" : " " ) 31 + r[3] 32 33 ); 34 35 return res; 36 37 // 前がシャープ、後がスペース|patternならばタグ 38 function is_tag( before, after ){ 39 var before_match = before.match(/^[##]$/); 40 var after_match = after.match(/^\s$/) || after.match(pattern); 41 return ( before_match && after_match ) ? true : false; 42 } 43} 44 45// 正規表現をエスケープ 46function escapeRegExp(string) { 47 return string.replace(/[\^$.*+?()[]{}|]/g, '\$&'); 48} 49

###試したこと
ジャムパンが受け取れない原因をさぐるためにxを出力してみましたら、やはりこの結果がおかしかったです。

var res = str.replace( reg,x=>( ( r=x.match(new RegExp(reg.source)) ) ) && console.log('x=「'+x+'」') );

以下の結果となり、ジャムパンが受け取れないのはやはりxがおかしいからだとわかりましたが…しかし、いつどこでジャムパンが消えてしまうのか、どうしてもわかりません。

x=「食パンジ」 x=「ンごまあんぱん」

さらに以下でreg.sourcestrもみましたが、それらにはジャムパンがありました。いつxからジャムパンが消えてしまうのか、さっぱりです。

var res = str.replace( reg,x=>( ( r=x.match(new RegExp(reg.source)) ) ) && console.log('x=「'+x+'」') +console.log('str=「'+str+'」') +console.log('reg.source=「'+JSON.stringify(reg.source)+'」') );

どうすればジャムパンについても実現できますでしょうか。

###補足情報(FW/ツールのバージョンなど)

特にバージョン情報は関係ないかと思いますが、もし解決策にjQueryをお使いになる場合がございましたら、最新の3.4での方法でお願いできましたら幸いです。

何卒、宜しくお願いいたします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

乗りかかった船なので一応以下で

投稿2020/04/02 07:09

yambejp

総合スコア114829

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

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

mezamashiTV

2020/04/02 07:44

えなななんですかこれ…好きに入力できるように作ってくださったんですか…信じられません(泣)本当にありがとうございます。 連日貴重なお時間を割いて下さいまして心より感謝申し上げます。
yambejp

2020/04/02 07:53

重要なのは ・まずはマッチした文字を抜き出すこと ・次に前後の文字を拾っておくこと これができれば8割完成しています。 たぶんもっと効率的な書き方があるのですが 効率性をあげると拡張性が犠牲になるので 落とし所が難しいですよね・・・ あとなに仕様追加が必要なら適当に質問いれておいてください
mezamashiTV

2020/04/02 10:18

なるほど。効率と拡張性で悩むケースなどかつてありませんでした(動いたからヨシな姿勢でした)が、今回その重要性を目の当たりにできるまたとない機会となりました。 正規表現のエスケープにハイフンを追加してくださったり等こまかい点までご配慮頂きまして誠にありがとうございます。おかげ様でやっとこの作業から抜け出せました。>_ _)>
guest

0

前提が共有できていないかもですが、これではダメなのですか?

js

1"食パンあとジャムパンあとごまあんぱん".replace(/(食パン|あんぱん|ごまあんぱん|食パン(はちみつ味)|ジャムパン)/g," #$& ").trim(); 2//"#食パン あと #ジャムパン あと #ごまあんぱん" 3 4"食パンジャムパンごまあんぱん";.replace(/(食パン|あんぱん|ごまあんぱん|食パン(はちみつ味)|ジャムパン)/g," #$& ").trim(); 5//"#食パン #ジャムパン #ごまあんぱん"

再挑戦を追記

js

1s.replace( 2 /(.?)(食パン|あんぱん|ごまあんぱん|食パン(はちみつ味)|ジャムパン)/g, 3 (match,p1,p2) => 4 match === p2 ? ` #${match} ` : 5 p1.match(/[。、!!]/) ? `${p1}#${p2} ` : 6 p1 !== "#" ? `${p1} #${p2} ` : 7 match 8).trim();

投稿2020/04/02 06:10

編集2020/04/02 07:16
Lhankor_Mhy

総合スコア36104

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

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

mezamashiTV

2020/04/02 06:19 編集

ありがとうございます。シンプルでいいですね。 そちらですと「// 元からタグの場合はそのまま」の処理や、「pattern」についての処理もできませんので、質問のように少し複雑な流れになっています。
Lhankor_Mhy

2020/04/02 06:36

ああ、なるほどですね。
Lhankor_Mhy

2020/04/02 07:17

もう一度チャレンジしてみました。
Lhankor_Mhy

2020/04/02 07:23

ああ、「タグが連続したあ間のスペースは1つ」がダメかあ…… 置換しちゃうのもダメか。よく考えると、元文字列の末尾スペースを生かすなら、トリムもダメなのか。 ふむむ。
yambejp

2020/04/02 07:41

結局仕様が増えてくると冗長に処理する方が早かったりするんですよねー
mezamashiTV

2020/04/02 07:47

再挑戦もありがとうございます。replaceの戻り値であるp1などを使うアプローチはいいですね。 今回もまたyambejp様が解決してくださいましたが、Lhankor_Mhy様のコードも勉強になりました。
Lhankor_Mhy

2020/04/02 08:03

回答するというよりも、パズル的に楽しませていただきました。 >結局仕様が増えてくると冗長に処理する方が早かったりするんですよねー しかりしかり。
guest

0

ジャムパンが抜けてしまう

ARR の name に 半角の (,) が利用されているためです。
正規表現パターンにおいてグループ化するための機能を持ちますので、エスケープが必要になります。

javascript

1let quotemeta = str => str.replace(/\W/g, '\$&');

追記)
エスケープはできていましたね。申し訳ありません。

"(^|.)(" + パターン + ")(.|$)" のパターンに対して
食パンジャムパンごまあんぱん とパンの名称が連続するのが原因です。

以下のようにマッチしています。

  1. 食パンジャムパンごまあんぱん」を評価し ^+"食パン"+. にマッチ

(ジャムパンのにかかるため、その次の からマッチ処理されます)
2. 「ャムパンごまあんぱん」を評価し .+"ごまあんぱん"+$ にマッチ

投稿2020/04/02 06:25

編集2020/04/02 07:25
AkitoshiManabe

総合スコア5432

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

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

mezamashiTV

2020/04/02 06:34

ありがとうございます。ご指摘の半角かっこはの部分は以下escapeRegExp()でエスケープしていると思うのですが、 ARR.map(x=>escapeRegExp(x.name)) これでは不足なのでしょうか?
AkitoshiManabe

2020/04/02 07:27

追記しました。原因についてのみ言及し、yambejp さんの codepen を参考にしてみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問