📝

(C#) native2asciiを.NET Frameworkで実装した。

2024/09/07に公開

ASCIIコードは義務なんです。

国際文字対応してますか?
義務ですよ。🙃
果たしてますか?

概要

まだまだPropertyファイルでASCIIを使っている現場を目の当たりにして。これからも辛酸を舐めそうで、うっかり作ってみた。

課題対策

課題

JDK同梱の native2ascii にはいくつか課題がある。

  • 入手性
    • Java8 までしか native2ascii がない。しかも、OpenJDKだとJava 8は32bitまでしかない。
  • 動作
    • native2asciiでは -reverse オプションでの上書き保存が出来ない。。。
      (リダイレクトは先に出力先をオープンするので、内容を読み出す前に中身が飛ぶ。)
    • EmEditor の ツールから native2ascii を呼び出し、テキストを標準出力で渡す際、一定のサイズを超えると EmEditor がハングする。 (Meryなら大丈夫な謎。)

対策

  • native2asciiを模倣する🤔

Java用ツールを.NETで作るなんてどうかしてるよ!

でも Windows同梱のCSC + MSBuildでなんてワクワクするね!

青果物

環境

  • MSBuild (Windows10同梱)
  • CSC Framework 4 (Windows10同梱)
  • .NET Framework4 (Windows10同梱)

ワクワク!

ソースとバイナリ

https://github.com/libraplanet/Native2AsciiDotNet/

※ MIT License

Native2AsciiDotNet.exe
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
class Program {
  private static int Main(string[] args) {
    bool isReverse = false;
    bool hasError = false;
    Encoding encoding = Encoding.Default;
    string inputFilePath = null;
    string outputFilePath = null;

    for(int i = 0; i < args.Length; i++) {
      string arg = args[i];
      switch(arg) {
        case "-reverse":
          isReverse = true;
          break;
        case "-encoding":
          i += 1;
          if(i < args.Length) {
            try {
              encoding = Encoding.GetEncoding(args[i]);
            } catch(Exception e) {
              Console.Error.WriteLine(e.Message);
              hasError = true;
            }
          } else {
            hasError = true;
            Console.Error.WriteLine("no encoding...");
          }
          break;
        default:
          if(inputFilePath == null) {
            inputFilePath = arg;
          } else if(outputFilePath == null) {
            outputFilePath = arg;
          } else {
            hasError = true;
            Console.Error.WriteLine("too many arguments...");
          }
          break;
      }
    }
    if(hasError) {
      return -1;
    } else {
      String inputText, convertedText;
      if(inputFilePath == null) {
        using(Stream iStream = Console.OpenStandardInput())
        using(StreamReader sReader = new StreamReader(iStream, encoding)) {
          inputText = sReader.ReadToEnd();
        }
      } else {
        using(FileStream fStream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        using(StreamReader sReader = new StreamReader(fStream, encoding)) {
          inputText = sReader.ReadToEnd();
        }
      }

      if(isReverse) {
        convertedText = Regex.Replace(inputText, @"\\u([0-9a-fA-F]{4})",delegate(Match m) {
          int n = Convert.ToInt32(m.Groups[1].Value, 16);
          char c = (char)n;
          return c.ToString();
        });
      } else {
        StringBuilder sb = new StringBuilder();
        foreach(char c in inputText) {
          if(c <= '\u007F') {
            sb.Append(c);
          } else {
            sb.Append(string.Format(@"\u{0:x4}", Convert.ToInt32(c)));
          }
        }
        convertedText = sb.ToString();
      }

      if(outputFilePath == null) {
        using(Stream oStream = Console.OpenStandardOutput())
        using(StreamWriter sWriter = new StreamWriter(oStream, encoding)) {
          sWriter.Write(convertedText);
        }
      } else {
        using(FileStream fStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
        using(StreamWriter sWriter = new StreamWriter(fStream, encoding)) {
          sWriter.Write(convertedText);
        }
      }
      return 0;
    }
  }
}

使い方

command

cmd
Native2AsciiDotNet myfile.txt myfile_ascii.txt
Native2AsciiDotNet -reverse myfile_native.txt myfile_ascii.txt
Native2AsciiDotNet -reverse myfile.txt myfile.txt
Native2AsciiDotNet -encoding UTF-8 myfile.txt
type myfile_ascii.txt | Native2AsciiDotiNet -encoding UTF-8 -reverse > myfile_native.txt

TextEditor

Native2AsciiDotiNetを好きな場所に置いて、そのパスを指定する。エディタ直下もあり。

EmEditor

ìmage.png

Mery

ìmage.png

実行イメージ

image.png

標準入出力ならいつでも相互変換ができるので一番便利。

※ ファイルの場合デフォルトの文字コードによっては化ける可能性があり。ツール設定でUTF-8を指定いているため、エディタのデフォルト文字コードも合わせてUTF-8にしておく必要が微レ存。
(このご時世に、メモ帳のデフォルト文字コードをUNICODEにしていないやつなんて、流石にいないよな!)

Q&A

Q 変数定義場所おかしくない?任意のステートメントで定義できるよ?

C言語村生まれ、Java育ち、final教信者なので。
変数宣言は最初に。スコープは適切にわかりやすく!

Q JREは必要?

CLRが必要。

Q .NET6とかどう?

インストールしてない。

謝辞🙇

Discussion