44832


条件式に正規表現を使う場合どうすればいいのでしょうか？

[code]

    if (randomNum === 3) {
        if (inputAnswer === "パン") {
            correctAnswerEasyQ();
            commentary1.innerHTML = '【パン】';
            commentary2.innerHTML = 'たくさん！';
    
            getPoint10();
    
            description1.innerHTML = '';
        } else {
            mistakeAnswerEasyQ();
            commentary1.innerHTML = '【パン】';
            commentary2.innerHTML = 'たくさん！';
        }
    }
    
[/code]

を

[code]

    if (randomNum === 3) {
    
        while(i < answerNum) {
            var answerTxt = changeAnswer();
    
            if (answerTxt === 'パン') {
                correctAnswerEasyQ();
                commentary1.innerHTML = '【パン】';
                commentary2.innerHTML = 'たくさん！';
    
                getPoint10();
    
                flag = true;
    
                break;
            } else {
                falseNum++;
    
            }
    
            if(falseNum === answerNum && flag === false) {
                mistakeAnswerEasyQ();
                commentary1.innerHTML = '【パン】';
                commentary2.innerHTML = 'たくさん！';
            }
    
            i++;
        }
    
    }
    
[/code]

に変換したい

上記のようにサブライムで置換をしたいのですが正規表現でどう表現すればいいかがわかりません。

そして文字列の部分だけが基本的に違う同じ変換を数百行わないといけないのですが手動でやるには大変すぎます。  
何とか一括置換するアイデアはないでしょうか？

＿＿＿＿＿＿＿＿＿＿＿＿＿＿  
せめて下記のように文字列が違い、かつ下記のようにきれいに並んでいないものを一括でコピペできないでしょうか？  
inputAnswer === "パン"  
inputAnswer === "ごはん"  
inputAnswer === "いも"

これを個数分すべてひとつづつやっていくのは大変です。  
きれいに並んでいれば出来るのですが。

これが出来れば一度すべて変換後の形を張り付けて、それぞれ違う値は次にいっぺんにはり付けられます。


CC BY-SA 4.0
2018-06-17T15:40:37.207
44830
2018-06-18T23:44:17.710
2018-06-18T02:55:37.597
24247
24247
question
正規表現 sublimetext
正規表現で複数行のソースコードを一括置換したい


masmさんのおっしゃる通り、数百個の重複コードを1つの関数にまとめた方が今後のメンテナンスや機能拡張もしやすくなると思います。

何らかの理由で重複コードをまとめられない時には、正規表現での一括置換は理論上可能です。  
`(?s)`フラグを使うことで、[複数行の置換](http://tkymtk.hatenablog.com/entry/sublime-regex-
match-multi-lines-2014-01)ができます。

ただし1回の置換ですべてをこなそうとすると、正規表現の文字列が長くなりすぎて間違いを直すことも困難になります。  
下記のように段階を踏んで複数回置換をする方が良いでしょう。

  1. `if (randomNum === 3)` の下に`var answerTxt = changeAnswer();`までの3行を追加する
  2. `description1.innerHTML = '';`を`flag = true;`～`break`に置換する
  3. `} else {`以下を置換する  
...

実際に処理をすると、ifの中のインデントを追加する方法や、部分的に手入力でコード修正や改行が入っていて正規表現にマッチしない箇所に悩まされる可能性があります。

私なら正規表現のみで無理やり対応せずに、テキストエディタの[マクロ](https://webkaru.net/dev/mac-sublime-
macro/)機能を使います。  
上記の複数回置換の段階を踏んで書き換えを行うマクロを作成し、修正前と修正後のコードを差分比較しながら個々の書き換えを行います。

マクロでも書き換えができないほどイレギュラーパターンが多ければ、pythonやjavascriptで使い捨ての置換コードを作成します。  
対応方法は複数ありますので、最適な方法をご検討ください。

* * *

> せめて下記のように文字列が違い、かつ下記のようにきれいに並んでいないものを一括でコピペできないでしょうか？  
>  inputAnswer === "パン"  
>  inputAnswer === "ごはん"  
>  inputAnswer === "いも"

※元質問のソースコードは'パン'とシングルクォーテーションになっていますが、追加質問の通りダブルクォーテーションで回答します。

  1. `Find -> Find in files` で複数ファイル検索画面を開く
  2. 正規表現検索を有効にして、`Find:`に`inputAnswer\s*===\s*"[^"]+"`を入力する
  3. 検索対象でファイルを選択する
  4. 一覧で出てきた検索結果をコピペして別のテキストファイルに保存する
  5. 上記のテキストファイルをSublime Textで開きなおし、正規表現で置換する  
Find: `^.+(inputAnswer)\s*===\s*("[^"]+").*$  
Replace:`$1 === $2`

> 中身をすべて選択することがうまくいきません。これではだめなのでしょうか？.* if (inputAnswer.* }

私の回答のリンク先にある、複数行の置換は試していただいたでしょうか。  
カッコはグループ化に使用するので、検索文字として扱うならばエスケープが必要です。

`(?s)^if\s*\(inputAnswer.+?else.+?}`


CC BY-SA 4.0
2018-06-18T01:55:44.257
44832
2018-06-18T03:58:48.787
2018-06-18T03:58:48.787
9820
9820
44830
answer


JavaScriptやPythonの場合は、正規表現による置き換えよりも、ソースコードをAST(抽象構文木)に変換してくれるライブラリーが充実しているので、ASTを使って修正した方が簡単です。

以下は、facebookの [jscodeshift](https://github.com/facebook/jscodeshift) を使った例です。

jscodeshift のインストールは npm を使って

[code]

    $ npm install -g jscodeshift
    
[/code]

使い方は、変換モジュール（transform.js）を以下のように作成して、

[code]

    module.exports = function(fileInfo, api, options) {
      // transform `fileInfo.source` here
      // ...
      // return changed source
      return source;
    };
    
[/code]

`./src`ディレクトリーにコードがある場合であれば、以下のコマンドで変換できます。

[code]

    jscodeshift -t transform.js　'./src' 
    
[/code]

また、オプションで -d を付けると空運転をし、-p をつけるとコードが表示されるので開発のときには便利です。

処理としては、次の3つの手順に分けて行ったらいいと思います。  
手順1. 以下のコードのように変更前のコードの前に変更後のコードをコピーする。コメントにUUIDを付けているのは、`if (randomNum ===
3)`が別の場所にもある場合の対策のためです。  
手順2. 変更後のコードの'1'〜'5'を変更前の該当する文字列で置き換える。  
手順3. 変更前のコードを削除。

[code]

    if (randomNum === 3) {
        //b437e2d6-732a-11e8-adc0-fa7ae01bbebc
        while(i < answerNum) {
            var answerTxt = changeAnswer();
    
            if (answerTxt === '1') {
                correctAnswerEasyQ();
                commentary1.innerHTML = '2';
                commentary2.innerHTML = '3';
    
                getPoint10();
    
                flag = true;
    
                break;
            } else {
                falseNum++;
    
            }
    
            if(falseNum === answerNum && flag === false) {
                mistakeAnswerEasyQ();
                commentary1.innerHTML = '4';
                commentary2.innerHTML = '5';
            }
    
            i++;
        }
    
        if (inputAnswer === "パン") {
            correctAnswerEasyQ();
            commentary1.innerHTML = '【パン】';
            commentary2.innerHTML = 'たくさん！';
    
            getPoint10();
    
            description1.innerHTML = '';
        } else {
            mistakeAnswerEasyQ();
            commentary1.innerHTML = '【パン】';
            commentary2.innerHTML = 'たくさん！';
        }
    }
    
[/code]

手順1.の transform.js  
正規表現による置き換えも可能だし、単にコピーするだけなので全部手作業でしてもそれほど時間は要しないと思いますが、`if (inputAnswer ===
"パン") {`の前にコメントでUUIDを表示するようにしてみます。UUIDがあれば、単純な置き換えでできます。

[code]

    module.exports = function(fileInfo, api, options) {
        const j = api.jscodeshift;
        const root = j(fileInfo.source);
        const comment = j.commentLine('b437e2d6-732a-11e8-adc0-fa7ae01bbebc');
        const transformCalls = root.find(j.IfStatement, {
            test: {
                operator: "===",
                left: {
                    name: 'randomNum'
                },
                right: {
                    value: 3
                }
            }
        });
    
        transformCalls.forEach(p => {
            p.node.consequent.body[0].comments = [comment]
        });
    
        return root.toSource();
    };
    
[/code]

`if(randomNum ===
3)`という条件だけで検索していますが、置き換えしない場所にも同じ式がある場合には、条件を増やすか手作業で削除してください。

手順2.のtransform.js

`transformCalls.forEach`以外の所は手順1.と同じなので省略しています。また、UUIDのコメントを残して置き換えた場合のコードです。

複雑そうに見えますが、[AST Explorer](http://astexplorer.net)
を使うとASTの状態を見ることができるのでそれほどでもありません。`AST
Explorer`を使うときは、上部のメニューバーにある「Transform」で[jscodeshift]を選択してONにします。

[code]

    transformCalls.forEach(p => {
        const p0 = p.node.consequent.body[0];
        const p1 = p.node.consequent.body[1];
        if(p0.comments[0].value === 'b437e2d6-732a-11e8-adc0-fa7ae01bbebc') {
            p0.body.body[1].test.right.value = p1.test.right.value;
            p0.body.body[1].consequent.body[1].expression.right.value =
                p1.consequent.body[1].expression.right.value;
            p0.body.body[1].consequent.body[2].expression.right.value =
                p1.consequent.body[2].expression.right.value;
            p0.body.body[2].consequent.body[1].expression.right.value =
                p1.alternate.body[1].expression.right.value;
            p0.body.body[2].consequent.body[2].expression.right.value =
                p1.alternate.body[2].expression.right.value;
        }
    });
    
[/code]

手順3.のtransform.js  
変更前のコードを削除するのは、もう簡単です。

[code]

    transformCalls.forEach(p => {
        if(p.node.consequent.body[0].comments[0].value === 'b437e2d6-732a-11e8-adc0-fa7ae01bbebc') {
            p.node.consequent.body.pop()
        }
    });
    
[/code]


CC BY-SA 4.0
2018-06-18T23:31:22.397
44865
2018-06-18T23:44:17.710
2018-06-18T23:44:17.710
15171
15171
44830
answer