📝
(C#) native2asciiを.NET Frameworkで実装した。
ASCIIコードは義務なんです。
国際文字対応してますか?
義務ですよ。🙃
果たしてますか?
概要
まだまだPropertyファイルでASCIIを使っている現場を目の当たりにして。これからも辛酸を舐めそうで、うっかり作ってみた。
課題対策
課題
JDK同梱の native2ascii にはいくつか課題がある。
- 入手性
- Java8 までしか native2ascii がない。しかも、OpenJDKだとJava 8は32bitまでしかない。
- 動作
- native2asciiでは
-reverse
オプションでの上書き保存が出来ない。。。
(リダイレクトは先に出力先をオープンするので、内容を読み出す前に中身が飛ぶ。) - EmEditor の ツールから native2ascii を呼び出し、テキストを標準出力で渡す際、一定のサイズを超えると EmEditor がハングする。 (Meryなら大丈夫な謎。)
- native2asciiでは
対策
- native2asciiを模倣する🤔
Java用ツールを.NETで作るなんてどうかしてるよ!
でも Windows同梱のCSC + MSBuildでなんてワクワクするね!
青果物
環境
- MSBuild (Windows10同梱)
- CSC Framework 4 (Windows10同梱)
- .NET Framework4 (Windows10同梱)
ワクワク!
ソースとバイナリ
※ 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
Mery
実行イメージ
標準入出力ならいつでも相互変換ができるので一番便利。
※ ファイルの場合デフォルトの文字コードによっては化ける可能性があり。ツール設定でUTF-8を指定いているため、エディタのデフォルト文字コードも合わせてUTF-8にしておく必要が微レ存。
(このご時世に、メモ帳のデフォルト文字コードをUNICODEにしていないやつなんて、流石にいないよな!)
Q&A
Q 変数定義場所おかしくない?任意のステートメントで定義できるよ?
C言語村生まれ、Java育ち、final教信者なので。
変数宣言は最初に。スコープは適切にわかりやすく!
Q JREは必要?
CLRが必要。
Q .NET6とかどう?
インストールしてない。
謝辞🙇
- EmEditor
https://jp.emeditor.com/ - Mery
https://www.haijin-boys.com/wiki/メインページ - native2ascii
https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/native2ascii.html - C#正規表現で文字をReplaceする3つの方法と使い分け
https://chishiki21.blogspot.com/2021/11/Regex-Replace-Match-Result.html#2-個々のmatch結果を見たり処理したいときの使い方
Discussion