Skip to content

Commit 8776166

Browse files
azuclaude
andauthored
feat(string): ES2025のRegExp.escapeメソッドを追加 (#1837)
## 変更点 - 正規表現オブジェクトセクションに`RegExp.escape`メソッドの説明を追加 - 特殊文字のエスケープについて説明した後に、ES2025の新機能として紹介 - 正規表現の特殊文字を安全にエスケープする基本的な使い方を示すコード例を追加 - 文字列の置換/削除セクションの`replaceAll`のコード例に`RegExp.escape`を使った例を追加 - 既存のコード例に自然に組み込む形で、実用的な使用例を提示 ```js RegExp.escape("+"); // \+ ``` ## URL https://jsprimer.net/basic/string/#regexp-escape ## 関連 fix #1781 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude <[email protected]>
1 parent b9884da commit 8776166

File tree

6 files changed

+313
-10
lines changed

6 files changed

+313
-10
lines changed

source/basic/string/README.md

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -546,13 +546,8 @@ console.log(str.includes("いる")); // => true
546546

547547
正規表現は正規表現オブジェクト(`RegExp`オブジェクト)として表現されます。
548548
正規表現オブジェクトはマッチする範囲を決める`パターン`と正規表現の検索モードを指定する`フラグ`の2つで構成されます。
549-
正規表現のパターン内では、次の文字は**特殊文字**と呼ばれ、特別な意味を持ちます。特殊文字として解釈されないように入力する場合には`\`(バックスラッシュ)でエスケープする必要があります。
550549

551-
```
552-
\ ^ $ . * + ? ( ) [ ] { } |
553-
```
554-
555-
正規表現オブジェクトを作成するには、正規表現リテラルと`RegExp`コンストラクタを使う2つの方法があります。
550+
正規表現オブジェクトを作成するには、正規表現リテラルと`RegExp`コンストラクタを使う2つの方法があります。正規表現リテラルは、`/``/`のリテラル内に正規表現のパターンを書くことで、正規表現オブジェクトを作成でき、`RegExp`コンストラクタは文字列から正規表現オブジェクトを作成できます。
556551

557552
<!-- textlint-disable eslint -->
558553
<!-- doctest:disable -->
@@ -564,7 +559,15 @@ const patternB = new RegExp("パターン文字列", "フラグ");
564559
```
565560
<!-- textlint-enable eslint -->
566561

567-
正規表現リテラルは、`/``/`のリテラル内に正規表現のパターンを書くことで、正規表現オブジェクトを作成できます。
562+
563+
正規表現のパターン内では、次の文字は**特殊文字**と呼ばれ、特別な意味を持ちます。
564+
565+
```
566+
\ ^ $ . * + ? ( ) [ ] { } |
567+
```
568+
569+
たとえば、`+`は1回以上の繰り返しを意味する特殊文字です。
570+
568571
次のコードでは、`+`という1回以上の繰り返しを意味する特殊文字を使い、`a`が1回以上連続する文字列にマッチする正規表現オブジェクトを作成しています。
569572

570573
```js
@@ -581,6 +584,21 @@ const pattern = /a+/;
581584
const pattern = new RegExp("a+");
582585
```
583586

587+
正規表現では、特殊文字をそのまま文字として扱いたい場合は、バックスラッシュ(`\`)でエスケープする必要があります。
588+
589+
たとえば、`+`という特殊文字をそのまま文字として扱いたい場合は、`\+`のようにバックスラッシュでエスケープします。
590+
591+
また、ES2025では、`RegExp.escape`メソッドが追加され、正規表現の特殊文字を安全にエスケープできます。`RegExp.escape`メソッドを使うことで、文字列の中に正規表現として意味を持つ特殊文字が含まれていても、自動的にエスケープできます。
592+
593+
{{book.console}}
594+
<!-- doctest:meta:{ "ECMAScript": "2025" } -->
595+
```js
596+
const escaped = RegExp.escape("+");
597+
console.log(escaped); // \+
598+
```
599+
600+
<!-- "\\+" と書きたいけど、見た目が微妙なので\+にしている -->
601+
584602
### 正規表現リテラルと`RegExp`コンストラクタの違い {#difference-regexp-literal-regexp-constructor}
585603

586604
<!-- 評価とコンパイルは仕様から来てる用語 https://tc39.es/ecma262/#sec-pattern -->
@@ -1047,17 +1065,19 @@ Stringの`replaceAll`メソッドでは、正規表現ではなく文字列を
10471065
そのため、正規表現では特殊な意味を持つ`?`のような文字列も検索文字列にそのまま書いて置換ができます。
10481066

10491067
{{book.console}}
1050-
<!-- doctest:meta:{ "ECMAScript": "2021" } -->
1068+
<!-- doctest:meta:{ "ECMAScript": "2025" } -->
10511069
```js
10521070
// 検索対象となる文字列
10531071
const str = "???";
10541072
// replaceメソッドに文字列を指定した場合は、最初に一致したものだけが置換される
10551073
console.log(str.replace("?", "!")); // => "!??"
10561074
// replaceAllメソッドに文字列を指定した場合は、一致したものがすべて置換される
10571075
console.log(str.replaceAll("?", "!")); // => "!!!"
1058-
// replaceメソッドの場合は、正規表現の特殊文字はエスケープが必要となる
1076+
// replaceメソッドに正規表現を渡す場合、正規表現の特殊文字はエスケープが必要
10591077
console.log(str.replace(/\?/g, "!")); // => "!!!"
1060-
// replaceAllメソッドにも正規表現を渡せるが、この場合はエスケープが必要となるためreplaceと同じ
1078+
// RegExp.escapeとreplaceメソッドを使った場合(ES2025)
1079+
console.log(str.replace(new RegExp(RegExp.escape("?"), "g"), "!")); // => "!!!"
1080+
// replaceAllメソッドにも正規表現を渡せるが、この場合もエスケープが必要(replaceと同様)
10611081
console.log(str.replaceAll(/\?/g, "!")); // => "!!!"
10621082
```
10631083

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# 設計ファイル: RegExp.escape メソッドのドキュメント追加
2+
3+
## 追加位置
4+
5+
### ファイルパス
6+
`/source/basic/string/README.md`
7+
8+
### 追加位置1: 正規表現オブジェクトセクション
9+
「正規表現オブジェクト」セクション(540行目付近)の`RegExp`コンストラクタの説明の後に追加
10+
11+
理由:
12+
- `RegExp`関連のメソッドとして自然な位置
13+
- 正規表現の特殊文字のエスケープについて説明した直後なので文脈的に適切
14+
15+
### 追加位置2: replaceメソッドのコード例
16+
「文字列の置換/削除」セクション(1056-1062行目)のコード例に`RegExp.escape`を使った例を追加
17+
- 特に説明を加えず、自然にコード例の一部として含める
18+
19+
## ドキュメント構造
20+
21+
### 正規表現オブジェクトセクションへの追加
22+
23+
#### セクション名
24+
`### [ES2025] RegExp.escape {#regexp-escape}`
25+
26+
#### 内容構成
27+
1. **導入説明**(1段落)
28+
- メソッドの目的:正規表現の特殊文字を安全にエスケープ
29+
- ES2025で追加された新機能であることを明記
30+
31+
2. **基本的な使い方**(コード例1つ)
32+
- シンプルな例で`RegExp.escape`の基本動作を示す
33+
- 特殊文字のエスケープ例
34+
35+
### replaceメソッドセクションへの追加
36+
既存のコード例に1行追加するだけ:
37+
```js
38+
// RegExp.escapeを使った場合
39+
console.log(str.replace(new RegExp(RegExp.escape("?"), "g"), "!")); // => "!!!"
40+
```
41+
42+
## コード例の設計
43+
44+
### 正規表現オブジェクトセクションでの基本例
45+
46+
↓みたいに変更するイメージ
47+
48+
## 正規表現オブジェクト {#regexp-object}
49+
50+
<!-- パターンと正規表現オブジェクトの用語については https://github.com/asciidwango/js-primer/issues/21#issuecomment-293502813 -->
51+
52+
文字列による検索では、固定の文字列にマッチするものしか検索できません。
53+
一方で正規表現による検索では、あるパターン(規則性)にマッチするという柔軟な検索ができます。
54+
55+
正規表現は正規表現オブジェクト(`RegExp`オブジェクト)として表現されます。
56+
正規表現オブジェクトはマッチする範囲を決める`パターン`と正規表現の検索モードを指定する`フラグ`の2つで構成されます。
57+
58+
正規表現オブジェクトを作成するには、正規表現リテラルと`RegExp`コンストラクタを使う2つの方法があります。正規表現リテラルは、`/``/`のリテラル内に正規表現のパターンを書くことで、正規表現オブジェクトを作成でき、`RegExp`コンストラクタは文字列から正規表現オブジェクトを作成できます。
59+
60+
<!-- textlint-disable eslint -->
61+
<!-- doctest:disable -->
62+
```js
63+
// 正規表現リテラルで正規表現オブジェクトを作成
64+
const patternA = /パターン/フラグ;
65+
// `RegExp`コンストラクタで正規表現オブジェクトを作成
66+
const patternB = new RegExp("パターン文字列", "フラグ");
67+
```
68+
<!-- textlint-enable eslint -->
69+
70+
71+
正規表現のパターン内では、次の文字は**特殊文字**と呼ばれ、特別な意味を持ちます。
72+
73+
```
74+
\ ^ $ . * + ? ( ) [ ] { } |
75+
```
76+
77+
たとえば、`+`は1回以上の繰り返しを意味する特殊文字です。
78+
79+
次のコードでは、`+`という1回以上の繰り返しを意味する特殊文字を使い、`a`が1回以上連続する文字列にマッチする正規表現オブジェクトを作成しています。
80+
81+
```js
82+
const pattern = /a+/;
83+
```
84+
85+
正規表現オブジェクトを作成するもうひとつの方法として`RegExp`コンストラクタがあります。
86+
`RegExp`コンストラクタでは、文字列から正規表現オブジェクトを作成できます。
87+
88+
次のコードでは、`RegExp`コンストラクタを使って`a`が1文字以上連続している文字列にマッチする正規表現オブジェクトを作成しています。
89+
これは先ほどの正規表現リテラルで作成した正規表現オブジェクトと同じ意味になります。
90+
91+
```js
92+
const pattern = new RegExp("a+");
93+
```
94+
95+
正規表現では、特殊文字をそのまま文字として扱いたい場合は、バックスラッシュ(`\`)でエスケープする必要があります。
96+
97+
たとえば、`+`という特殊文字をそのまま文字として扱いたい場合は、`\+`のようにバックスラッシュでエスケープします。
98+
99+
ES2025では、`RegExp.escape`メソッドが追加され、正規表現の特殊文字を簡単にエスケープできるようになりました。このメソッドを使うことで、手動でエスケープする手間が省けます。
100+
101+
```js
102+
const escaped = RegExp.escape("a+b?c");
103+
console.log(escaped); // => "a\+b\?c"
104+
```
105+
106+
### replaceセクションでの追加例(既存コードに混ぜる)
107+
```js
108+
const str = "???";
109+
// ... 既存のコード例 ...
110+
// replaceAllメソッドに文字列を指定した場合は、一致したものがすべて置換される
111+
console.log(str.replaceAll("?", "!")); // => "!!!"
112+
// replaceメソッドの場合は、正規表現の特殊文字はエスケープが必要となる
113+
console.log(str.replace(/\?/g, "!")); // => "!!!"
114+
// RegExp.escapeを使った場合(ES2025)
115+
console.log(str.replace(new RegExp(RegExp.escape("?"), "g"), "!")); // => "!!!"
116+
// replaceAllメソッドにも正規表現を渡せるが、この場合はエスケープが必要となるためreplaceと同じ
117+
console.log(str.replaceAll(/\?/g, "!")); // => "!!!"
118+
```
119+
120+
## 文体と形式
121+
122+
### 既存の文体に合わせる要素
123+
- `{{book.console}}`タグの使用
124+
- コード例の前後に説明文を配置
125+
- コメントは`// =>`形式で結果を示す
126+
- ES仕様年の明記([ES2025]タグ)
127+
- アンカーリンク用のID(`{#regexp-escape}`
128+
129+
### トーンの統一
130+
- 「〜できます」調の丁寧な説明
131+
- 技術的詳細は最小限に
132+
- 初心者にも理解しやすい言葉選び
133+
134+
## 他セクションとの関連
135+
136+
### 参照すべき既存セクション
137+
- 正規表現オブジェクト(line 540-)
138+
- 正規表現リテラルとRegExpコンストラクタの違い(line 584-)
139+
- 文字列の置換/削除(line 989-)
140+
141+
### 相互参照の追加
142+
- 正規表現の特殊文字の説明箇所から`RegExp.escape`への言及を検討(オプション)
143+
144+
## 制約事項の遵守
145+
146+
### 軽い説明に留める
147+
- メソッドの内部実装には触れない
148+
- エスケープされる全特殊文字のリストは載せない
149+
- 基本的な使い方と利点の説明に焦点
150+
151+
### 初心者向けの配慮
152+
- 正規表現の知識が浅くても理解できる説明
153+
- 実用的なユースケースを提示
154+
- 過度に技術的な用語を避ける
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# 実装計画ファイル: RegExp.escape メソッドのドキュメント追加
2+
3+
## 実装手順
4+
5+
### ステップ1: 正規表現オブジェクトセクションの修正
6+
**ファイル**: `/source/basic/string/README.md`
7+
**位置**: 541-598行目(正規表現オブジェクトセクション全体を置き換え)
8+
9+
#### 変更内容:
10+
1. 既存の正規表現オブジェクトセクションの内容を維持
11+
2. 特殊文字のエスケープの説明の後に`RegExp.escape`メソッドを追加
12+
3. ES2025のdoctestメタデータを追加
13+
14+
具体的には以下のような構造に変更:
15+
- 正規表現オブジェクトの説明
16+
- 正規表現リテラルと`RegExp`コンストラクタの説明
17+
- 特殊文字の説明
18+
- **NEW: 特殊文字のエスケープと`RegExp.escape`メソッドの説明**
19+
20+
### ステップ2: replaceメソッドのコード例への追加
21+
**ファイル**: `/source/basic/string/README.md`
22+
**位置**: 1074行目(既存のコード例の中)
23+
24+
#### 変更内容:
25+
既存のコード例に1行追加:
26+
```js
27+
// 既存の行の後に追加
28+
console.log(str.replace(/\?/g, "!")); // => "!!!"
29+
// RegExp.escapeを使った場合(ES2025)
30+
console.log(str.replace(new RegExp(RegExp.escape("?"), "g"), "!")); // => "!!!"
31+
```
32+
33+
### ステップ3: doctestメタデータの追加
34+
両方のコード例に`<!-- doctest:meta:{ "ECMAScript": "2025" } -->`を追加して、ES2025環境でのテストを指定
35+
36+
## 実装の注意点
37+
38+
### 1. 既存コードへの影響
39+
- 既存のセクション構造を崩さない
40+
- 行番号の変更に注意(後続のセクションへの影響)
41+
42+
### 2. コード例の動作確認
43+
- `{{book.console}}`タグを正しく配置
44+
- コメントの`// =>`形式を統一
45+
- doctestメタデータでES2025を指定
46+
47+
### 3. 文体の統一
48+
- 「〜できます」「〜します」調を維持
49+
- 既存の説明と同じレベルの詳細度
50+
51+
## 検証項目
52+
53+
### 実装後の確認
54+
1. マークダウンの構文が正しいか
55+
2. コード例が実行可能か
56+
3. 既存のドキュメントと自然に統合されているか
57+
4. アンカーリンク(`#regexp-escape`)が機能するか
58+
59+
### テスト
60+
- doctestが通るか確認(ES2025環境)
61+
- ビルドエラーがないか確認
62+
63+
## リスクと対策
64+
65+
### リスク1: ES2025のブラウザサポート
66+
**対策**: doctestメタデータで明示的にES2025を指定し、サポート状況を示す
67+
68+
### リスク2: 既存の説明との重複
69+
**対策**: 正規表現の特殊文字の説明は最小限にし、既存の説明を参照
70+
71+
## 完了基準
72+
- [ ] 正規表現オブジェクトセクションに`RegExp.escape`の説明を追加
73+
- [ ] replaceメソッドのコード例に`RegExp.escape`の使用例を追加
74+
- [ ] doctestメタデータを適切に設定
75+
- [ ] マークダウンのビルドが成功
76+
- [ ] 既存のドキュメントと自然に統合されている
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# 要件ファイル: RegExp.escape メソッドのドキュメント追加
2+
3+
## 概要
4+
ES2025で追加される`RegExp.escape`メソッドについて、js-primerの文字列の章にドキュメントを追加する。
5+
6+
## 機能要件
7+
8+
### 1. ドキュメントの追加位置
9+
- `/source/basic/string/README.md`ファイルに追加
10+
- 正規表現関連のセクション(文字列の検索や置換の文脈)に追加
11+
12+
### 2. 説明内容
13+
- `RegExp.escape`メソッドの基本的な説明
14+
- メソッドの目的:正規表現の特殊文字を安全にエスケープする
15+
- ES2025で追加される新機能であることを明記
16+
17+
### 3. コード例
18+
- 基本的な使用例を提供
19+
- `replaceAll`メソッドと組み合わせた実用的な例
20+
- エスケープが必要な特殊文字の例(例:`?``.``*`など)
21+
22+
### 4. 説明のトーン
23+
- 初心者にも理解しやすい簡潔な説明
24+
- 必須ではないが便利な機能であることを伝える
25+
- 複雑になりすぎない程度の説明に留める
26+
- 既存の文章を参考にする source/basic/string/README.md を合わせる
27+
28+
## 非機能要件
29+
30+
### 1. 文書の一貫性
31+
- 既存のjs-primerの文体・形式に合わせる
32+
- 他のメソッドの説明と同じレベルの詳細度
33+
34+
### 2. コード例の品質
35+
- 実行可能で正確なコード例
36+
- コメントを適切に付けて理解しやすくする
37+
38+
### 3. 互換性の言及
39+
- ES2025の機能であることを明確にする
40+
- 必要に応じてブラウザサポート状況への言及
41+
42+
## 制約事項
43+
- 軽い説明に留める(issueの要望通り)
44+
- 過度に技術的な詳細は避ける
45+
- 初心者向けのプライマーの性質を維持する
46+
47+
## 成功基準
48+
- `RegExp.escape`の基本的な使い方が理解できる
49+
- なぜこのメソッドが便利なのかが伝わる
50+
- 既存のドキュメントと自然に統合されている

test/front-matter-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ describe("front-matter", function() {
2222
`!${sourceDir}/**/SCREENSHOT.md`,
2323
// サンプルコードの一部
2424
`!${sourceDir}/use-case/nodecli/**/src/**/sample*.md`,
25+
// specsディレクトリは除く
26+
`!${sourceDir}/**/specs/**/*.md`,
2527
]);
2628
describe("author", function() {
2729
files.forEach(filePath => {

test/markdown-doc-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe("doctest:md", function() {
6060
const files = globbySync([
6161
`${sourceDir}/**/*.md`,
6262
`!${sourceDir}/**/node_modules{,/**}`,
63+
`!${sourceDir}/**/specs/**/*.md`,
6364
`!**/OUTLINE.md`
6465
]);
6566
files.forEach(filePath => {

0 commit comments

Comments
 (0)