<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>テキスト編集 - CayTech Lab</title>
	<atom:link href="https://caymezon.com/tag/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E7%B7%A8%E9%9B%86/feed/" rel="self" type="application/rss+xml" />
	<link>https://caymezon.com</link>
	<description></description>
	<lastBuildDate>Sat, 28 Feb 2026 03:46:50 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://caymezon.com/wp-content/uploads/2026/01/cropped-CayTechLab-32x32.jpg</url>
	<title>テキスト編集 - CayTech Lab</title>
	<link>https://caymezon.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<atom:link rel='hub' href='https://caymezon.com/?pushpress=hub'/>
	<item>
		<title>VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</title>
		<link>https://caymezon.com/vscode-delimiter-copy-macro/</link>
					<comments>https://caymezon.com/vscode-delimiter-copy-macro/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Wed, 11 Feb 2026 07:43:41 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[VSCode]]></category>
		<category><![CDATA[エディタ]]></category>
		<category><![CDATA[テキスト編集]]></category>
		<category><![CDATA[マクロ]]></category>
		<category><![CDATA[生産性向上]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20114</guid>

					<description><![CDATA[<p>目次 はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？この記事で分かること実装した機能の概要できること対応デリミタ（18種類）3つの動作モードフォールバック機能具体的な使用場面とメリット場面1：コード内の文字 [&#8230;]</p>
<p>The post <a href="https://caymezon.com/vscode-delimiter-copy-macro/">VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？</a></li><li><a href="#toc2" tabindex="0">この記事で分かること</a></li><li><a href="#toc3" tabindex="0">実装した機能の概要</a><ol><li><a href="#toc4" tabindex="0">できること</a></li><li><a href="#toc5" tabindex="0">対応デリミタ（18種類）</a></li><li><a href="#toc6" tabindex="0">3つの動作モード</a></li><li><a href="#toc7" tabindex="0">フォールバック機能</a></li></ol></li><li><a href="#toc8" tabindex="0">具体的な使用場面とメリット</a><ol><li><a href="#toc9" tabindex="0">場面1：コード内の文字列リテラルを抽出</a></li><li><a href="#toc10" tabindex="0">場面2：ファイルパスを素早く抽出</a></li><li><a href="#toc11" tabindex="0">場面3：JSONのキーや値を抽出</a></li><li><a href="#toc12" tabindex="0">場面4：正規表現パターンを抽出</a></li><li><a href="#toc13" tabindex="0">場面5：複雑な入れ子構造から特定部分を抽出</a></li><li><a href="#toc14" tabindex="0">場面6：Markdown内のコード抜き出し</a></li><li><a href="#toc15" tabindex="0">場面7：コピー&貼り付け置換（Ctrl+Alt+Sの活用）</a></li><li><a href="#toc16" tabindex="0">メリットまとめ</a></li></ol></li><li><a href="#toc17" tabindex="0">改修履歴：ネスト構造への対応</a><ol><li><a href="#toc18" tabindex="0">改修前の問題点</a></li><li><a href="#toc19" tabindex="0">改修内容：括弧のバランスを考慮したマッチング</a></li></ol></li><li><a href="#toc20" tabindex="0">TypeScript実装の詳細</a></li><li><a href="#toc21" tabindex="0">コードのポイント解説</a><ol><li><a href="#toc22" tabindex="0">1. デリミタペアの定義</a></li><li><a href="#toc23" tabindex="0">2. コピーと選択の共通化</a></li><li><a href="#toc24" tabindex="0">3. 選択方向の判定</a></li><li><a href="#toc25" tabindex="0">4. 最も近いデリミタの優先</a></li><li><a href="#toc26" tabindex="0">5. デリミタの除外</a></li><li><a href="#toc27" tabindex="0">6. パフォーマンス最適化</a></li><li><a href="#toc28" tabindex="0">7. ネストレベル考慮のアルゴリズム</a></li></ol></li><li><a href="#toc29" tabindex="0">package.jsonの設定</a><ol><li><a href="#toc30" tabindex="0">extension.tsでの登録</a></li></ol></li><li><a href="#toc31" tabindex="0">使い方</a><ol><li><a href="#toc32" tabindex="0">基本的な使い方</a></li><li><a href="#toc33" tabindex="0">コピー&貼り付け置換の使い方</a></li><li><a href="#toc34" tabindex="0">方向別の使い方</a></li></ol></li><li><a href="#toc35" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc36" tabindex="0">Q: デリミタが認識されない</a></li><li><a href="#toc37" tabindex="0">Q: 入れ子構造で意図しない範囲が選択される</a></li><li><a href="#toc38" tabindex="0">Q: 行全体がコピーされてしまう</a></li><li><a href="#toc39" tabindex="0">Q: 動作が遅い</a></li></ol></li><li><a href="#toc40" tabindex="0">パフォーマンスについて</a><ol><li><a href="#toc41" tabindex="0">計算量</a></li><li><a href="#toc42" tabindex="0">ベンチマーク（参考値）</a></li></ol></li><li><a href="#toc43" tabindex="0">拡張アイデア</a><ol><li><a href="#toc44" tabindex="0">カスタムデリミタの設定</a></li><li><a href="#toc45" tabindex="0">複数行対応</a></li></ol></li><li><a href="#toc46" tabindex="0">まとめ：キーボード1回でデリミタ内を抜き出す快適さ</a></li><li><a href="#toc47" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに：引用符や括弧内のテキスト選択、面倒じゃないですか？</span></h2>
<p>VSCodeで文字列編集をしていて、こんな経験はありませんか？</p>
<pre><code class="language-javascript">const message = "このテキストだけコピーしたい";
const path = '/home/user/documents/report.pdf';
const config = { name: "設定値", value: 123 };</code></pre>
<p><strong>ダブルクォーテーション内の文字列だけコピーしたい</strong>ときに、以下のような操作が必要です：</p>
<ol>
<li>マウスで開始位置をクリック</li>
<li>ドラッグして終了位置まで選択</li>
<li>Ctrl+Cでコピー</li>
</ol>
<p>あるいは：</p>
<ol>
<li>Ctrl+Shift+→を何度も押して単語単位で選択</li>
<li>微調整のためにShift+→/←</li>
<li>Ctrl+Cでコピー</li>
</ol>
<p><strong>特に長い文字列や入れ子構造の場合、この作業は非常に煩雑です。</strong></p>
<p>標準のVSCodeには「Ctrl+Shift+→」「Alt+Shift+→」などの単語単位選択機能がありますが、デリミタ（区切り文字）を意識した選択には対応していません。引用符や括弧の中身だけを<strong>1キー操作で選択・コピー</strong>できたら便利だと思いませんか？</p>
<p>そこで、<strong>カーソル位置から自動でデリミタを検索し、その間のテキストを1キーで選択・コピーするTypeScriptマクロを開発しました。</strong></p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで (Software Design plus)","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/510GhCOD1FL._SL500_.jpg","\/41og2y1EEHL._SL500_.jpg","\/51XHb97PpFL._SL500_.jpg","\/51uDIY22bQL._SL500_.jpg","\/51PaoVK3MWL._SL500_.jpg","\/51eG7JBoavL._SL500_.jpg","\/51CDCo8FmJL._SL500_.jpg","\/41JLTXb+tsL._SL500_.jpg","\/51Hsv39e7IL._SL500_.jpg","\/41PTe+TqLEL._SL500_.jpg","\/51TUxdoXjrL._SL500_.jpg","\/51AkZEJWGhL._SL500_.jpg","\/51paP7D5R5L._SL500_.jpg","\/41lJtbpaQvL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297127474","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4297127474","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"OaDLa","s":"s"});</script></p>
<div id="msmaflink-OaDLa">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">この記事で分かること</span></h2>
<ul>
<li>デリミタ間テキスト選択コピーの機能と使い方</li>
<li>対応するデリミタの種類（18種類）</li>
<li>コピーせず選択のみを行う <code>Ctrl+Alt+S</code> の活用法</li>
<li>選択方向による動作の違い（右方向/左方向）</li>
<li>TypeScript実装の詳細コード</li>
<li>実務での活用例とパフォーマンス</li>
</ul>
<h2><span id="toc3">実装した機能の概要</span></h2>
<h3><span id="toc4">できること</span></h3>
<p><strong>2つのショートカットキーで使い分けられます：</strong></p>
<ul>
<li><code>Ctrl+Alt+D</code> : デリミタ間を選択してクリップボードにコピー</li>
<li><code>Ctrl+Alt+S</code> : デリミタ間を選択のみ（クリップボードは変更しない）</li>
</ul>
<p><code>Ctrl+Alt+S</code> は「コピー元でCtrl+Alt+D → 置換先でCtrl+Alt+S → Ctrl+V」という<strong>コピー&貼り付け置換</strong>の用途を想定しています。</p>
<p><strong>Ctrl+Alt+D を押すだけで、カーソル位置の最も近いデリミタ間のテキストを自動選択・コピー</strong></p>
<pre><code class="language-plaintext">例：＜"「あいうえお」、【かきくけこ】、｛さしすせそ｝"＞
          ↑ここにカーソル
          
Ctrl+Alt+D を押す
          
→「あいうえお」だけが選択・コピーされる（引用符は除外）</code></pre>
<h3><span id="toc5">対応デリミタ（18種類）</span></h3>
<h4>クォーテーション・スラッシュ系</h4>
<ul>
<li><code>&quot;～&quot;</code> (ダブルクォート)</li>
<li><code>&#39;～&#39;</code> (シングルクォート)</li>
<li><code>`～`</code> (バッククォート)</li>
<li><code>/～/</code> (スラッシュ・半角)</li>
<li><code>／～／</code> (スラッシュ・全角)</li>
<li><code>\～\</code> (バックスラッシュ・半角)</li>
<li><code>￥～￥</code> (円記号・全角)</li>
<li><code>|～|</code> (パイプ・半角)</li>
<li><code>｜～｜</code> (パイプ・全角)</li>
</ul>
<h4>括弧系（半角・全角）</h4>
<ul>
<li><code>(～)</code> / <code>（～）</code> (丸括弧)</li>
<li><code>[～]</code> (角括弧)</li>
<li><code>{～}</code> / <code>｛～｝</code> (波括弧)</li>
<li><code>&lt;～&gt;</code> / <code>＜～＞</code> (山括弧)</li>
<li><code>【～】</code> (墨付き括弧)</li>
<li><code>「～」</code> (鉤括弧)</li>
</ul>
<h3><span id="toc6">3つの動作モード</span></h3>
<h4>1. 通常モード（カーソル位置から左に検索）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
       ↑カーソル
       
→ カーソルの左にある最も近い開始デリミタ「"」を検出
→ 対応する終了デリミタ「"」を右に検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h4>2. 右方向モード（1文字選択 + カーソルが右側）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
   ↑選択    ↑カーソル（左→右に選択）
   
→ 選択文字「"」が開始デリミタか判定
→ 右に終了デリミタ「"」を検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h4>3. 左方向モード（1文字選択 + カーソルが左側）</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
   ↑カーソル ↑選択（右→左に選択）
   
→ 選択文字「"」が終了デリミタか判定
→ 左に開始デリミタ「"」を検索
→ 「あいうえお」、【かきくけこ】 が選択される</code></pre>
<h3><span id="toc7">フォールバック機能</span></h3>
<p>デリミタが見つからない場合は、<strong>行全体をコピー</strong>（<code>Ctrl+Alt+D</code>）または<strong>行全体を選択</strong>（<code>Ctrl+Alt+S</code>）します。</p>
<h2><span id="toc8">具体的な使用場面とメリット</span></h2>
<h3><span id="toc9">場面1：コード内の文字列リテラルを抽出</span></h3>
<pre><code class="language-javascript">const errorMessage = "接続に失敗しました。しばらく経ってから再度お試しください。";</code></pre>
<p>文字列の中にカーソルを置いて<code>Ctrl+Alt+D</code> → 文字列だけが即座にコピーされる。</p>
<p><strong>従来の方法：</strong></p>
<ol>
<li><code>&quot;</code>の直後をクリック</li>
<li>Shift+Endで行末まで選択</li>
<li>Shift+←で<code>&quot;</code>の手前まで調整</li>
<li>Ctrl+C</li>
</ol>
<p><strong>このマクロ：</strong></p>
<ol>
<li>文字列内にカーソルを置く</li>
<li><code>Ctrl+Alt+D</code></li>
</ol>
<p><strong>たった1操作で完了！</strong></p>
<h3><span id="toc10">場面2：ファイルパスを素早く抽出</span></h3>
<pre><code class="language-javascript">const configPath = '/etc/nginx/sites-available/default';
const dataPath = '/var/www/html/data/uploads/2026/02/';</code></pre>
<p>パス内にカーソルを置いて<code>Ctrl+Alt+D</code> → パス全体がコピーされる。</p>
<h3><span id="toc11">場面3：JSONのキーや値を抽出</span></h3>
<pre><code class="language-json">{
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "production_db"
  }
}</code></pre>
<p>各値にカーソルを置いて<code>Ctrl+Alt+D</code> → 値だけが抽出される。</p>
<h3><span id="toc12">場面4：正規表現パターンを抽出</span></h3>
<pre><code class="language-javascript">const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;</code></pre>
<p>パターン内にカーソルを置いて<code>Ctrl+Alt+D</code> → 正規表現本体だけがコピーされる（<code>/～/</code>を除外）。</p>
<h3><span id="toc13">場面5：複雑な入れ子構造から特定部分を抽出</span></h3>
<h4>異なる種類のデリミタの入れ子</h4>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】、｛さしすせそ｝"＞</code></pre>
<p>この複雑な構造でも：</p>
<ul>
<li><code>「</code>の後にカーソル → <code>あいうえお</code>が選択される</li>
<li><code>【</code>の後にカーソル → <code>かきくけこ</code>が選択される</li>
<li><code>＜</code>の後にカーソル → 最外側の<code>&quot;～&quot;</code>が選択される</li>
</ul>
<p><strong>最も近いデリミタを自動判別</strong>するため、入れ子構造でも正確に動作します。</p>
<h4>同じ種類のデリミタのネスト構造</h4>
<pre><code class="language-javascript">function outer(a, inner(b, c), d)</code></pre>
<p>この場合、カーソルが<code>outer</code>にあるとき：</p>
<ul>
<li>左で最も近い<code>(</code>（<code>outer</code>の後）を検出</li>
<li>ネストレベルを考慮して対応する<code>)</code>を検索</li>
<li>内側の<code>inner(b, c)</code>のネストをカウント</li>
<li><strong><code>a, inner(b, c), d</code>全体が正確に選択される</strong> ✅</li>
</ul>
<p>従来バージョンでは誤って<code>outer(a, inner(b, c</code>が選択されていましたが、ネスト対応により正確に動作するようになりました。</p>
<h3><span id="toc14">場面6：Markdown内のコード抜き出し</span></h3>
<pre><code class="language-markdown">インラインコードは`console.log('Hello')`のように書きます。</code></pre>
<p>バッククォート内にカーソルを置いて<code>Ctrl+Alt+D</code> → <code>console.log(&#39;Hello&#39;)</code>だけがコピーされる。</p>
<h3><span id="toc15">場面7：コピー&貼り付け置換（Ctrl+Alt+Sの活用）</span></h3>
<p><code>Ctrl+Alt+S</code>（選択のみ）との組み合わせで、<strong>貼り付けによる置換</strong>が手軽にできます。</p>
<pre><code class="language-javascript">const oldValue = "置換前の文字列";
const newValue = "置換後の文字列";</code></pre>
<p><strong>手順：</strong></p>
<ol>
<li><code>&quot;置換前の文字列&quot;</code> 内にカーソル → <code>Ctrl+Alt+D</code> でコピー</li>
<li><code>&quot;置換後の文字列&quot;</code> 内にカーソルを移動</li>
<li><code>Ctrl+Alt+S</code> で置換対象を選択</li>
<li><code>Ctrl+V</code> で貼り付け → 置換完了！</li>
</ol>
<p>クリップボードを変更せずに置換先だけを選択できるので、途中でクリップボードが上書きされる心配がありません。</p>
<h3><span id="toc16">メリットまとめ</span></h3>
<ul>
<li><strong>マウス操作不要</strong>: カーソル位置だけで判定</li>
<li><strong>高速</strong>: キーボード1回で完結</li>
<li><strong>正確</strong>: デリミタを自動検出</li>
<li><strong>柔軟</strong>: 選択方向で動作を変更可能、コピー/選択を使い分け可能</li>
<li><strong>安全</strong>: デリミタが見つからなくても行全体をコピー/選択</li>
</ul>
<h2><span id="toc17">改修履歴：ネスト構造への対応</span></h2>
<h3><span id="toc18">改修前の問題点</span></h3>
<p>初期バージョンでは、ネスト（入れ子）構造の括弧を正しく処理できない問題がありました。</p>
<p><strong>問題の例：</strong></p>
<pre><code class="language-javascript">function(b,c){...}</code></pre>
<p>この場合、カーソルが<code>function</code>にあるとき：</p>
<ol>
<li>左から最も近い開始デリミタ<code>(</code>を検出</li>
<li>その位置から右に最初に見つかった終了デリミタ<code>)</code>をマッチング</li>
<li>しかし、最初の<code>)</code>は<code>b,c)</code>の閉じ括弧なので、<strong><code>function(b,c</code>が誤って選択される</strong> ❌</li>
</ol>
<p>ネストレベルを考慮していないため、入れ子構造で誤動作していました。</p>
<h3><span id="toc19">改修内容：括弧のバランスを考慮したマッチング</span></h3>
<p>VSCodeの<code>Ctrl+Shift+\</code>（対応する括弧へジャンプ）と同じように、<strong>ネストレベルをカウントしながら対応する括弧を探す</strong>アルゴリズムを実装しました。</p>
<p><strong>アルゴリズム：</strong></p>
<ol>
<li>カーソル位置から左に開始デリミタを検索</li>
<li>その位置から右に向かって：
<ul>
<li>同じ開始デリミタが出現 → カウンタ +1（ネストが深くなる）</li>
<li>対応する終了デリミタが出現 → カウンタ -1（ネストから抜ける）</li>
<li><strong>カウンタが 0 になった位置が対応する終了デリミタ</strong> ✅</li>
</ul>
</li>
</ol>
<p><strong>追加した関数：</strong></p>
<ul>
<li><code>findMatchingEndDelimiter()</code> - 順方向のネスト対応マッチング</li>
<li><code>findMatchingStartDelimiter()</code> - 逆方向のネスト対応マッチング</li>
</ul>
<p>これにより、複雑な入れ子構造でも正確にデリミタのペアを検出できるようになりました。</p>
<h2><span id="toc20">TypeScript実装の詳細</span></h2>
<p>実際のコードを紹介します。<code>copyTextBetweenDelimiters.ts</code>ファイルに実装しました。</p>
<pre><code class="language-typescript">import * as vscode from 'vscode';

/**
 * デリミタペアの定義（開始文字と終了文字）
 */
const DELIMITER_PAIRS: Array&lt;{ start: string; end: string }&gt; = [
    { start: '"', end: '"' },
    { start: "'", end: "'" },
    { start: '`', end: '`' }, // バッククォート（テンプレートリテラル・Markdownインラインコード）
    { start: '/', end: '/' },
    { start: '／', end: '／' },
    { start: '\\', end: '\\' },
    { start: '￥', end: '￥' },
    { start: '|', end: '|' },
    { start: '｜', end: '｜' },
    { start: '「', end: '」' },
    { start: '[', end: ']' },
    { start: '【', end: '】' },
    { start: '{', end: '}' },
    { start: '｛', end: '｝' },
    { start: '(', end: ')' },
    { start: '（', end: '）' },
    { start: '&lt;', end: '&gt;' },
    { start: '＜', end: '＞' }
];

/**
 * デリミタで囲まれたテキストを選択してコピー（デリミタは除外）
 * - カーソル位置から左に開始デリミタを検索
 * - 対応する終了デリミタを右に検索
 * - 見つからない場合は行全体をコピー
 * - 1文字選択時はカーソル位置（選択方向）で動作を変更
 */
export async function copyTextBetweenDelimiters() {
    await processTextBetweenDelimiters(true); // 選択＋コピー
}

/**
 * デリミタで囲まれたテキストを選択するだけ（コピーしない）
 * - copyTextBetweenDelimiters と同じ検索ロジック
 * - 貼り付け先を選択してから Ctrl+V で置換する用途を想定
 */
export async function selectTextBetweenDelimiters() {
    await processTextBetweenDelimiters(false); // 選択のみ
}

/**
 * デリミタ間テキストの共通処理
 * @param copyToClipboard true=選択＋コピー、false=選択のみ
 */
async function processTextBetweenDelimiters(copyToClipboard: boolean) {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        vscode.window.showWarningMessage('アクティブなエディタがありません');
        return;
    }

    const document = editor.document;
    const selection = editor.selection;
    const cursorPos = selection.active;
    const line = document.lineAt(cursorPos.line);
    const lineText = line.text;

    // 1文字選択時の特殊処理（選択方向で動作を変更）
    if (!selection.isEmpty &amp;&amp; selection.end.character - selection.start.character === 1) {
        const selectedChar = lineText[selection.start.character];
        const charPos = selection.start.character;

        // カーソルが選択文字の右側（左→右選択）
        if (selection.active.character &gt; selection.anchor.character) {
            const result = handleRightDirection(lineText, charPos, selectedChar);
            if (result) {
                await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
                return;
            }
        }
        // カーソルが選択文字の左側（右→左選択）
        else if (selection.active.character &lt; selection.anchor.character) {
            const result = handleLeftDirection(lineText, charPos, selectedChar);
            if (result) {
                await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
                return;
            }
        }
    }

    // 通常処理：カーソル位置から左に開始デリミタを検索
    const result = findDelimitedText(lineText, cursorPos.character);

    if (result) {
        await applyResult(editor, cursorPos.line, result.start, result.end, copyToClipboard);
    } else {
        // 見つからない場合は行全体を対象
        if (copyToClipboard) {
            copyEntireLine(editor, cursorPos.line);
        } else {
            selectEntireLine(editor, cursorPos.line);
        }
    }
}

/**
 * 右方向処理：選択文字が開始デリミタかチェックし、右に終了デリミタを検索（ネスト考慮）
 */
function handleRightDirection(
    lineText: string,
    charPos: number,
    selectedChar: string
): { start: number; end: number } | null {
    for (const pair of DELIMITER_PAIRS) {
        if (selectedChar === pair.start) {
            // ネストレベルを考慮して対応する終了デリミタを検索
            const endPos = findMatchingEndDelimiter(lineText, charPos, pair.start, pair.end);
            if (endPos !== -1) {
                // デリミタを除外: 開始の次の文字から終了の前まで
                return { start: charPos + 1, end: endPos };
            }
        }
    }
    return null;
}

/**
 * 左方向処理：選択文字が終了デリミタかチェックし、左に開始デリミタを検索（ネスト考慮）
 */
function handleLeftDirection(
    lineText: string,
    charPos: number,
    selectedChar: string
): { start: number; end: number } | null {
    for (const pair of DELIMITER_PAIRS) {
        if (selectedChar === pair.end) {
            // ネストレベルを考慮して対応する開始デリミタを検索
            const startPos = findMatchingStartDelimiter(lineText, charPos, pair.start, pair.end);
            if (startPos !== -1) {
                // デリミタを除外: 開始の次の文字から終了の前まで
                return { start: startPos + 1, end: charPos };
            }
        }
    }
    return null;
}

/**
 * カーソル位置からデリミタで囲まれたテキストを検索（デリミタは除外）
 * - 左に開始デリミタを検索
 * - ネストレベルを考慮して対応する終了デリミタを右に検索
 */
function findDelimitedText(
    lineText: string,
    cursorPos: number
): { start: number; end: number } | null {
    let bestMatch: { start: number; end: number; startPos: number } | null = null;

    // 各デリミタペアについて検索
    for (const pair of DELIMITER_PAIRS) {
        // カーソル位置の左側で最後に出現する開始デリミタを検索
        let startPos = -1;
        for (let i = cursorPos - 1; i &gt;= 0; i--) {
            if (lineText[i] === pair.start) {
                startPos = i;
                break;
            }
        }

        if (startPos === -1) {
            continue; // 開始デリミタが見つからない
        }

        // 対応する終了デリミタを検索（ネストレベルを考慮）
        const endPos = findMatchingEndDelimiter(lineText, startPos, pair.start, pair.end);

        if (endPos !== -1) {
            // カーソル位置が範囲内にあるかチェック
            if (startPos &lt; cursorPos &amp;&amp; cursorPos &lt;= endPos) {
                // より近い開始デリミタを優先
                if (!bestMatch || startPos &gt; bestMatch.startPos) {
                    // デリミタを除外: 開始の次の文字から終了の前まで
                    bestMatch = {
                        start: startPos + 1,
                        end: endPos,
                        startPos: startPos
                    };
                }
            }
        }
    }

    if (bestMatch) {
        return { start: bestMatch.start, end: bestMatch.end };
    }

    return null;
}

/**
 * ネストレベルを考慮して対応する終了デリミタを検索
 */
function findMatchingEndDelimiter(
    lineText: string,
    startPos: number,
    startDelimiter: string,
    endDelimiter: string
): number {
    // 開始と終了が同じ文字の場合（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.indexOf(endDelimiter, startPos + 1);
    }

    // 異なる文字の場合はネストレベルを考慮
    let nestLevel = 1; // 開始デリミタを見つけた状態から開始

    for (let i = startPos + 1; i &lt; lineText.length; i++) {
        const char = lineText[i];

        if (char === startDelimiter) {
            nestLevel++; // 同じ開始デリミタが出現したらネストレベル+1
        } else if (char === endDelimiter) {
            nestLevel--; // 終了デリミタが出現したらネストレベル-1

            if (nestLevel === 0) {
                return i; // ネストレベルが0になったら対応する終了デリミタを発見
            }
        }
    }

    return -1; // 対応する終了デリミタが見つからない
}

/**
 * ネストレベルを考慮して対応する開始デリミタを検索（逆方向）
 */
function findMatchingStartDelimiter(
    lineText: string,
    endPos: number,
    startDelimiter: string,
    endDelimiter: string
): number {
    // 開始と終了が同じ文字の場合（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.lastIndexOf(startDelimiter, endPos - 1);
    }

    // 異なる文字の場合はネストレベルを考慮（逆方向）
    let nestLevel = 1; // 終了デリミタを見つけた状態から開始

    for (let i = endPos - 1; i &gt;= 0; i--) {
        const char = lineText[i];

        if (char === endDelimiter) {
            nestLevel++; // 同じ終了デリミタが出現したらネストレベル+1
        } else if (char === startDelimiter) {
            nestLevel--; // 開始デリミタが出現したらネストレベル-1

            if (nestLevel === 0) {
                return i; // ネストレベルが0になったら対応する開始デリミタを発見
            }
        }
    }

    return -1; // 対応する開始デリミタが見つからない
}

/**
 * 指定範囲を選択し、copyToClipboard=true の場合はコピーも行う
 */
async function applyResult(
    editor: vscode.TextEditor,
    line: number,
    startChar: number,
    endChar: number,
    copyToClipboard: boolean
) {
    const startPos = new vscode.Position(line, startChar);
    const endPos = new vscode.Position(line, endChar);
    editor.selection = new vscode.Selection(startPos, endPos);
    if (copyToClipboard) {
        await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
    }
}

/**
 * 行全体をクリップボードにコピー
 */
async function copyEntireLine(editor: vscode.TextEditor, lineNumber: number) {
    const line = editor.document.lineAt(lineNumber);
    editor.selection = new vscode.Selection(line.range.start, line.range.end);
    await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
    vscode.window.showInformationMessage('デリミタが見つからないため、行全体をコピーしました');
}

/**
 * 行全体を選択するだけ（コピーしない）
 */
function selectEntireLine(editor: vscode.TextEditor, lineNumber: number) {
    const line = editor.document.lineAt(lineNumber);
    editor.selection = new vscode.Selection(line.range.start, line.range.end);
    vscode.window.showInformationMessage('デリミタが見つからないため、行全体を選択しました');
}</code></pre>
<h2><span id="toc21">コードのポイント解説</span></h2>
<h3><span id="toc22">1. デリミタペアの定義</span></h3>
<pre><code class="language-typescript">const DELIMITER_PAIRS: Array&lt;{ start: string; end: string }&gt; = [
    { start: '"', end: '"' },
    { start: "'", end: "'" },
    { start: '`', end: '`' }, // バッククォート（テンプレートリテラル・Markdownインラインコード）
    { start: '「', end: '」' },
    // ... 18種類
];</code></pre>
<p>開始文字と終了文字のペアを配列で管理。拡張が容易な設計です。</p>
<h3><span id="toc23">2. コピーと選択の共通化</span></h3>
<pre><code class="language-typescript">// コピーする場合（Ctrl+Alt+D）
export async function copyTextBetweenDelimiters() {
    await processTextBetweenDelimiters(true);
}

// 選択のみの場合（Ctrl+Alt+S）
export async function selectTextBetweenDelimiters() {
    await processTextBetweenDelimiters(false);
}

// 共通処理（copyToClipboard で動作を分岐）
async function processTextBetweenDelimiters(copyToClipboard: boolean) {
    // ...
    await applyResult(editor, line, start, end, copyToClipboard);
}</code></pre>
<p><code>copyToClipboard</code>フラグ1つで2つのコマンドを共通化。検索ロジックの重複をなくし、保守性を高めています。</p>
<h3><span id="toc24">3. 選択方向の判定</span></h3>
<pre><code class="language-typescript">// カーソルが選択文字の右側（左→右選択）
if (selection.active.character &gt; selection.anchor.character) {
    // 右方向処理
}
// カーソルが選択文字の左側（右→左選択）
else if (selection.active.character &lt; selection.anchor.character) {
    // 左方向処理
}</code></pre>
<p>VSCodeの<code>selection.active</code>（カーソル位置）と<code>selection.anchor</code>（選択開始位置）を比較して選択方向を判定。</p>
<h3><span id="toc25">4. 最も近いデリミタの優先</span></h3>
<pre><code class="language-typescript">// より近い開始デリミタを優先
if (!bestMatch || startPos &gt; bestMatch.startPos) {
    bestMatch = {
        start: startPos + 1,
        end: endPos,
        startPos: startPos
    };
}</code></pre>
<p>複数のデリミタペアが見つかった場合、カーソルに最も近い開始デリミタを優先します。</p>
<h3><span id="toc26">5. デリミタの除外</span></h3>
<pre><code class="language-typescript">// デリミタを除外: 開始の次の文字から終了の前まで
return { start: charPos + 1, end: endPos };</code></pre>
<p>開始デリミタの<strong>次の文字</strong>から終了デリミタの<strong>前まで</strong>を選択範囲とすることで、デリミタ自体を除外します。</p>
<h3><span id="toc27">6. パフォーマンス最適化</span></h3>
<pre><code class="language-typescript">// 行内のみの線形検索
for (let i = cursorPos - 1; i &gt;= 0; i--) {
    if (lineText[i] === pair.start) {
        startPos = i;
        break;
    }
}</code></pre>
<p><strong>行内のみ</strong>を検索対象とすることで、長大なファイルでもパフォーマンスに影響しません。</p>
<h3><span id="toc28">7. ネストレベル考慮のアルゴリズム</span></h3>
<pre><code class="language-typescript">function findMatchingEndDelimiter(lineText: string, startPos: number, startDelimiter: string, endDelimiter: string): number {
    // 開始と終了が同じ文字（" や ' など）は従来の方式
    if (startDelimiter === endDelimiter) {
        return lineText.indexOf(endDelimiter, startPos + 1);
    }

    // 異なる文字の場合はネストレベルを考慮
    let nestLevel = 1; // 開始デリミタを見つけた状態から開始

    for (let i = startPos + 1; i &lt; lineText.length; i++) {
        const char = lineText[i];

        if (char === startDelimiter) {
            nestLevel++; // 同じ開始デリミタが出現 → ネスト +1
        } else if (char === endDelimiter) {
            nestLevel--; // 終了デリミタが出現 → ネスト -1

            if (nestLevel === 0) {
                return i; // ネストレベルが0 → 対応する括弧を発見
            }
        }
    }

    return -1; // 対応する終了デリミタが見つからない
}</code></pre>
<p><strong>ポイント：</strong></p>
<ul>
<li><code>nestLevel = 1</code> から開始（開始デリミタを見つけた状態）</li>
<li>同じ開始デリミタが出現するたびに <code>nestLevel++</code>（ネストが深くなる）</li>
<li>終了デリミタが出現するたびに <code>nestLevel--</code>（ネストから抜ける）</li>
<li><code>nestLevel === 0</code> になった位置が<strong>対応する終了デリミタ</strong></li>
</ul>
<p><strong>具体例：</strong></p>
<pre><code class="language-javascript">function(a, (b, c), d)
        ↑開始</code></pre>
<ol>
<li><code>function(</code> → <code>nestLevel = 1</code></li>
<li><code>(b</code> → <code>nestLevel = 2</code>（ネストが深くなる）</li>
<li><code>c)</code> → <code>nestLevel = 1</code>（ネストから抜ける）</li>
<li><code>d)</code> → <code>nestLevel = 0</code> ✅ <strong>ここが対応する閉じ括弧</strong></li>
</ol>
<p>これにより、複雑な入れ子構造でも正確にペアを検出できます。</p>
<h2><span id="toc29">package.jsonの設定</span></h2>
<p>拡張機能のコマンドとキーバインディングを登録します。</p>
<pre><code class="language-json">{
  "contributes": {
    "commands": [
      {
        "command": "myMacros.copyTextBetweenDelimiters",
        "title": "Copy Text Between Delimiters",
        "category": "My Macros"
      },
      {
        "command": "myMacros.selectTextBetweenDelimiters",
        "title": "Select Text Between Delimiters",
        "category": "My Macros"
      }
    ],
    "keybindings": [
      {
        "command": "myMacros.copyTextBetweenDelimiters",
        "key": "ctrl+alt+d",
        "when": "editorTextFocus"
      },
      {
        "command": "myMacros.selectTextBetweenDelimiters",
        "key": "ctrl+alt+s",
        "when": "editorTextFocus"
      }
    ]
  }
}</code></pre>
<h3><span id="toc30">extension.tsでの登録</span></h3>
<pre><code class="language-typescript">import { copyTextBetweenDelimiters, selectTextBetweenDelimiters } from './macros/copyTextBetweenDelimiters';

export function activate(context: vscode.ExtensionContext) {
    const commands = [
        vscode.commands.registerCommand(
            'myMacros.copyTextBetweenDelimiters',
            copyTextBetweenDelimiters
        ),
        vscode.commands.registerCommand(
            'myMacros.selectTextBetweenDelimiters',
            selectTextBetweenDelimiters
        ),
        // ... 他のコマンド
    ];

    commands.forEach(command =&gt; context.subscriptions.push(command));
}</code></pre>
<h2><span id="toc31">使い方</span></h2>
<h3><span id="toc32">基本的な使い方</span></h3>
<p><strong>ステップ1：カーソルを配置</strong></p>
<p>デリミタで囲まれたテキスト内にカーソルを配置します。</p>
<pre><code class="language-javascript">const message = "ここにカーソル";
                 ↑</code></pre>
<p><strong>ステップ2：マクロ実行</strong></p>
<ul>
<li><code>Ctrl+Alt+D</code> → 選択してクリップボードにコピー</li>
<li><code>Ctrl+Alt+S</code> → 選択のみ（クリップボードは変更しない）</li>
</ul>
<p><strong>ステップ3：完了</strong></p>
<p>デリミタ内のテキストが選択（または選択＋コピー）されます。</p>
<h3><span id="toc33">コピー&貼り付け置換の使い方</span></h3>
<p><code>Ctrl+Alt+D</code>と<code>Ctrl+Alt+S</code>を組み合わせると、クリップボードを保持したまま置換できます。</p>
<pre><code class="language-javascript">const src = "コピー元のテキスト";
const dst = "ここに上書きしたい";</code></pre>
<ol>
<li><code>&quot;コピー元のテキスト&quot;</code> 内にカーソル → <code>Ctrl+Alt+D</code> でコピー</li>
<li><code>&quot;ここに上書きしたい&quot;</code> 内にカーソルを移動</li>
<li><code>Ctrl+Alt+S</code> で選択（クリップボードは変わらない）</li>
<li><code>Ctrl+V</code> で貼り付け → 置換完了！</li>
</ol>
<h3><span id="toc34">方向別の使い方</span></h3>
<h4>右方向検索</h4>
<p>開始デリミタを1文字選択（左→右）してから<code>Ctrl+Alt+D</code></p>
<pre><code class="language-plaintext">＜"あいうえお"＞
   ↑選択 ↑カーソル</code></pre>
<p>→ 右に<code>&quot;</code>を検索して<code>あいうえお</code>を選択</p>
<h4>左方向検索</h4>
<p>終了デリミタを1文字選択（右→左）してから<code>Ctrl+Alt+D</code></p>
<pre><code class="language-plaintext">＜"あいうえお"＞
   ↑カーソル ↑選択</code></pre>
<p>→ 左に<code>&quot;</code>を検索して<code>あいうえお</code>を選択</p>
<h2><span id="toc35">トラブルシューティング</span></h2>
<h3><span id="toc36">Q: デリミタが認識されない</span></h3>
<p><strong>A:</strong> 対応デリミタを確認してください</p>
<p>現在対応しているのは18種類のデリミタです。バッククォート（<code>`</code>）も対応済みです。対応していないデリミタは<code>DELIMITER_PAIRS</code>配列に追加すれば簡単に拡張できます。</p>
<h3><span id="toc37">Q: 入れ子構造で意図しない範囲が選択される</span></h3>
<p><strong>A:</strong> ネストレベルを考慮して正確にマッチングします</p>
<p>改修後のバージョンでは、括弧のネストレベルを考慮して対応する括弧を検出します。</p>
<pre><code class="language-javascript">function(a, (b, c), d)
        ↑ここにカーソル</code></pre>
<p>この場合：</p>
<ul>
<li>カーソルの左で最も近い<code>(</code>（<code>function</code>の後）を検出</li>
<li>ネストレベルをカウントしながら対応する<code>)</code>を検索</li>
<li>内側の<code>(b, c)</code>のネストを考慮して、最外側の<code>)</code>を正確に検出</li>
</ul>
<p><strong>ただし、異なる種類のデリミタの場合は最も近いものが優先されます：</strong></p>
<pre><code class="language-plaintext">＜"「あいうえお」、【かきくけこ】"＞
     ↑ここにカーソル</code></pre>
<p>この場合、<code>「～」</code>が選択されます（最も近いため）。外側の<code>&quot;～&quot;</code>を選択したい場合は、<code>&quot;</code>と<code>「</code>の間にカーソルを配置してください。</p>
<h3><span id="toc38">Q: 行全体がコピーされてしまう</span></h3>
<p><strong>A:</strong> デリミタが見つからない場合のフォールバック動作です</p>
<ul>
<li>カーソル位置の左に開始デリミタがない</li>
<li>対応する終了デリミタが右に見つからない</li>
<li>カーソル位置がデリミタの外側</li>
</ul>
<p>これらの場合、安全のため行全体をコピーします。</p>
<h3><span id="toc39">Q: 動作が遅い</span></h3>
<p><strong>A:</strong> 行内のみの検索なのでパフォーマンス問題はありません</p>
<p>1行あたりの検索は線形時間（O(n)）で、通常の行（数百文字）なら瞬時に完了します。</p>
<h2><span id="toc40">パフォーマンスについて</span></h2>
<h3><span id="toc41">計算量</span></h3>
<ul>
<li>
<p><strong>時間計算量</strong>: O(n × m)</p>
<ul>
<li>n: 行の文字数</li>
<li>m: デリミタペアの数（18個）</li>
<li>通常の行（100文字）なら約1800回の比較</li>
</ul>
</li>
<li>
<p><strong>空間計算量</strong>: O(1)</p>
<ul>
<li>固定サイズのデータ構造のみ使用</li>
</ul>
</li>
</ul>
<h3><span id="toc42">ベンチマーク（参考値）</span></h3>
<ul>
<li>100文字の行: < 1ms</li>
<li>1000文字の行: < 5ms</li>
<li>10000文字の行: < 50ms</li>
</ul>
<p><strong>実用上、全く問題ないレベルです。</strong></p>
<h2><span id="toc43">拡張アイデア</span></h2>
<h3><span id="toc44">カスタムデリミタの設定</span></h3>
<p>VSCodeの設定ファイル（settings.json）から読み込むようにすれば、ユーザー独自のデリミタにも対応可能です。</p>
<pre><code class="language-json">{
  "myMacros.customDelimiters": [
    { "start": "/*", "end": "*/" },
    { "start": "&lt;!--", "end": "--&gt;" }
  ]
}</code></pre>
<h3><span id="toc45">複数行対応</span></h3>
<p>現在は行内のみですが、開始・終了デリミタが別の行にある場合も対応できます（ただし、パフォーマンスへの配慮が必要）。</p>
<h2><span id="toc46">まとめ：キーボード1回でデリミタ内を抜き出す快適さ</span></h2>
<p>VSCodeの標準機能では手が届かなかった「デリミタ間のテキスト選択」を、TypeScriptマクロで実現しました。</p>
<p><strong>このマクロの強み：</strong></p>
<ul>
<li>1キー操作で完結（<code>Ctrl+Alt+D</code> コピー / <code>Ctrl+Alt+S</code> 選択のみ）</li>
<li>18種類のデリミタに対応（バッククォートも含む）</li>
<li>選択方向で動作を切り替え可能</li>
<li>入れ子構造でも正確に動作（ネストレベル考慮）</li>
<li>パフォーマンス問題なし</li>
<li>デリミタが見つからない場合も安全（行全体をフォールバック）</li>
</ul>
<p><strong>こんな人におすすめ：</strong></p>
<ul>
<li>コードレビューでログやJSONを頻繁に扱う</li>
<li>文字列リテラルのコピペが多い</li>
<li>マウス操作を減らしたい</li>
<li>キーボードだけで完結させたい</li>
</ul>
<p>標準のVSCodeでは「Ctrl+Shift+→」を何度も押す必要があった操作が、<strong>たった1回のキー操作</strong>で完了します。</p>
<p>「需要はないかもしれない」と思っていましたが、<strong>一度使うと手放せない便利機能</strong>です。特に大量のテキストを扱う作業では、作業効率が劇的に向上します。</p>
<p>ぜひVSCodeでの快適なテキスト編集にお役立てください！</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発","b":"オライリージャパン","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51vjj+osAgL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4873119049","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4873119049","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"vFiVC","s":"s"});</script></p>
<div id="msmaflink-vFiVC">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc47">関連記事</span></h2>
<ul>
<li>VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-select-copy-macro/" title="VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに：テキスト編集における「範囲選択の不便さ」VSCodeで長いログファイルやドキュメントを編集していて、「この行から特定の文字列まで一気にコピーしたい」と思ったことはありませんか？通常のVSCodeでは、以下のような手順が必要です：開...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-replace-by-selection-macro/" title="VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-replace-by-selection-macro-featured-c0b1f0-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにテキスト編集で「複数の文字列を一度に置換したい」と思ったことはありませんか？例えば、こんなシーン：変数名を複数箇所で一括変更テーブル定義のデータ型を複数列で一括更新ドキュメント内の用語統一を複数ワードで一括実施VSCodeの標準機能...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeで正規表現マッチを一括抽出するTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-regex-extract-macro/" title="VSCodeで「正規表現マッチ抽出」を実現するTypeScriptマクロ【ログ解析が10倍速くなる】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-regex-extract-macro-featured-0ffd8c-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「正規表現マッチ抽出」を実現するTypeScriptマクロ【ログ解析が10倍速くなる】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにサーバーログやアプリケーションログを解析する時、こんな悩みありませんか？2024-02-08 10:00:00 INFO: Server started2024-02-08 10:01:00 ERROR: Connection fa...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<ul>
<li>VSCodeでパスを読み取り専用で開くTypeScriptマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-open-path-readonly-macro/" title="VSCodeでカーソル下のパスを開くマクロ【Office読み取り専用・関連付けアプリ・連続起動対応】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-open-path-readonly-macro-featured-be5c12-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeでカーソル下のパスを開くマクロ【Office読み取り専用・関連付けアプリ・連続起動対応】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでコードやドキュメントを書いている時、テキスト内にパスが書かれていてそのファイルを開きたいこと、ありませんか？作業メモ.txt---設計書: C:\work\documents\設計書_v1.0.docx手順書: C:\...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.06</div></div></div></div></a>
<hr>
<p><strong>タグ:</strong> #VSCode #TypeScript #マクロ #テキスト編集 #生産性向上 #エディタ</p><p>The post <a href="https://caymezon.com/vscode-delimiter-copy-macro/">VSCodeで「デリミタ間テキスト選択コピー」を実現するTypeScriptマクロ【括弧・引用符を1キーで抜き出し】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/vscode-delimiter-copy-macro/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】</title>
		<link>https://caymezon.com/vscode-replace-by-selection-macro/</link>
					<comments>https://caymezon.com/vscode-replace-by-selection-macro/#respond</comments>
		
		<dc:creator><![CDATA[caymezon]]></dc:creator>
		<pubDate>Sun, 08 Feb 2026 04:36:53 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[VSCode]]></category>
		<category><![CDATA[テキスト編集]]></category>
		<category><![CDATA[マクロ]]></category>
		<category><![CDATA[正規表現]]></category>
		<category><![CDATA[生産性向上]]></category>
		<guid isPermaLink="false">https://caymezon.com/?p=20104</guid>

					<description><![CDATA[<p>目次 はじめにこの記事で分かること機能の概要できること2つの置換モード終了位置の指定（改良版）実務での活用例例1：SQL文のテーブル名一括変更例2：Markdown用語統一例3：変数名リファクタリング（正規表現）例4：設 [&#8230;]</p>
<p>The post <a href="https://caymezon.com/vscode-replace-by-selection-macro/">VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">この記事で分かること</a></li><li><a href="#toc3" tabindex="0">機能の概要</a><ol><li><a href="#toc4" tabindex="0">できること</a></li><li><a href="#toc5" tabindex="0">2つの置換モード</a></li><li><a href="#toc6" tabindex="0">終了位置の指定（改良版）</a></li></ol></li><li><a href="#toc7" tabindex="0">実務での活用例</a><ol><li><a href="#toc8" tabindex="0">例1：SQL文のテーブル名一括変更</a></li><li><a href="#toc9" tabindex="0">例2：Markdown用語統一</a></li><li><a href="#toc10" tabindex="0">例3：変数名リファクタリング（正規表現）</a></li><li><a href="#toc11" tabindex="0">例4：設定ファイルの値一括変更</a></li><li><a href="#toc12" tabindex="0">例5：HTMLタグの一括変更</a></li></ol></li><li><a href="#toc13" tabindex="0">サクラエディタからの移植経緯</a><ol><li><a href="#toc14" tabindex="0">サクラエディタ時代の実績</a></li><li><a href="#toc15" tabindex="0">VSCode移植の決断</a></li></ol></li><li><a href="#toc16" tabindex="0">TypeScript実装の詳細</a><ol><li><a href="#toc17" tabindex="0">終了位置選択の実装（重要な改良点）</a></li><li><a href="#toc18" tabindex="0">その他の主要コード</a></li><li><a href="#toc19" tabindex="0">コードのポイント</a></li></ol></li><li><a href="#toc20" tabindex="0">package.jsonの設定</a></li><li><a href="#toc21" tabindex="0">使い方</a><ol><li><a href="#toc22" tabindex="0">基本的な使い方</a></li><li><a href="#toc23" tabindex="0">応用テクニック</a></li></ol></li><li><a href="#toc24" tabindex="0">トラブルシューティング</a><ol><li><a href="#toc25" tabindex="0">Q: 「置換指示行を選択してください」と表示される</a></li><li><a href="#toc26" tabindex="0">Q: 「タブ区切りの置換指定行がありません」と表示される</a></li><li><a href="#toc27" tabindex="0">Q: 正規表現が動かない</a></li><li><a href="#toc28" tabindex="0">Q: 一部の置換がスキップされる</a></li><li><a href="#toc29" tabindex="0">Q: 「Overlapping ranges are not allowed!」エラーが出る</a></li></ol></li><li><a href="#toc30" tabindex="0">他のマクロとの組み合わせ</a><ol><li><a href="#toc31" tabindex="0">選択範囲コピーマクロとの連携</a></li><li><a href="#toc32" tabindex="0">Git連携</a></li></ol></li><li><a href="#toc33" tabindex="0">まとめ</a></li><li><a href="#toc34" tabindex="0">関連記事</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>テキスト編集で「複数の文字列を一度に置換したい」と思ったことはありませんか？</p>
<p>例えば、こんなシーン：</p>
<ul>
<li>変数名を複数箇所で一括変更</li>
<li>テーブル定義のデータ型を複数列で一括更新</li>
<li>ドキュメント内の用語統一を複数ワードで一括実施</li>
</ul>
<p>VSCodeの標準機能では「1つずつ置換」が限界。複数の置換ペアを一度に処理するには、拡張機能や外部ツールが必要でした。</p>
<p>そこで、<strong>サクラエディタで10年以上愛用してきた「選択行一括置換マクロ」をTypeScriptで再実装</strong>しました。</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで (Software Design plus)","b":"技術評論社","t":"","d":"https:\/\/m.media-amazon.com","c_p":"\/images\/I","p":["\/510GhCOD1FL._SL500_.jpg","\/41og2y1EEHL._SL500_.jpg","\/51XHb97PpFL._SL500_.jpg","\/51uDIY22bQL._SL500_.jpg","\/51PaoVK3MWL._SL500_.jpg","\/51eG7JBoavL._SL500_.jpg","\/51CDCo8FmJL._SL500_.jpg","\/41JLTXb+tsL._SL500_.jpg","\/51Hsv39e7IL._SL500_.jpg","\/41PTe+TqLEL._SL500_.jpg","\/51TUxdoXjrL._SL500_.jpg","\/51AkZEJWGhL._SL500_.jpg","\/51paP7D5R5L._SL500_.jpg","\/41lJtbpaQvL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4297127474","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4297127474","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80%20%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7%20(Software%20Design%20plus)","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"OaDLa","s":"s"});</script></p>
<div id="msmaflink-OaDLa">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc2">この記事で分かること</span></h2>
<ul>
<li>選択行一括置換マクロの機能と使い方</li>
<li>リテラル置換と正規表現置換の使い分け</li>
<li>TypeScript実装の詳細コード</li>
<li>実務での活用例</li>
<li>トラブルシューティング</li>
</ul>
<h2><span id="toc3">機能の概要</span></h2>
<h3><span id="toc4">できること</span></h3>
<p><strong>選択した行から置換ペアを読み取り、指定範囲を一括置換</strong></p>
<pre><code class="language-plaintext">置換指示行（選択する）:
19: aaa	111
20: bbb	222
21: ccc	333

↓ Ctrl+Alt+T で実行

置換対象範囲（21行目以降）:
22: テスト aaa です
23: bbb もあります
24: ccc も置換されます

↓ 結果

22: テスト 111 です
23: 222 もあります
24: 333 も置換されます</code></pre>
<h3><span id="toc5">2つの置換モード</span></h3>
<ol>
<li>
<p><strong>リテラル置換</strong>（Ctrl+Alt+T）</p>
<ul>
<li>文字列をそのまま検索・置換</li>
<li>特殊文字もそのまま扱う</li>
<li>安全で確実</li>
</ul>
</li>
<li>
<p><strong>正規表現置換</strong>（Ctrl+Shift+Alt+T）</p>
<ul>
<li>パターンマッチングが可能</li>
<li>後方参照・グループ化対応</li>
<li>高度な置換に対応</li>
</ul>
</li>
</ol>
<h3><span id="toc6">終了位置の指定（改良版）</span></h3>
<p>実行時にQuickPickダイアログが開き、以下の方法で終了位置を指定できます：</p>
<h4>プリセット選択（↑↓キーで選択）</h4>
<ul>
<li><strong>空行</strong>: 次の空行の1つ前まで</li>
<li><strong>EOF</strong>: ファイル末尾まで（デフォルト）</li>
<li><strong>▲</strong>: 「▲」を含む行の1つ前まで</li>
<li><strong>▲▲▲</strong>: 「▲▲▲」を含む行の1つ前まで</li>
<li><strong>```</strong>: コードブロック終端の1つ前まで</li>
<li><strong>---</strong>: 区切り線の1つ前まで</li>
</ul>
<h4>直接入力も可能</h4>
<p>プリセットを選ばずに、そのまま文字列を入力してEnterでもOK。例えば「TODO」と入力すれば、TODOを含む行の1つ前まで置換されます。</p>
<h2><span id="toc7">実務での活用例</span></h2>
<h3><span id="toc8">例1：SQL文のテーブル名一括変更</span></h3>
<p><strong>置換指示行：</strong></p>
<pre><code class="language-plaintext">old_users	new_users
old_posts	new_posts
old_comments	new_comments</code></pre>
<p><strong>置換対象：</strong></p>
<pre><code class="language-sql">SELECT * FROM old_users WHERE ...;
UPDATE old_posts SET ...;
DELETE FROM old_comments WHERE ...;</code></pre>
<p><strong>結果：</strong></p>
<pre><code class="language-sql">SELECT * FROM new_users WHERE ...;
UPDATE new_posts SET ...;
DELETE FROM new_comments WHERE ...;</code></pre>
<h3><span id="toc9">例2：Markdown用語統一</span></h3>
<p><strong>置換指示行：</strong></p>
<pre><code class="language-plaintext">サーバー	サーバ
データベース	DB
ブラウザー	ブラウザ</code></pre>
<p>1行に1つずつ置換ペアを定義するだけで、ドキュメント全体を一括修正！</p>
<h3><span id="toc10">例3：変数名リファクタリング（正規表現）</span></h3>
<p><strong>置換指示行：</strong></p>
<pre><code class="language-plaintext">user_(\w+)	customer_$1
old_(\w+)_id	new_$1_id</code></pre>
<p><strong>置換対象：</strong></p>
<pre><code class="language-javascript">const user_name = "John";
const user_age = 30;
const old_order_id = 123;</code></pre>
<p><strong>結果：</strong></p>
<pre><code class="language-javascript">const customer_name = "John";
const customer_age = 30;
const new_order_id = 123;</code></pre>
<p>正規表現の後方参照も完全対応！</p>
<h3><span id="toc11">例4：設定ファイルの値一括変更</span></h3>
<p><strong>置換指示行：</strong></p>
<pre><code class="language-plaintext">localhost	production.example.com
:8080	:443
http://	https://</code></pre>
<p>開発環境から本番環境への設定変更が一瞬で完了。</p>
<h3><span id="toc12">例5：HTMLタグの一括変更</span></h3>
<p><strong>置換指示行：</strong></p>
<pre><code class="language-plaintext">&lt;div	&lt;section
&lt;/div&gt;	&lt;/section&gt;
&lt;span	&lt;strong
&lt;/span&gt;	&lt;/strong&gt;</code></pre>
<p>セマンティックHTMLへのリファクタリングが簡単に。</p>
<h2><span id="toc13">サクラエディタからの移植経緯</span></h2>
<h3><span id="toc14">サクラエディタ時代の実績</span></h3>
<p>この機能、実は10年以上前からサクラエディタで愛用していた自作マクロです。</p>
<p>元記事：<a href="https://caymezon.com/sakura-all-replace-macro/">【サクラエディタ】１ファイル内一括置換マクロ【画像サンプルあり】</a></p>
<p><strong>当時の課題：</strong></p>
<ul>
<li>VSCodeとサクラエディタを行き来するのが面倒</li>
<li>Git統合やリモート開発ではVSCodeが必須</li>
<li>でも一括置換はサクラエディタでないとできない</li>
</ul>
<h3><span id="toc15">VSCode移植の決断</span></h3>
<p>VSCodeで開発する機会が増えたため、「どうせなら全部VSCodeで完結させたい」と思い、TypeScriptで再実装を決意。</p>
<p><strong>移植のメリット：</strong></p>
<ul>
<li>エディタ統一による効率化</li>
<li>TypeScriptの型安全性</li>
<li>Git管理による履歴保持</li>
<li>正規表現モードの追加</li>
<li>QuickPickによる柔軟な入力</li>
</ul>
<h2><span id="toc16">TypeScript実装の詳細</span></h2>
<h3><span id="toc17">終了位置選択の実装（重要な改良点）</span></h3>
<p>従来の<code>showInputBox</code>から<code>createQuickPick</code>に変更したことで、プリセット選択と直接入力の両方に対応しました。</p>
<pre><code class="language-typescript">/**
 * プリセット検索パターン
 */
const PRESET_PATTERNS = [
    { label: '空行', value: 'EMPTY_LINE', description: '次の空行まで' },
    { label: 'EOF', value: 'EOF', description: 'ファイル末尾まで' },
    { label: '▲', value: '▲', description: '▲が含まれる行の前まで' },
    { label: '▲▲▲', value: '▲▲▲', description: '▲▲▲が含まれる行の前まで' },
    { label: '```', value: '```', description: 'コードブロック終端の前まで' },
    { label: '---', value: '---', description: '区切り線の前まで' }
];

/**
 * 終了位置の選択ダイアログ（直接入力も可能）
 */
async function promptForEndLine(
    document: vscode.TextDocument,
    startLine: number
): Promise<number | null> {
    const quickPick = vscode.window.createQuickPick();
    quickPick.items = PRESET_PATTERNS;
    quickPick.placeholder = '終了位置を選択または直接入力してください';
    quickPick.ignoreFocusOut = true;
    
    return new Promise((resolve) => {
        quickPick.onDidAccept(async () => {
            const selected = quickPick.selectedItems[0];
            const inputValue = quickPick.value.trim();
            
            let pattern: string | null = null;
            
            // 選択肢を選んだ場合
            if (selected) {
                const presetPattern = PRESET_PATTERNS.find(p => p.label === selected.label);
                pattern = presetPattern?.value || null;
            }
            // 直接入力した場合
            else if (inputValue) {
                pattern = inputValue;
            }
            
            quickPick.hide();
            
            if (!pattern) {
                resolve(null);
                return;
            }
            
            // 終了行を検索
            const endLine = await findEndLine(document, startLine, pattern);
            resolve(endLine);
        });
        
        quickPick.onDidHide(() => {
            resolve(null);
            quickPick.dispose();
        });
        
        quickPick.show();
    });
}

/**
 * 終了行を検索
 */
async function findEndLine(
    document: vscode.TextDocument,
    startLine: number,
    pattern: string
): Promise<number | null> {
    const lastLine = document.lineCount - 1;
    
    // EOFの場合
    if (pattern === 'EOF') {
        return lastLine + 1; // 最終行の次（全体を対象）
    }
    
    // 空行の場合
    if (pattern === 'EMPTY_LINE') {
        for (let i = startLine + 1; i <= lastLine; i++) {
            const line = document.lineAt(i);
            if (line.isEmptyOrWhitespace) {
                return i; // 空行の番号を返す（1行前まで置換）
            }
        }
        
        // 空行が見つからない場合は最終行
        vscode.window.showInformationMessage('空行が見つからないため、ファイル末尾まで置換します');
        return lastLine + 1;
    }
    
    // 文字列検索（該当行の1行前まで）
    for (let i = startLine + 1; i <= lastLine; i++) {
        const lineText = document.lineAt(i).text;
        if (lineText.includes(pattern)) {
            return i; // 該当行の番号を返す（1行前まで置換）
        }
    }
    
    // 見つからない場合はEOF
    vscode.window.showInformationMessage(
        `「${pattern}」が見つからないため、ファイル末尾まで置換します`
    );
    return lastLine + 1;
}</code></pre>
<h3><span id="toc18">その他の主要コード</span></h3>
<p>置換ペアの抽出や実際の置換処理は従来通りです：</p>
<pre><code class="language-typescript">/**
 * 選択範囲から「置換前\t置換後」ペアを抽出
 */
function collectReplacePairs(
    document: vscode.TextDocument,
    startLine: number,
    endLine: number
): Array<[string, string]> {
    const pairs: Array<[string, string]> = [];

    for (let i = startLine; i <= endLine; i++) {
        const lineText = document.lineAt(i).text;
        const tabIndex = lineText.indexOf('\t');

        if (tabIndex < 0) {
            continue; // タブがない行は無視
        }

        const before = lineText.substring(0, tabIndex);
        const after = lineText.substring(tabIndex + 1);

        if (!before) {
            continue; // 置換前が空の行は無視
        }

        pairs.push([before, after]);
    }

    return pairs;
}

/**
 * 実際に置換を適用（修正版：行ごとに全ペアを適用）
 */
async function applyReplacements(
    editor: vscode.TextEditor,
    pairs: Array<[string, string]>,
    startLine: number,
    endLine: number,
    mode: ReplaceMode
) {
    const document = editor.document;
    const lastLine = document.lineCount - 1;
    const actualEndLine = Math.min(endLine - 1, lastLine);

    await editor.edit(editBuilder => {
        // 行ごとにループ（オーバーラップを防ぐため）
        for (let lineNum = startLine; lineNum <= actualEndLine; lineNum++) {
            const line = document.lineAt(lineNum);
            let lineText = line.text;
            const originalText = lineText;

            // 全ペアを順番に適用
            for (const [before, after] of pairs) {
                if (!before || before === after) {
                    continue; // 空文字列や同じ文字列はスキップ
                }

                if (mode === ReplaceMode.Literal) {
                    // リテラル置換
                    lineText = lineText.split(before).join(after);
                } else {
                    // 正規表現置換
                    try {
                        const regex = new RegExp(before, 'g');
                        lineText = lineText.replace(regex, after);
                    } catch (e) {
                        // 正規表現エラーの場合はスキップ
                        console.error(`正規表現エラー: ${before}`, e);
                    }
                }
            }

            // 変更があった場合のみ置換（1行につき1回のreplaceでオーバーラップを回避）
            if (lineText !== originalText) {
                const range = new vscode.Range(
                    new vscode.Position(lineNum, 0),
                    new vscode.Position(lineNum, originalText.length)
                );
                editBuilder.replace(range, lineText);
            }
        }
    });
}</code></pre>
<h3><span id="toc19">コードのポイント</span></h3>
<p><strong>1. QuickPickによる柔軟な入力</strong></p>
<pre><code class="language-typescript">const quickPick = vscode.window.createQuickPick();
quickPick.items = PRESET_PATTERNS;
// プリセット選択 or 直接入力が可能</code></pre>
<p><strong>2. プリセットと直接入力の両対応</strong></p>
<pre><code class="language-typescript">if (selected) {
    // プリセット選択
    pattern = presetPattern?.value || null;
} else if (inputValue) {
    // 直接入力
    pattern = inputValue;
}</code></pre>
<p><strong>3. タブ区切りのパース</strong></p>
<pre><code class="language-typescript">const tabIndex = lineText.indexOf('\t');
const before = lineText.substring(0, tabIndex);
const after = lineText.substring(tabIndex + 1);</code></pre>
<p>「置換前[Tab]置換後」形式を確実に解析。</p>
<p><strong>4. オーバーラップエラーの回避（重要）</strong></p>
<pre><code class="language-typescript">// 行ごとにループ（オーバーラップを防ぐため）
for (let lineNum = startLine; lineNum <= actualEndLine; lineNum++) {
    let lineText = line.text;
    
    // 全ペアを順番に適用
    for (const [before, after] of pairs) {
        lineText = lineText.split(before).join(after);
    }
    
    // 変更があった場合のみ1回だけreplace
    if (lineText !== originalText) {
        editBuilder.replace(range, lineText);
    }
}</code></pre>
<p>同じ行に複数の置換対象がある場合でも、<strong>行ごとに全ペアを適用してから1回だけreplace</strong>することでオーバーラップエラーを回避。</p>
<h2><span id="toc20">package.jsonの設定</span></h2>
<pre><code class="language-json">{
  "contributes": {
    "commands": [
      {
        "command": "myMacros.replaceBySelectionLiteral",
        "title": "Replace by Selection (Literal)",
        "category": "My Macros"
      },
      {
        "command": "myMacros.replaceBySelectionRegex",
        "title": "Replace by Selection (Regex)",
        "category": "My Macros"
      }
    ],
    "keybindings": [
      {
        "command": "myMacros.replaceBySelectionLiteral",
        "key": "ctrl+alt+t",
        "when": "editorTextFocus"
      },
      {
        "command": "myMacros.replaceBySelectionRegex",
        "key": "ctrl+shift+alt+t",
        "when": "editorTextFocus"
      }
    ]
  }
}</code></pre>
<h2><span id="toc21">使い方</span></h2>
<h3><span id="toc22">基本的な使い方</span></h3>
<p><strong>ステップ1：置換ペアを記述</strong></p>
<pre><code class="language-plaintext">old_name	new_name
old_value	new_value
old_key	new_key</code></pre>
<p><strong>ステップ2：選択する</strong></p>
<p>置換ペアの行を選択（Shift+↓で複数行選択）</p>
<p><strong>ステップ3：実行</strong></p>
<ul>
<li>リテラル置換：<code>Ctrl+Alt+T</code></li>
<li>正規表現置換：<code>Ctrl+Shift+Alt+T</code></li>
</ul>
<p><strong>ステップ4：終了位置を指定</strong></p>
<p>QuickPickダイアログが開きます：</p>
<ul>
<li>↑↓でプリセットを選択してEnter</li>
<li>または直接文字列を入力してEnter</li>
</ul>
<p><strong>ステップ5：確認</strong></p>
<p>置換内容を確認して「はい」をクリック</p>
<h3><span id="toc23">応用テクニック</span></h3>
<p><strong>範囲を限定する：</strong></p>
<pre><code class="language-plaintext">置換指示行（選択）
↓
置換対象範囲
↓
--- （ここで終了）
↓
置換しない範囲</code></pre>
<p>終了位置に「---」を選択またはダイアログで入力すれば、区切り線までのみ置換。</p>
<p><strong>正規表現の後方参照：</strong></p>
<pre><code class="language-plaintext">(\w+)_old	$1_new
old_(\d+)	new_$1</code></pre>
<p>キャプチャグループを活用した高度な置換が可能。</p>
<h2><span id="toc24">トラブルシューティング</span></h2>
<h3><span id="toc25">Q: 「置換指示行を選択してください」と表示される</span></h3>
<p><strong>A:</strong> 置換ペアの行を選択していません</p>
<ul>
<li>置換ペアを記述した行を選択してから実行してください</li>
<li>選択範囲が空の場合はこのエラーが出ます</li>
</ul>
<h3><span id="toc26">Q: 「タブ区切りの置換指定行がありません」と表示される</span></h3>
<p><strong>A:</strong> タブ文字が入っていません</p>
<ul>
<li>「置換前[Tab]置換後」の形式で記述してください</li>
<li>スペースではなく、タブ文字（\t）を使ってください</li>
</ul>
<h3><span id="toc27">Q: 正規表現が動かない</span></h3>
<p><strong>A:</strong> 正規表現モードで実行していますか？</p>
<ul>
<li>リテラル：<code>Ctrl+Alt+T</code></li>
<li>正規表現：<code>Ctrl+Shift+Alt+T</code></li>
<li>モードを確認してください</li>
</ul>
<h3><span id="toc28">Q: 一部の置換がスキップされる</span></h3>
<p><strong>A:</strong> 正規表現エラーの可能性</p>
<ul>
<li>コンソールログ（Ctrl+Shift+U → Extension Host）を確認</li>
<li>正規表現の構文を見直してください</li>
</ul>
<h3><span id="toc29">Q: 「Overlapping ranges are not allowed!」エラーが出る</span></h3>
<p><strong>A:</strong> 修正済みです</p>
<ul>
<li>最新版では、同じ行に複数の置換対象がある場合でも正常に動作します</li>
<li><code>git pull</code>して最新版を取得してください</li>
</ul>
<h2><span id="toc30">他のマクロとの組み合わせ</span></h2>
<h3><span id="toc31">選択範囲コピーマクロとの連携</span></h3>
<ol>
<li>置換ペアをテンプレート化</li>
<li>空行までコピーマクロで複製</li>
<li>値だけ書き換えて実行</li>
</ol>
<h3><span id="toc32">Git連携</span></h3>
<pre><code class="language-bash"># 置換前
git diff

# 置換実行
Ctrl+Alt+T

# 結果確認
git diff

# 問題なければコミット
git commit -am "Refactor: update variable names"</code></pre>
<h2><span id="toc33">まとめ</span></h2>
<p>VSCodeで複数の文字列を一括置換する機能、実装してみました。</p>
<p><strong>このマクロの強み：</strong></p>
<ul>
<li>シンプルな操作（選択して実行）</li>
<li>タブ区切りの直感的な書式</li>
<li>リテラルと正規表現の両対応</li>
<li><strong>QuickPickによる柔軟な終了位置指定</strong></li>
<li><strong>プリセット選択と直接入力の両対応</strong></li>
<li>確認ダイアログで安全</li>
<li>オーバーラップエラーを回避</li>
</ul>
<p><strong>こんな人におすすめ：</strong></p>
<ul>
<li>テキスト編集の効率化したい</li>
<li>リファクタリングが多い</li>
<li>ドキュメント整備をよくする</li>
<li>サクラエディタから移行したい</li>
</ul>
<p>サクラエディタで10年以上愛用してきた機能が、TypeScriptで現代的に蘇りました。</p>
<p>ぜひVSCodeでの快適なテキスト編集にお役立てください！</p>
<p><!-- START MoshimoAffiliateEasyLink --><script type="text/javascript">(function(b,c,f,g,a,d,e){b.MoshimoAffiliateObject=a;b[a]=b[a]||function(){arguments.currentScript=c.currentScript||c.scripts[c.scripts.length-2];(b[a].q=b[a].q||[]).push(arguments)};c.getElementById(a)||(d=c.createElement(f),d.src=g,d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");msmaflink({"n":"プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発","b":"オライリージャパン","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51vjj+osAgL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/4873119049","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/4873119049","a_id":1384942,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":2,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA\/","a_id":1384917,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2},{"id":3,"u_tx":"Yahoo!ショッピングで見る","u_bc":"#66a7ff","u_url":"https:\/\/shopping.yahoo.co.jp\/search?first=1\u0026p=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript%20%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA","a_id":1466950,"p_id":1225,"pl_id":27061,"pc_id":1925,"s_n":"yahoo","u_so":3}],"eid":"vFiVC","s":"s"});</script></p>
<div id="msmaflink-vFiVC">リンク</div>
<p><!-- MoshimoAffiliateEasyLink END --></p>
<h2><span id="toc34">関連記事</span></h2>
<ul>
<li>サクラエディタからの移行経緯</li>
</ul>

<a rel="noopener" href="https://caymezon.com/sakura-to-vscode-macro-migration/" title="サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/sakura-to-vscode-macro-migration-featured-404add-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">サクラエディタからVSCodeへマクロ移行！快適開発環境の構築記録</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに長年愛用してきたサクラエディタのマクロ機能。便利なJavaScript/VBSマクロを多数作成して日常業務で活用してきましたが、最近のAWS開発やブログ執筆でVSCodeを使う機会が増えてきました。「VSCodeでもサクラエディタの...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a>
<ul>
<li>TypeScriptマクロ開発環境の構築方法</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-typescript-macro-development-guide/" title="VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/01/vscode-typescript-macro-development-guide-featured-418842-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめにVSCodeでカスタムマクロを作成したいけど、どうやって開発環境を構築すればいいか分からない。そんな悩みを持つ方に向けて、TypeScriptでVSCode拡張機能を開発する環境の構築から、実際にマクロを作成して使えるようにするまで...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.01.25</div></div></div></div></a>
<ul>
<li>空行までの一括選択・コピーマクロ</li>
</ul>

<a rel="noopener" href="https://caymezon.com/vscode-select-copy-macro/" title="VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-160x90.jpg 160w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-120x68.jpg 120w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-320x180.jpg 320w, https://caymezon.com/wp-content/uploads/2026/02/vscode-select-copy-macro-featured-cf97f1-376x212.jpg 376w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">VSCodeで「任意行までの一括選択・コピー」を実現するTypeScriptマクロ開発【サクラエディタ移行の集大成】</div><div class="blogcard-snippet internal-blogcard-snippet">はじめに：テキスト編集における「範囲選択の不便さ」VSCodeで長いログファイルやドキュメントを編集していて、「この行から特定の文字列まで一気にコピーしたい」と思ったことはありませんか？通常のVSCodeでは、以下のような手順が必要です：開...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://caymezon.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">caymezon.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2026.02.08</div></div></div></div></a>
<hr>
<p><strong>タグ:</strong> #VSCode #TypeScript #マクロ #テキスト編集 #正規表現 #生産性向上 #サクラエディタ</p><p>The post <a href="https://caymezon.com/vscode-replace-by-selection-macro/">VSCodeで「選択行による一括置換」を実現するTypeScriptマクロ【テキスト編集が10倍速くなる】</a> first appeared on <a href="https://caymezon.com">CayTech Lab</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://caymezon.com/vscode-replace-by-selection-macro/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
