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

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

新規登録して質問してみよう
ただいま回答率
85.35%
正規表現

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

Q&A

解決済

1回答

950閲覧

正規表現:英単語にはヒットさせHTMLエスケープにはヒットさせない方法

benkyo.fun

総合スコア9

正規表現

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

0グッド

1クリップ

投稿2021/12/05 00:38

正規表現のパターンで悩んでいます。環境はPC・モバイルのブラウザで、JavaScript内で正規表現を使用しています。
HTML内に記述されている英単語に一括してaタグを付けたいので、以下のような正規表現で置換を実行しています。

regularExpression = /([a-zA-ZÀ-ÿ]+)/g;

これで概ね問題なく置換ができているのですが、HTMLのエスケープ文字がある文書の場合、中間部分にヒットしてしまいます。<であればltにヒットします。
これを避けるため、否定後読みで対応しようとしたのですが、

regularExpression = /((?<!&)[a-zA-ZÀ-ÿ]+)/g;

これですと、<であればtにヒットします。lが&の存在によりアンマッチとなった次に、tからマッチングを開始してtがマッチしたのだと推測しています。
HTMLエスケープの末尾の;は、英文中でも単語末尾に登場しますので、後読み無しで単独で使用することはできません。
そこで、先読みと組み合わせて、

regularExpression = /((?<!&)[a-zA-ZÀ-ÿ]+(?!;))/g;

前後を条件として記述したところ、PC環境のChromeでは成功する(HTMLエスケープ以外の英単語にマッチする)のですが、MacのSafariとモバイル環境SafariとChromeでは、なぜか、HTMLエスケープだけでなく、すべての単語にマッチしなくなります(先の2つのパターンはいずれの環境でもマッチング結果は同じです)。
なお、
・英文の空白部分にはマッチさせたくないので、「空白に続くアルファベット文字列」というパターンは使用したくありません。
・文章全体の置換なので重い処理ですから、予めHTMLエスケープ文字を代替文字に置換しておいて、もう一度HTMLエスケープに戻すという2回の置換を行う策は避けたいです。

できれば正規表現による置換だけで目的を達成したいのですが、手詰まりになってしまいました。皆様お知恵拝借させて下さい。よろしくおねがいします。

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

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

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

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

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

maisumakun

2021/12/05 01:08

> できれば正規表現による置換だけで目的を達成したいのですが textContentから拾えば、エスケープは展開されて文字になっているかと思うのですが、そういう手段は取れないのでしょうか?
benkyo.fun

2021/12/05 01:22 編集

(すみません。削除しました。)
benkyo.fun

2021/12/05 01:37

通常のHTML文書なので、構文要素として<div>や<br>を含んでいるため、textContentで取得してしまうと、これらが消失し、後で戻すときに体裁が復元できないようです。
otn

2021/12/05 03:23

調べるとSafariは後読みに対応してないという記述が見つかります。 Chromeは問題なし。 ということで、 > MacのSafariとモバイル環境SafariとChromeでは、なぜか、HTMLエスケープだけでなく、すべての単語にマッチしなくなります(先の2つのパターンはいずれの環境でもマッチング結果は同じです)。 は、確認ミスでは無いでしょうか。Safariのみ2つ目と3つ目が他と異なるという結果になるはず。
benkyo.fun

2021/12/05 03:47 編集

失礼しました。たしかにご指摘の通りで、Safariは2つ目と3つ目で、マッチに失敗します。 一方、Chromeは、再度確認してみましたが、デスクトップ版(Mac Versión 96.0.4664.55 (Build oficial) (x86_64))では、3つ目はマッチに成功しますが、モバイル版(iPhone 96.0.4664.53)ではマッチに失敗します。 まとめますと、以下の通りです。 2番目 regularExpression = /((?<!&)[a-zA-ZÀ-ÿ]+)/g; Mac Safari iPhone Safari この2つは同じ結果  何にもマッチしない Mac Chrome iPhone Chrome この2つは同じ結果  &lt;のtにマッチ 3番目 regularExpression = /((?<!&)[a-zA-ZÀ-ÿ]+(?!;))/g; Mac Safari iPhone Safari この2つは同じ結果  何にもマッチしない Mac Chrome  英単語にはマッチしてHTMLエスケープにはマッチしない iPhone Chrome  何にもマッチしない
otn

2021/12/05 08:41

AndroidのChromeだと3番目で問題ないですね。
benkyo.fun

2021/12/06 01:47

確認ありがとうございます。そうなんですね。 iOSのアプリでChromeをエンベッドブラウザにしている他のアプリからでも同じ現象でした。正規表現でだけでなんとかできるに越したことはないのですが、環境起因の制限があるとすると厳しいですね。
guest

回答1

0

ベストアンサー

コールバック付きの置換を行って、「&***の形も拾うけど、そこは置換せず返す」ことで対応する方法はどうでしょうか?(MDN

javascript

1text.replace(/&?([a-zA-ZÀ-ÿ]+)/g, (match) => match[0] === '&' ? match : `<a>${match}</a>`)

投稿2021/12/05 01:26

maisumakun

総合スコア146018

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

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

benkyo.fun

2021/12/05 01:48

ありがとうございます。要望が実現できました。 処理が一つ増えますが、全体を何度も置換するよりはよっぽど速そうです。
benkyo.fun

2021/12/05 01:49

replaceの第二引数は関数が指定できるんですね。勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問