ひらがな/カタカナ変換

提供: MeryWiki
ナビゲーションに移動 検索に移動

ひらがな/カタカナ トグル変換[編集]

実行するごとに「ひらがな ⇔ カタカナ」の相互変換をします。
※ ひらがなとカタカナが混在した文字列はカタカナに統一します。


マルチカーソル/複数選択範囲での動作[編集]

マルチカーソル/複数選択範囲 での推奨動作要件: Mery ver 3.0.1 以上

制限事項
  • 複数の選択範囲にたいして統一的に「ひらがな化」または「カタカナ化」の変換を適用することはできません。
    それぞれの選択範囲ごとに「ひらがな化/カタカナ化」の変換方式が個別に適用されます(「カタカナ」の選択範囲と「ひらがな」の選択範囲がある場合、前者の選択範囲の文字列は「ひらがなに変換」され、後者の選択範囲の文字列は「カタカナに変換」されます。
    また、ひらがな/カタカナの混在した文字列の場合はカタカナ化されます)。


  • エディタが折り返し表示になっているとき、折り返しより後ろ(改行まで)の文字列は矩形選択範囲内の文字列とみなされません。
    また、同一論理行内で完結した矩形選択では変換しません。
    あらかじめ、変換の必用な部分だけを Ctrl+ドラッグ で複数選択範囲にするか「選択範囲を行に分ける」コマンド(右クリックメニュー用コマンド)を適用してから、このマクロを実行してください。
  • 矩形選択範囲から実行した場合も変換後に選択範囲を復帰しますが、矩形選択範囲ではなく、複数選択状態になります (文字幅が変わるため矩形選択ではズレてしまい、正常に復帰できない)。


ソースコード[編集]

ダウンロード >> 「ファイル:ひらがな/カタカナ変換.zip」(アイコン入り)

2020/07/08: 第2版の修正版

  • ひらがな/カタカナのない複数選択範囲から実行したときに UNDO 履歴が残らないように変更

2020/06/24: 第2版

  • Mery ver 3.0.1 以降のマルチカーソル/複数選択範囲に対応
  • ブックマーク保守の処理を最適化

2020/01/03: 初版

#title = "ひらがな/カタカナ変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
#icon = "あア[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl", 324

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

// ---------- ▼ 設定項目 ▼ ---------- //

// ■ 選択範囲がないとき
var autoSelection = 1;
  /**
   * 0: なにもしない
   * 1: カーソル位置の単語を自動選択
   * 2: カーソル位置の行全体(表示行)を自動選択
   * 3: カーソル位置の行全体(論理行)を自動選択
   * 4: 文書全体を自動選択
   */

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

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

if ( d.ReadOnly ) {
  Status = " このドキュメントは書き換え禁止です。";
}
else if ( s.IsEmpty && ! autoSelection ) {
  Status = " 選択範囲がありません。";
}
else {
  editor.ExecuteCommandByID( 2189 );	// アクティブなペイン
  var sx = ScrollX,  sy = ScrollY;

  // マルチカーソル/複数選択に対応
  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 ( pos > -1 ) {
    if ( autoSelection === 1 ) {
      s.SelectWord();
    }
    else if ( autoSelection === 2 || autoSelection === 3 ) {
      var posMode = autoSelection - 1;
      s.EndOfLine( false, posMode );
      s.SetAnchorPoint( posMode, 1, s.GetActivePointY ( posMode ) );
    }
    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 = tmp = s.Text;

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

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

    if ( st !== tmp ) {
      // ブックマークを保存
      var bmArray = GetBookmark( ty, by );

      // 選択範囲を変換
      s.Text = tmp;

      // ブックマークを復元
      RestoreBookmark( ty, by, bmArray );

      s.SetActivePos( tp + tmp.length + a );
      s.SetAnchorPos( tp );
    }

    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( 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 );
    }
  }
}


/**
 * 関数 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 );
    }
  }
}




以下2件、参照 >> 『テキスト整形』マクロ

ひらがな → カタカナ変換[編集]

#title = "ひらがな → カタカナ変換"
// e.g. 「あいうえお」 → 「アイウエオ」

var s = document.selection;
if( s.Text ) {
  s.Text = s.Text.replace( /[\u3041-\u3096\u309D\u309E]/g, function( t ) {
    return String.fromCharCode( t.charCodeAt( 0 ) + 0x60 )
  });
}

カタカナ → ひらがな変換[編集]

#title = "全角カタカナ → ひらがな変換"
// e.g. 「アイウエオ」 → 「あいうえお」

var s = document.selection;
if( s.Text ) {
  s.Text = s.Text.replace( /[\u30A1-\u30F3\u30FD\u30FE]/g, function( t ) {
    return String.fromCharCode( t.charCodeAt( 0 ) - 0x60 )
  });
}


ひらがな/カタカナ マルチカーソル対応版 (トグル変換未対応) by Kuro[編集]

Mery Ver 3.0.0 のマルチカーソルに対応する例として sukemaru さんのソースコードをもとにカスタマイズしてみました。

変換処理の部分は手を加えずメソッド化しただけです。

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

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

追記: よく見ると「わ゛」あたりの変換は文字数が変わっているので、このままだと位置がずれそうです。 → とりあえず暫定で文字数が変化したときに再計算するようにしてみましたが、少々強引な気もします。(2020/03/15)

#title = "ひらがな/カタカナ変換"
#tooltip = "ひらがな/全角カタカナ のトグル変換"
#icon = "文字_あア[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl", 324

// ---------- ▼ 設定項目 ▼ ----------

// ■ 選択範囲がないとき
var autoSelection = 1;
  /**
   * 0: なにもしない
   * 1: カーソル位置の単語を自動選択
   * 2: カーソル位置の行全体(表示行)を自動選択
   * 3: カーソル位置の行全体(論理行)を自動選択
   * 4: 文書全体を自動選択
   */

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

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

if ( d.ReadOnly ) {
  Status = " このドキュメントは書き換え禁止です。";
}
else if ( isEmpty && autoSelection == 0 ) {
  Status = " 選択範囲がありません。";
}
else {
  Redraw = false;
  var sx = ScrollX,  sy = ScrollY;

  // 以下、変更した箇所
  // ---------------------------------ここから---------------------------------
  // もともとここにあった処理は下部の Convert 関数にそのまま移動

  // 複数選択を保持しておくための配列 (SetActivePoint を使うと複数選択が解除されるため、事前に選択箇所を格納しておく必要がある)
  var selections = [];

  // マルチカーソルの場合、document.selection.Count は 0 より大きい値が返る
  if (document.selection.Count > 0) {
    for (var i = 0; i < document.selection.Count; i++) {
      // GetTopPointX、GetTopPointY、GetBottomPointX、GetBottomPointY のみ、第二引数に 0 以上の値を指定すれば複数選択の箇所が取得できる
      selections.push({
        tx: s.GetTopPointX( mePosLogical, i ),
        ty: s.GetTopPointY( mePosLogical, i ),
        bx: s.GetBottomPointX( mePosLogical, i ),
        by: s.GetBottomPointY( mePosLogical, i )
      });
    }
  // マルチカーソルではない場合
  } else {
    // GetTopPointX、GetTopPointY、GetBottomPointX、GetBottomPointY は第二引数を省略するか -1 を指定すれば現在のカーソル位置が取得できる
    selections.push({
      tx: s.GetTopPointX( mePosLogical ),
      ty: s.GetTopPointY( mePosLogical ),
      bx: s.GetBottomPointX( mePosLogical ),
      by: s.GetBottomPointY( mePosLogical )
    });
  }

  BeginUndoGroup();
  try {
    var cnt = 0;
    var len = 0;
    for (var i = 0; i < selections.length; i++) {
      // 複数選択の箇所に現在のカーソルを設定する (選択範囲の開始と終了が逆になることがあるけど気にしない方向で…)
      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.SetActivePos( s.GetActivePos() + cnt, true );
      len = d.Text.length;
      Convert(s.IsEmpty, s.GetActivePointY( mePosLogical ), ( isEmpty ) ? s.GetActivePos() : -1);
      cnt += d.Text.length - len;
    }
  } finally {
    EndUndoGroup();
  }
  // 今のところマクロから複数選択を設定する仕組みがないので複数の選択範囲を復元することはできません
  // ---------------------------------ここまで---------------------------------

  ScrollX = sx;  ScrollY = sy;
  Redraw = true;
}

// Convert メソッドの中身はもとのソースから変更なし
// isEmpty、ay、pos は選択範囲に応じて更新する必要があるため引数で渡す
function Convert(isEmpty, ay, pos) {
  // 非選択時には自動選択
  if ( isEmpty ) {
    if ( autoSelection == 1 ) {
      s.SelectWord();
      if ( s.GetActivePointY( mePosLogical ) != ay ) {
        s.SetActivePos( pos );
      }
    }
    else if ( autoSelection == 2 || autoSelection == 3 ) {
      var posMode = autoSelection - 1;
      s.SetAnchorPoint( posMode, 1, s.GetActivePointY ( posMode ) );
      s.EndOfLine( true, posMode );
    }
    else if ( autoSelection == 4 ) { s.SelectAll(); }
  }
  var st = s.Text;

  if ( st ) {
    var anc = s.GetAnchorPos(),  act = s.GetActivePos();
    var tp = Math.min( anc, act );
    var tmp;

    // ひらがな → 全角カタカナ変換 「ゔ ゕ ゖ → ヴ ヵ ヶ」含む
    tmp = st.replace( /う[゛゙u\3099]/g, "ヴ" )
            .replace( /[\u3041-\u3096\u309D\u309E]/g, function( chr ) {
             return String.fromCharCode( chr.charCodeAt( 0 ) + 0x60 );
    } );
    // ※ unicode 文字に対応できるときは「ヷ ヸ ヹ ヺ」に変換
    if ( d.Encoding >= 65000 ) {
      tmp = tmp.replace( /ワ[゛゙u\3099]/g, "ヷ" ).replace( /ヰ[゛゙u\3099]/g, "ヸ" )
               .replace( /ヱ[゛゙u\3099]/g, "ヹ" ).replace( /ヲ[゛゙u\3099]/g, "ヺ" );
    }

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

    if ( st != tmp ) {
      // ブックマークを保存
      var bmArray = [];
      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;
      act = s.GetActivePos();

      // ブックマークを復元
      var bmCount = bmArray.length;
      if ( bmCount ) {
        editor.ExecuteCommandByID( 2129 );  // ブックマークをクリア
        for ( var i = 0; i < bmCount; i ++ ) {
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
          editor.ExecuteCommandByID( 2126 );  // ブックマークを設定/解除(設定)
        }
      }
      s.SetActivePos( tp );  s.SetActivePos( act, true );
    }
    else {
      Status = " ひらがな/カタカナ がありません。";
      if ( pos >= 0 ) { s.SetActivePos( pos ); }
    }
  }
}


メモ[編集]

@ Kuro さん

第2版でマルチカーソル/複数選択範囲からの実行と、選択範囲の復帰ができるようになりました。

また、ほかのテキスト操作・変換系マクロも同様にマルチカーソル対応にすることができました。
参考コードをいただき、ありがとうございました。(sukemaru, 2020/06/24 - 2020/07/08)

スポンサーリンク