再帰を利用して、HTMLのテキスト(タグで仕切られた範囲)を全て”[num]”に切り替えるプログラムを作りたいのですが、  
Javascriptが初めてなのもありまして、なかなか目標を達成することができません。  
例えば、

```

    入力
    ＜a＞はじめまして＜/a＞
    ＜a＞h_chicKerです＜/a＞
    ＜a＞よろしくお願いします。＜/a＞
    
    =>
    出力
    ＜a＞NUM:1＜/a＞
    ＜a＞NUM:2＜/a＞
    ＜a＞NUM:3＜/a＞
    
```

のようにしたいです。  
変換するHTMLの例は  
<https://teratail.com>  
のトップページとします。  
再帰の雛形は作ってみました。

```

      <script type="text/javascript">
    
        function changeStr(element) {
    
        if (element == null) {
        var element = document.body;
        }
        if (element.childNodes.length > 0) {
        changeColor(element.firstChild);
        }
        if (element.nodeType == 1) {
        //ここに処理を書く？
        }
        }
    
      </script>
    
```

なにかありましたら、随時補足させていただきます。  
よろしくお願いします。
CC BY-SA 3.0
2015-12-07T15:54:21.453
19727
2015-12-09T23:44:57.710
12470
question
javascript html
再帰を用いた文字列の変換
再帰的に該当するノードをコレクションする[弾さん作成](http://blog.livedoor.jp/dankogai/js/resize.txt)`getElementsByFunction`のような関数を作っておくとこういう場合に便利です。  
（コレクションした後は単なるループで処理できます。このようにしない場合でも再帰的にノードを探索する例としてgetElementsByFunctionが参考になると思います。）  
以下の例はgetElementsByFunctionで指定したノード以下のテキストノードで改行以外のものを置き換えます。

```

    <html>
    <head>
    <title>example</title>
    <script type="text/javascript">
    var getElementsByFunction = function(root, func){
      var result = [];
      (function(node){
        var kids = node.childNodes;
        for (var i = 0, l = kids.length; i < l; i++){
          if (func(kids[i])) result[result.length] = kids[i];
          if (kids[i].hasChildNodes()) arguments.callee(kids[i]);
        }
      })(root);
      return result;
    };
    </script>
    <script type="text/javascript">
    function isTextNode(node){
     return node.nodeType == 3; //TEXT_NODE
    }
    function test(){
     var nodes = getElementsByFunction(document.getElementById("block1"), isTextNode);
     var j = 1;
     for(var i = 0; i < nodes.length; ++i){
      if(nodes[i].nodeValue != "\n")
       nodes[i].nodeValue = "NUM:" + j++;
     }
    }
    </script>
    </head>
    <body>
    <div id="block1"><p>text1</p>
    <a href=".">text2</a>
    <a href=".">text3</a>
    </div>
    <button onclick="test()">実行</button>
    
    </body>
    </html>
```
CC BY-SA 3.0
2015-12-07T16:53:12.320
19731
2015-12-07T16:53:12.320
5044
19727
answer
例えば、のケースであれば下のコードで実装できます。

```

    <div id="target">
      <a>aaa</a>
      <a>bbb</a>
      <a>ccc</a>
    </div>
    
```

もし質問の意図と違っていたらコメントください。

```

    function changeStr(element) {
      if (element == null) {
        var element = document.getElementById("target");
      }
    
      if (element.nodeType == 1) {
        Array.prototype.forEach.call(element.children, function(e, i) {
          e.textContent = "NUM:" + (i + 1);
        });
      }
    };
    
```

* * *
```

    function changeStr(element) {
      if (element == null) {
        var element = document.getElementById("target");
      }
    
      if (element.nodeType == 1) {
        Array.prototype.forEach.call(element.children, function(e, i) {
          e.textContent = "NUM:" + (i + 1);
        });
      }
    };
```

```

    <div id="target">
      <a>aaa</a>
      <a>bbb</a>
      <a>ccc</a>
      <p>ddd<b>eee</b>fff</p>
    </div>
    <button onclick="changeStr(null)">実行</button>
```

* * *

【実行前】

```

    <div id="target">
      <a>aaa</a>
      <a>bbb</a>
      <a>ccc</a>
      <p>ddd<b>eee</b>fff</p>
    </div>
    
```

【実行後】

```

    <div id="target">
      <a>NUM:1</a>
      <a>NUM:2</a>
      <a>NUM:3</a>
      <p>NUM:4<b>NUM:5</b>NUM:6</p>
    </div>
    
```

* * *

上記【実行前】、【実行後】を想定して書いてみましたがいかがでしょうか。

```

    function changeStr(element) {
      if (element == null) {
        var element = document.getElementById("target");
      }
    
      if (element.nodeType == 1) {
        var result = {};
    
        result.index = 0;
        result.count = 1;
        result.str = element.innerHTML
          .replace(/\s*(<[a-z])/gi, "$1").trim()
          .replace(/>([^<]+)</g, ">NUM:<");
    
        do {
          result = _numIncrement(result.str, result.index, result.count);
    
          result.index = result.index + 1;
          result.count = result.count + 1;
        } while(result.index);
    
        element.innerHTML = result.str;
      }
    
      function _numIncrement(_str, _index, _count) {
        var _numIndex = _str.indexOf("NUM:", _index);
        var _before = _str.substr(0, _numIndex + 4);
        var _after = _str.substr(_numIndex + 4);
    
        if(_numIndex >= 0) {
          _str = _before + _count + _after;
        }
    
        return {"str": _str, "index": _numIndex, "count": _count};
      };
    };
```

```

    <div id="target">
      <a>aaa</a>
      <a>bbb</a>
      <a>ccc</a>
      <p>ddd<b>eee</b>fff</p>
    </div>
    <button onclick="changeStr(null)">実行</button>
```
CC BY-SA 3.0
2015-12-08T00:17:06.040
19740
2015-12-09T04:56:04.650
2015-12-09T04:56:04.650
13493
13493
19727
answer
再帰の勉強をしているのでなければ、jQueryで簡単に実現可能です。

```

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
        <script>
          function test() {
            $('#block1 *')
              .contents()
              .filter(function() {
                return this.nodeType==3 && $.trim($(this).text()).length > 0;
              })
              .each(function(index, value) {
                this.nodeValue = 'NUM:' + (index+1);
              });
          }
        </script>
      </head>
      <body>
        <div id="block1"><p>text1</p>
          <a href=".">text2</a>
          <a href=".">text3</a>
          <p>ddd<b>eee</b>fff</p>
        </div>
        <button onclick="test()">実行</button>
      </body>
    </html>
    
```

出力

```

    <div id="block1"><p>NUM:1</p>
          <a href=".">NUM:2</a>
          <a href=".">NUM:3</a>
          <p>NUM:4<b>NUM:6</b>NUM:5</p>
    </div>
    
```
CC BY-SA 3.0
2015-12-09T02:23:57.050
19778
2015-12-09T23:44:57.710
2015-12-09T23:44:57.710
7837
7837
19727
answer