2016年6月6日月曜日

ブックマークレットと複数行テキストを双方向に変換するJavaScript

ブックマークレットは1行にまとめられていて、文字数にも制限があるため処理に無関係な空白は基本的にありません。
そのため編集の難易度は普通のプログラムよりも高いです。
少しでも見やすく、編集しやすい状態にするためのサンプルを作成しました。
また、複数行のテキストから余分なスペースや改行を取り除くサンプルも作成しました。
 

  function(getsTN){
    // ブックマークレット(一行テキスト)を編集&閲覧のために複数行へ変換する
    var inp=getsTN('input')[0], ta=getsTN('textarea')[0], v=inp.value
    var str='', chr, sw文字列中, 字下げ=0, swVar, sw括弧
    var fun連続 = function(c,l){for(var s='',i=0;i<l;i++){s+=c} return s}
    for(var i=0,L=v.length;i<L;i++){
      chr = v.charAt(i)
      if(sw文字列中){
        str += chr
        if(sw文字列中==chr){sw文字列中 = false}
      }else{
        switch(chr){
          case '"': case "'":
            sw文字列中 = chr
            str += chr
            continue
          case '{':
            字下げ++
            if(swVar){swVar=false}
          case ';':
            if(sw括弧){
              str += chr
            }else{
              str += chr + '\r\n' + fun連続('\t',字下げ)
            }
            if(swVar){swVar=false}
            break
          case '}':
            字下げ--
            if(str.match(/([^\v]+\r\n[\t]*\})\r\n[\t]*$/)){ str = RegExp.$1 }
            str += '\r\n' + fun連続('\t',字下げ) + chr + '\r\n' + fun連続('\t',字下げ)
            if(swVar){swVar=false}
            break
          case ',':
            if(swVar && !sw括弧){ str += ',\r\n' + fun連続('\t',字下げ) + '    ' }else{ str += chr }
            break
          default:
            switch(chr){
              case '(': if(!sw括弧 && !sw文字列中){sw括弧 = true } break
              case ')': if( sw括弧 && !sw文字列中){sw括弧 = false} break
              case 'v': if(!swVar && (str.slice(str.length-1)+v.slice(i,i+5)).match(/\tvar |:void /)){swVar = true} break
            }
            str += chr
        }
      }
    }
    ta.value = str
  }
  function(getsTN){
    // 複数行テキストをブックマークレット(一行テキスト)へ変換する
    var inp=getsTN('input')[0], ta=getsTN('textarea')[0], v=ta.value
    var str='', sw文字列中, chr, arr='break/delete/return/typeof/case/var/void/new'.split('/'), obj={}, i, L, chr, key, reg
    for(i=0,L=arr.length;i<L;i++){
      key = arr[i]
      chr = key.charAt(0)
      if(!obj[chr]){ obj[chr]={} }
      obj[chr][key] = true
    }
    for(i=0,L=v.length; i<L ;i++){
      chr = v.charAt(i)
      if(sw文字列中){
        str += chr
        if(sw文字列中==chr){sw文字列中 = false}
      }else{
        if(obj[chr]){
          var sw一致=false
          for(key in obj[chr]){
            reg=new RegExp('([^\d]'+key+' )')
            if(v.slice(i-1,i+key.length+1).match(reg)){
              var s=RegExp.$1, l=s.length
              str += s.slice(1,l)
              i += l-2
              sw一致=true
            }
          }
          if(!sw一致){ str += chr }
          continue
        }
        
        switch(chr){
          case '\r':case '\n':case '\t':case ' ': continue
          case '|':
            if(v.slice(i-1,i+3).match(/( \|\| )/)){
              var s=RegExp.$1, l=s.length
              str += s.slice(0,l)
              i += l-2
            }else{
              str += chr
            }
            break
          case '"': case "'": sw文字列中 = chr
          default:
            str += chr
        }
      }
    }
    inp.value = str
  }
2016/07/26:「new Option」のように「new」の後ろにスペースが必要なケースでスペースを削除してしまっていたのを修正した。

0 件のコメント:

コメントを投稿