「ひらがな/カタカナ変換」の版間の差分

編集の要約なし
MSY-07 (トーク | 投稿記録)
空行と改行の除去
 
(3人の利用者による、間の7版が非表示)
1行目: 1行目:
== ひらがな/カタカナ トグル変換 ==  
== ひらがな/カタカナ トグル変換 ==  
実行するごとに「ひらがな ⇔ カタカナ」の相互変換をします。
※ ひらがなとカタカナが混在した文字列はカタカナに統一します。
=== マルチカーソル/複数選択範囲での動作 ===
'''マルチカーソル/複数選択範囲''' での推奨動作要件: Mery Ver <b style="color:#c00;">3.0.1</b> 以上


実行するごとに「ひらがな ⇔ カタカナ」の相互変換をします。
; 制限事項<br>
<br><br>
* <span style="color:#c00;">複数の選択範囲にたいして統一的に「ひらがな化」または「カタカナ化」の変換を適用することはできません。</span><br> それぞれの選択範囲ごとに「ひらがな化/カタカナ化」の変換方式が個別に適用されます(「カタカナ」の選択範囲と「ひらがな」の選択範囲がある場合、前者の選択範囲の文字列は「ひらがなに変換」され、後者の選択範囲の文字列は「カタカナに変換」されます。<br> また、ひらがな/カタカナの混在した文字列の場合はカタカナ化されます)。
* エディタが折り返し表示になっているとき、<span style="color:#c00;">折り返しより後ろ(改行まで)の文字列は矩形選択範囲内の文字列とみなされません。</span><br> また、同一論理行内で完結した矩形選択では変換しません。<br> あらかじめ、変換の必用な部分だけを Ctrl+ドラッグ で複数選択範囲にするか「選択範囲を行に分ける」コマンド(右クリックメニュー用コマンド)を適用してから、このマクロを実行してください。
* <span style="color:#c00;">矩形選択範囲から実行した場合も変換後に選択範囲を復帰しますが、矩形選択範囲ではなく、複数選択状態になります</span> (文字幅が変わるため矩形選択ではズレてしまい、正常に復帰できない)。
 
=== ソースコード ===
; ダウンロード >> 「[[ファイル:ひらがな/カタカナ変換.zip]]」(アイコン入り)
; ダウンロード >> 「[[ファイル:ひらがな/カタカナ変換.zip]]」(アイコン入り)
<source lang="javascript">
 
2020/07/08: 第2版の修正版<br>
* ひらがな/カタカナのない複数選択範囲から実行したときに UNDO 履歴が残らないように変更<br>
2020/06/24: 第2版
* Mery Ver 3.0.1 以降のマルチカーソル/複数選択範囲に対応
* ブックマーク保守の処理を最適化
2020/01/03: 初版
 
<syntaxhighlight lang="javascript" style="height:80em; overflow:auto;">
#title = "ひらがな/カタカナ変換"
#title = "ひらがな/カタカナ変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
#icon = "文字_あア[1].ico"
#icon = "あア[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl", 324
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl", 324


// ---------- ▼ 設定項目 ▼ ----------
/**
* --------------------------------------------------------
* ひらがな/カタカナ トグル変換
* sukemaru, 2020/01/03 - 2020/07/08
* --------------------------------------------------------
* ※ Mery Ver 3.0.1 以降の矩形選択範囲とマルチカーソル/複数選択範囲に対応
*/
 
// ---------- ▼ 設定項目 ▼ ---------- //


// ■ 選択範囲がないとき
// ■ 選択範囲がないとき
22行目: 48行目:
   */
   */


// ---------- ▲ 設定項目 ▲ ----------
// ---------- ▲ 設定項目 ▲ ---------- //


var d = editor.ActiveDocument,  s = d.selection;
var d = editor.ActiveDocument,  s = d.selection;
var isEmpty = s.IsEmpty;


if ( d.ReadOnly ) {
if ( d.ReadOnly ) {
   Status = " このドキュメントは書き換え禁止です。";
   Status = " このドキュメントは書き換え禁止です。";
}
}
else if ( isEmpty && autoSelection == 0 ) {
else if ( s.IsEmpty && ! autoSelection ) {
   Status = " 選択範囲がありません。";
   Status = " 選択範囲がありません。";
}
}
else {
else {
   Redraw = false;
   editor.ExecuteCommandByID( 2189 ); // アクティブなペイン
   var sx = ScrollX,  sy = ScrollY;
   var sx = ScrollX,  sy = ScrollY;
   var ay = s.GetActivePointY( mePosLogical );
 
   var pos = ( isEmpty ) ? s.GetActivePos() : -1;
  // マルチカーソル/複数選択に対応
   var arg = [ autoSelection ];
  // 選択範囲が1つで矩形選択ではないとき
  if ( ! s.Mode || s.Mode == 1 ) {
    KanaGanaConv( arg );
   }
  // 矩形選択または複数選択のとき
  else {
    var st = s.Text;
    BeginUndoGroup();
    AddUndo();
    MultiFunction( KanaGanaConv, arg );
    EndUndoGroup();
    // 変換なしなら AddUndo を破棄する ◆2020/07/08◆
    if ( s.Text === st ) { d.Undo(); }
  }
 
  ScrollX = sx;  ScrollY = sy;
}
 
/**
* 関数 KanaGanaConv( autoSelection )
* ひらがな/カタカナ トグル変換
*/
function KanaGanaConv( arg ) {
  var autoSelection = arg[0];
 
  var d = editor.ActiveDocument,  s = d.selection;
  var pos = s.IsEmpty ? s.GetActivePos() : -1;


   // 非選択時には自動選択
   // 非選択時には自動選択
   if ( isEmpty ) {
   if ( pos > -1 ) {
     if ( autoSelection == 1 ) {
     if ( autoSelection === 1 ) {
       s.SelectWord();
       s.SelectWord();
      if ( s.GetActivePointY( mePosLogical ) != ay ) {
        s.SetActivePos( pos );
      }
     }
     }
     else if ( autoSelection == 2 || autoSelection == 3 ) {
     else if ( autoSelection === 2 || autoSelection === 3 ) {
       var posMode = autoSelection - 1;
       var posMode = autoSelection - 1;
      s.EndOfLine( false, posMode );
       s.SetAnchorPoint( posMode, 1, s.GetActivePointY ( posMode ) );
       s.SetAnchorPoint( posMode, 1, s.GetActivePointY ( posMode ) );
      s.EndOfLine( true, posMode );
     }
     }
     else if ( autoSelection == 4 ) { s.SelectAll(); }
     else if ( autoSelection === 4 ) { s.SelectAll(); }
  }
  var tp = Math.min( s.GetActivePos(), s.GetAnchorPos() );
  var ty = s.GetTopPointY( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var a = 0;
  if ( ty < by && bx === 1 ) {
    by --;  a = 1;
    s.SetActivePoint( mePosLogical, d.GetLine( by, 0 ).length + 1, by );
    s.SetAnchorPos( tp );
   }
   }
   var st = s.Text;
   var st = tmp = s.Text;


   if ( st ) {
   if ( st ) {
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();
     // ● ひらがな ⇒ 全角カタカナ変換 「ゔ ゕ ゖ ⇒ ヴ ヵ ヶ」含む
    var tp = Math.min( anc, act );
     tmp = st.replace( /う[゛゙\u3099]/g, "ヴ" )
    var tmp;
 
     // ひらがな → 全角カタカナ変換 「ゔ ゕ ゖ → ヴ ヵ ヶ」含む
     tmp = st.replace( /う[゛゙u\3099]/g, "ヴ" )
             .replace( /[\u3041-\u3096\u309D\u309E]/g, function( chr ) {
             .replace( /[\u3041-\u3096\u309D\u309E]/g, function( chr ) {
             return String.fromCharCode( chr.charCodeAt( 0 ) + 0x60 );
             return String.fromCharCode( chr.charCodeAt( 0 ) + 0x60 );
68行目: 124行目:
     // ※ unicode 文字に対応できるときは「ヷ ヸ ヹ ヺ」に変換
     // ※ unicode 文字に対応できるときは「ヷ ヸ ヹ ヺ」に変換
     if ( d.Encoding >= 65000 ) {
     if ( d.Encoding >= 65000 ) {
       tmp = tmp.replace( /ワ[゛゙u\3099]/g, "ヷ" ).replace( /ヰ[゛゙u\3099]/g, "ヸ" )
       tmp = tmp.replace( /ワ[゛゙\u3099]/g, "\u30F7" ).replace( /ヰ[゛゙\u3099]/g, "\u30F8" )
               .replace( /ヱ[゛゙u\3099]/g, "ヹ" ).replace( /ヲ[゛゙u\3099]/g, "ヺ" );
               .replace( /ヱ[゛゙\u3099]/g, "\u30F9" ).replace( /ヲ[゛゙\u3099]/g, "\u30FA" );
     }
     }


     if ( st == tmp ) {
     if ( st === tmp ) {
       // 全角カタカナ → ひらがな変換
       // ● 全角カタカナ ⇒ ひらがな変換
       // ※ 「ヷ ヸ ヹ ヺ」は「かな+濁点」に分解する
       // ※ 「ヷ ヸ ヹ ヺ」は「かな+濁点」に分解する
       tmp = st.replace( /\u30F7/g, "わ゛" ).replace( /\u30F8/g, "ゐ゛" )
       tmp = st.replace( /\u30F7/g, "わ゛" ).replace( /\u30F8/g, "ゐ゛" )
80行目: 136行目:
               return String.fromCharCode( chr.charCodeAt( 0 ) - 0x60 );
               return String.fromCharCode( chr.charCodeAt( 0 ) - 0x60 );
       } );
       } );
       // ※ unicode 文字に対応できるときは「ヴ ヵ ヶ → ゔ ゕ ゖ」に変換
       // ※ unicode 文字に対応できるときは「ゔ ゕ ゖ」に変換
       if ( d.Encoding >= 65000 ) {
       if ( d.Encoding >= 65000 ) {
         tmp = tmp.replace( /[\u30F4-\u30F6]/g, function( chr ) {
         tmp = tmp.replace( /[\u30F4-\u30F6]/g, function( chr ) {
86行目: 142行目:
         } );
         } );
       }
       }
       // ※ Shift_JIS などでは「ヴ ヵ ヶ → う゛ ヵ ヶ」
       // ※ Shift_JIS などでは「ヴ ヵ ヶ ⇒ う゛ ヵ ヶ」
       else {
       else {
         tmp = tmp.replace( /\u30F4/g, "う゛" );
         tmp = tmp.replace( /\u30F4/g, "う゛" );
92行目: 148行目:
     }
     }


     if ( st != tmp ) {
     if ( st !== tmp ) {
       // ブックマークを保存
       // ブックマークを保存
       var bmArray = [];
       var bmArray = GetBookmark( ty, by );
      s.SetActivePoint( mePosLogical, 1, 2 );
      if ( s.PreviousBookmark() ) {
        bmArray.push( s.GetActivePointY( mePosLogical ) );
      }
      s.SetActivePos( 0 );
      while ( s.NextBookmark() ) {
        bmArray.push( s.GetActivePointY( mePosLogical ) );
      }
      s.SetActivePos( anc );  s.SetActivePos( act, true );
      ScrollX = sx;  ScrollY = sy;


       // 選択範囲を変換
       // 選択範囲を変換
       s.Text = tmp;
       s.Text = tmp;
      act = s.GetActivePos();


       // ブックマークを復元
       // ブックマークを復元
       var bmCount = bmArray.length;
       RestoreBookmark( ty, by, bmArray );
       if ( bmCount ) {
 
        editor.ExecuteCommandByID( 2129 ); // ブックマークをクリア
      s.SetActivePos( tp + tmp.length + a );
        for ( var i = 0; i < bmCount; i ++ ) {
      s.SetAnchorPos( tp );
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
    }
           editor.ExecuteCommandByID( 2126 ); // ブックマークを設定/解除(設定)
 
    else {
      Status = " ひらがな/カタカナ がありません。";
       if ( pos > -1 ) { s.SetActivePos( pos ); }
    }
  }
}
 
 
/**
* 関数 GetBookmark( ty, by )
* 指定された範囲のブックマークを収集
*/
function GetBookmark( ty, by ) {
  var bmArray = [],  bmY;
  var s = editor.ActiveDocument.selection;
  if ( ty < by ) {
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();
 
    if ( ty === 1 ) {
      s.SetActivePoint( mePosLogical, 1, 2 );
      if ( s.PreviousBookmark() ) {
        bmY = s.GetActivePointY( mePosLogical );
        if ( bmY >= ty && bmY <= by ) {
           bmArray.push( bmY );
         }
         }
       }
       }
       s.SetActivePos( tp );  s.SetActivePos( act, true );
       s.SetActivePos( 0 );
    }
    else { s.SetActivePoint( mePosLogical, 1, ty - 1 ); }
 
    while ( s.NextBookmark() ) {
      bmY = s.GetActivePointY( mePosLogical );
      if ( bmY >= ty && bmY <= by ) {
        bmArray.push( bmY );
      }
      else if ( bmY > by ) { break; }
    }
    s.SetActivePos( act );  s.SetAnchorPos( anc );
  }
  return bmArray;
}
 
/**
* 関数 RestoreBookmark( ty, by, bmArray, sel )
* 指定された範囲のブックマークを復元
*/
function RestoreBookmark( ty, by, bmArray, sel ) {
  var bmCount = bmArray.length;
  if ( bmCount ) {
    var s = editor.ActiveDocument.selection;
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();
    s.SetActivePoint( mePosLogical, 1, ty );
    s.ClearBookmark();
    for ( var i = 0; i < bmCount, bmArray[i] <= by; i ++ ) {
      if ( bmArray[i] < ty ) { continue; }
      s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
      s.SetBookmark();
    }
    if ( sel ) {
      s.SetActivePos( act );  s.SetAnchorPos( anc );
     }
     }
     else {
  }
       Status = " ひらがな/カタカナ がありません。";
}
      if ( pos >= 0 ) { s.SetActivePos( pos ); }
 
 
/**
* 関数 MultiFunction( Fn, arg1 )
* マルチカーソル(複数選択範囲)に対応させる
* ※ 文字数が変化しないマクロ用: 矩形選択を復帰可
*
* 第1引数: Function; 選択範囲ごとに適用する処理の関数
* 第2引数以降: Function に渡す引数をまとめた配列
*/
function MultiFunction( Fn, arg ) {
  var d = editor.ActiveDocument;
  var s = d.selection;
 
  // 矩形選択範囲は行に分ける
  var sMode = s.Mode;
  if ( sMode == 2 ) {
     var act = s.GetActivePos(),  anc = s.GetAnchorPos();
  }
  s.Mode = 3;
 
  // 選択範囲の座標を取得
  var sCount = s.Count;
  var Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = {
       act: s.GetActivePos( i ),
      anc: s.GetAnchorPos( i )
    };
  }
 
  // 各選択範囲を処理;
  for ( var i = 0, diff = 0, dl; i < sCount; i ++ ) {
    dl = d.TextLength;
    s.SetActivePos( Sel[i].act + diff );
    s.SetAnchorPos( Sel[i].anc + diff );
 
    Fn( arg ); // KanaGanaConv() 関数
 
    // Fn() の残した選択範囲(またはキャレット位置)を回収
    Sel[i].act = s.GetActivePos();
    Sel[i].anc = s.GetAnchorPos();
    diff += d.TextLength - dl; // 文字数の増減量(累積)
  }
 
  // 矩形選択範囲を復帰(文字数が変化していた場合はズレる)
  if ( sMode == 2 ) {
    s.SetAnchorPos( anc );
    s.SetActivePos( act, true );
    s.Mode = 2;
  }
  // マルチカーソル(複数選択範囲)を復帰
  else {
    for ( var i = 0; i < sCount; i ++ ) {
      s.AddPos( Sel[i].anc, Sel[i].act );
     }
     }
   }
   }
  ScrollX = sx;  ScrollY = sy;
  Redraw = true;
}
}
</source>
</syntaxhighlight>
<br>
----
----
<br>
以下2件、<b>参照 >> 『[[テキスト整形#字種/数値変換|テキスト整形]]』マクロ</b>
以下、<b>参照 >> 『[[テキスト整形#字種/数値変換|テキスト整形]]』マクロ</b>


=== ひらがな → カタカナ変換 ===  
== ひらがな → カタカナ変換 ==
<source lang="javascript">
<syntaxhighlight lang="javascript">
#title = "ひらがな → カタカナ変換"
#title = "ひらがな → カタカナ変換"
// e.g. 「あいうえお」 → 「アイウエオ」
// e.g. 「あいうえお」 → 「アイウエオ」
146行目: 298行目:
   });
   });
}
}
</source>
</syntaxhighlight>


=== カタカナ → ひらがな変換 ===
== カタカナ → ひらがな変換 ==
<source lang="javascript">
<syntaxhighlight lang="javascript">
#title = "全角カタカナ → ひらがな変換"
#title = "全角カタカナ → ひらがな変換"
// e.g. 「アイウエオ」 → 「あいうえお」
// e.g. 「アイウエオ」 → 「あいうえお」
159行目: 311行目:
   });
   });
}
}
</source>
</syntaxhighlight>


== ひらがな/カタカナ マルチカーソル対応版 (トグル変換未対応) by Kuro ==
== ひらがな/カタカナ マルチカーソル対応版 (トグル変換未対応) by Kuro ==
Mery Ver 3.0.0 のマルチカーソルに対応する例として sukemaru さんのソースコードをもとにカスタマイズしてみました。
Mery Ver 3.0.0 のマルチカーソルに対応する例として sukemaru さんのソースコードをもとにカスタマイズしてみました。


169行目: 320行目:
マクロからマルチカーソルの位置を取得することはできるのですが、マルチカーソルを設置する機能がないので複数選択の状態を復元することができないためトグル変換に対応できていません。
マクロからマルチカーソルの位置を取得することはできるのですが、マルチカーソルを設置する機能がないので複数選択の状態を復元することができないためトグル変換に対応できていません。


複数の選択範囲に対して変換処理を行うときに、ひらがな・カタカナ変換のように行数が変化しないものはこのようにシンプルに書けますが、変換前と変換後で行数が変わる場合は複数選択の位置を再計算してやる必要があるのでもう少し大変だと思います。
複数の選択範囲に対して変換処理を行うときに、ひらがな・カタカナ変換のように文字数・行数が変化しないものはこのようにシンプルに書けますが、変換前と変換後で文字数・行数が変わる場合は複数選択の位置を再計算してやる必要があるのでもう少し大変だと思います。


<source lang="javascript">
追記: よく見ると「わ゛」あたりの変換は文字数が変わっているので、このままだと位置がずれそうです。
→ とりあえず暫定で文字数が変化したときに再計算するようにしてみましたが、少々強引な気もします。(2020/03/15)
 
<syntaxhighlight lang="javascript">
#title = "ひらがな/カタカナ変換"
#title = "ひらがな/カタカナ変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
235行目: 389行目:
   BeginUndoGroup();
   BeginUndoGroup();
   try {
   try {
    var cnt = 0;
    var len = 0;
     for (var i = 0; i < selections.length; i++) {
     for (var i = 0; i < selections.length; i++) {
       // 複数選択の箇所に現在のカーソルを設定する (選択範囲の開始と終了が逆になることがあるけど気にしない方向で…)
       // 複数選択の箇所に現在のカーソルを設定する (選択範囲の開始と終了が逆になることがあるけど気にしない方向で…)
       s.SetActivePoint( mePosLogical, selections[i].bx, selections[i].by, false );
       s.SetActivePoint( mePosLogical, selections[i].bx, selections[i].by, false );
      s.SetActivePos( s.GetActivePos() + cnt, false );
       s.SetActivePoint( mePosLogical, selections[i].tx, selections[i].ty, true );
       s.SetActivePoint( mePosLogical, selections[i].tx, selections[i].ty, true );
      s.SetActivePos( s.GetActivePos() + cnt, true );
      len = d.Text.length;
       Convert(s.IsEmpty, s.GetActivePointY( mePosLogical ), ( isEmpty ) ? s.GetActivePos() : -1);
       Convert(s.IsEmpty, s.GetActivePointY( mePosLogical ), ( isEmpty ) ? s.GetActivePos() : -1);
      cnt += d.Text.length - len;
     }
     }
   } finally {
   } finally {
342行目: 502行目:
   }
   }
}
}
</source>
</syntaxhighlight>
 
== メモ ==
@ Kuro さん <br>
: 第2版でマルチカーソル/複数選択範囲からの実行と、選択範囲の復帰ができるようになりました。<br>
また、ほかのテキスト操作・変換系マクロも同様にマルチカーソル対応にすることができました。<br>
参考コードをいただき、ありがとうございました。(sukemaru, 2020/06/24 - 2020/07/08)
スポンサーリンク