Skip to content

Instantly share code, notes, and snippets.

@akeit0
Last active August 15, 2024 00:22
Show Gist options
  • Select an option

  • Save akeit0/b6e52358fa47560a2e032fd3653d8076 to your computer and use it in GitHub Desktop.

Select an option

Save akeit0/b6e52358fa47560a2e032fd3653d8076 to your computer and use it in GitHub Desktop.
RomajiReader Windowsの入力はおそらく全対応
//These codes are licensed under CC0.
using System;
using System.Collections.Generic;
//using RomajiReader;
// var reader = Reader.Default;
// Console.WriteLine(reader.Convert("shinkyoku"));//しゅんきょく
// Console.WriteLine(reader.Convert("kappa"));//かっぱ
// Console.WriteLine(reader.Convert("cinkya"));//しんきゃ
// Console.WriteLine(reader.Convert("rweqqap"));//rうぇっくぁp
// Console.WriteLine(reader.Convert("RWEQQAP"));//RうぇっくぁP
// Console.WriteLine(reader.Convert("exxnban"));//えっんばn
// Console.WriteLine(reader.Convert("ddhuxkan"));//っでゅヵn
namespace System.Runtime.CompilerServices
{
public class IsExternalInit
{
}
}
namespace RomajiReader
{
public record RomajiElement(string Romaji, string Hiragana, int ConsumeCount)
{
public bool Match(ReadOnlySpan<char> c, out string hiragana, out int consumeCount)
{
hiragana = "";
consumeCount = 0;
if (c.Length < Romaji.Length)
return false;
var romaji = Romaji.AsSpan();
for (int i = 0; i < romaji.Length; i++)
if (romaji[i] != c[i])
return false;
hiragana = Hiragana;
consumeCount = ConsumeCount;
return true;
}
}
public sealed class Reader(IEnumerable<RomajiElement> elements)
{
readonly List<RomajiElement>[] matchMap = ElementsToMap(elements);
static List<RomajiElement>[] ElementsToMap(IEnumerable<RomajiElement> elements)
{
var map = new List<RomajiElement>[27];
for (int i = 0; i < 27; i++)
{
map[i] = new();
}
foreach (var element in elements)
{
map[element.Romaji[0] - 'a'].Add(element);
}
return map;
}
static IEnumerable<(string Romaji, string Hiragana)> GetSimpleOnes()
{
return
[
new("la", "ぁ"),
new("xa", "ぁ"),
new("a", "あ"),
new("li", "ぃ"),
new("lyi", "ぃ"),
new("xi", "ぃ"),
new("xyi", "ぃ"),
new("i", "い"),
new("yi", "い"),
new("ye", "いぇ"),
new("lu", "ぅ"),
new("xu", "ぅ"),
new("u", "う"),
new("whu", "う"),
new("wu", "う"),
new("wha", "うぁ"),
new("wi", "うぃ"),
new("we", "うぇ"),
new("whe", "うぇ"),
new("who", "うぉ"),
new("le", "ぇ"),
new("lye", "ぇ"),
new("xe", "ぇ"),
new("xye", "ぇ"),
new("e", "え"),
new("lo", "ぉ"),
new("xo", "ぉ"),
new("o", "お"),
new("ka", "か"),
new("ga", "が"),
new("ki", "き"),
new("kyi", "きぃ"),
new("kye", "きぇ"),
new("kya", "きゃ"),
new("kyu", "きゅ"),
new("kyo", "きょ"),
new("gi", "ぎ"),
new("gyi", "ぎぃ"),
new("gye", "ぎぇ"),
new("gya", "ぎゃ"),
new("gyu", "ぎゅ"),
new("gyo", "ぎょ"),
new("cu", "く"),
new("ku", "く"),
new("qu", "く"),
new("kwa", "くぁ"),
new("qa", "くぁ"),
new("qwa", "くぁ"),
new("qi", "くぃ"),
new("qwi", "くぃ"),
new("qyi", "くぃ"),
new("qwu", "くぅ"),
new("qe", "くぇ"),
new("qo", "くぉ"),
new("qya", "くゃ"),
new("qyu", "くゅ"),
new("qyo", "くょ"),
new("gu", "ぐ"),
new("gwa", "ぐぁ"),
new("gwi", "ぐぃ"),
new("gwu", "ぐぅ"),
new("gwe", "ぐぇ"),
new("gwo", "ぐぉ"),
new("ke", "け"),
new("ge", "げ"),
new("co", "こ"),
new("ko", "こ"),
new("go", "ご"),
new("sa", "さ"),
new("za", "ざ"),
new("ci", "し"),
new("shi", "し"),
new("si", "し"),
new("syi", "しぃ"),
new("sha", "しゃ"),
new("sya", "しゃ"),
new("shu", "しゅ"),
new("syu", "しゅ"),
new("she", "しぇ"),
new("sye", "しぇ"),
new("syo", "しょ"),
new("sho", "しょ"),
new("ji", "じ"),
new("zi", "じ"),
new("jyi", "じぃ"),
new("zyi", "じぃ"),
new("je", "じぇ"),
new("jye", "じぇ"),
new("zye", "じぇ"),
new("ja", "じゃ"),
new("jya", "じゃ"),
new("zya", "じゃ"),
new("ju", "じゅ"),
new("jyu", "じゅ"),
new("zyu", "じゅ"),
new("jo", "じょ"),
new("jyo", "じょ"),
new("zyo", "じょ"),
new("su", "す"),
new("swa", "すぁ"),
new("swi", "すぃ"),
new("swu", "すぅ"),
new("swe", "すぇ"),
new("swo", "すぉ"),
new("zu", "ず"),
new("ce", "せ"),
new("se", "せ"),
new("ze", "ぜ"),
new("so", "そ"),
new("zo", "ぞ"),
new("ta", "た"),
new("da", "だ"),
new("chi", "ち"),
new("ti", "ち"),
new("cyi", "ちぃ"),
new("tyi", "ちぃ"),
new("che", "ちぇ"),
new("cye", "ちぇ"),
new("tye", "ちぇ"),
new("cha", "ちゃ"),
new("tya", "ちゃ"),
new("chu", "ちゅ"),
new("cyu", "ちゅ"),
new("tyu", "ちゅ"),
new("cho", "ちょ"),
new("cyo", "ちょ"),
new("tyo", "ちょ"),
new("di", "ぢ"),
new("dyi", "ぢぃ"),
new("dye", "ぢぇ"),
new("dya", "ぢゃ"),
new("dyu", "ぢゅ"),
new("dyo", "ぢょ"),
new("ltsu", "っ"),
new("xtu", "っ"),
new("tsu", "つ"),
new("tu", "つ"),
new("tsa", "つぁ"),
new("tsi", "つぃ"),
new("tse", "つぇ"),
new("tso", "つぉ"),
new("du", "づ"),
new("te", "て"),
new("thi", "てぃ"),
new("the", "てぇ"),
new("tha", "てゃ"),
new("thu", "てゅ"),
new("tho", "てょ"),
new("de", "で"),
new("dhi", "でぃ"),
new("dhe", "でぇ"),
new("dha", "でゃ"),
new("dhu", "でゅ"),
new("dho", "でょ"),
new("to", "と"),
new("twa", "とぁ"),
new("twi", "とぃ"),
new("twu", "とぅ"),
new("twe", "とぇ"),
new("two", "とぉ"),
new("do", "ど"),
new("dwa", "どぁ"),
new("dwi", "どぃ"),
new("dwu", "どぅ"),
new("dwe", "どぇ"),
new("dwo", "どぉ"),
new("na", "な"),
new("ni", "に"),
new("nyi", "にぃ"),
new("nye", "にぇ"),
new("nya", "にゃ"),
new("nyu", "にゅ"),
new("nyo", "にょ"),
new("nu", "ぬ"),
new("ne", "ね"),
new("no", "の"),
new("ha", "は"),
new("ba", "ば"),
new("pa", "ぱ"),
new("hi", "ひ"),
new("hyi", "ひぃ"),
new("hye", "ひぇ"),
new("hya", "ひゃ"),
new("hyu", "ひゅ"),
new("hyo", "ひょ"),
new("bi", "び"),
new("byi", "びぃ"),
new("bye", "びぇ"),
new("bya", "びゃ"),
new("byu", "びゅ"),
new("byo", "びょ"),
new("pi", "ぴ"),
new("pyi", "ぴぃ"),
new("pye", "ぴぇ"),
new("pya", "ぴゃ"),
new("pyu", "ぴゅ"),
new("pyo", "ぴょ"),
new("fu", "ふ"),
new("hu", "ふ"),
new("fa", "ふぁ"),
new("fwa", "ふぁ"),
new("fi", "ふぃ"),
new("fwi", "ふぃ"),
new("fyi", "ふぃ"),
new("fwu", "ふぅ"),
new("fe", "ふぇ"),
new("fo", "ふぉ"),
new("fwo", "ふぉ"),
new("fya", "ふゃ"),
new("fyu", "ふゅ"),
new("fyo", "ふょ"),
new("bu", "ぶ"),
new("pu", "ぷ"),
new("he", "へ"),
new("be", "べ"),
new("pe", "ぺ"),
new("ho", "ほ"),
new("bo", "ぼ"),
new("po", "ぽ"),
new("ma", "ま"),
new("mi", "み"),
new("myi", "みぃ"),
new("mye", "みぇ"),
new("mya", "みゃ"),
new("myu", "みゅ"),
new("myo", "みょ"),
new("mu", "む"),
new("me", "め"),
new("mo", "も"),
new("lya", "ゃ"),
new("xya", "ゃ"),
new("ya", "や"),
new("lyu", "ゅ"),
new("xyu", "ゅ"),
new("yu", "ゆ"),
new("lyo", "ょ"),
new("xyo", "ょ"),
new("yo", "よ"),
new("ra", "ら"),
new("ri", "り"),
new("ryi", "りぃ"),
new("rye", "りぇ"),
new("rya", "りゃ"),
new("ryu", "りゅ"),
new("ryo", "りょ"),
new("ru", "る"),
new("re", "れ"),
new("ro", "ろ"),
new("lwa", "ゎ"),
new("xwa", "ゎ"),
new("wa", "わ"),
new("wyi", "ゐ"),
new("wye", "ゑ"),
new("wo", "を"),
new("nn", "ん"),
new("xn", "ん"),
new("vu", "ヴ"),
new("va", "ヴぁ"),
new("vi", "ヴぃ"),
new("vyi", "ヴぃ"),
new("ve", "ヴぇ"),
new("vye", "ヴぇ"),
new("vo", "ヴぉ"),
new("vya", "ヴゃ"),
new("vyu", "ヴゅ"),
new("vyo", "ヴょ"),
new("lka", "ヵ"),
new("xka", "ヵ"),
new("lke", "ヶ"),
new("xke", "ヶ"),
];
}
static IEnumerable<RomajiElement> DefaultAll()
{
foreach (var (romaji, hiragana) in GetSimpleOnes())
{
yield return new(romaji, hiragana, romaji.Length);
if (romaji[0] is not ('a' or 'i' or 'u' or 'e' or 'o'))
{
if (romaji[0] != 'n' && romaji[0] != 'y')
{
yield return new("n" + romaji, "ん", 1);
}
yield return new(romaji[0] + romaji, "っ" + hiragana, romaji.Length + 1);
}
}
}
public static Reader Default { get; } = new(DefaultAll());
char[] loweredBuffer = new char[128];
char[] rawBuffer = new char[128];
public void Convert(ReadOnlySpan<char> text, List<char> result)
{
var count = 0;
result.Clear();
foreach (var c in text)
{
if (count >= loweredBuffer.Length)
{
Array.Resize(ref loweredBuffer, loweredBuffer.Length * 2);
Array.Resize(ref rawBuffer, rawBuffer.Length * 2);
}
//大文字と小文字はunicodeで差が32
loweredBuffer[count] = (c is >= 'A' and <= 'Z')? (char)(c + 32) : c;
rawBuffer[count] = c;
count++;
}
var remainCount = count;
while (0 < remainCount)
{
var start = count - remainCount;
var firstChar = loweredBuffer[start];
if (firstChar is >= 'a' and <= 'z')
{
foreach (var element in matchMap[firstChar - 'a'])
{
if (element.Match(loweredBuffer.AsSpan(start, remainCount), out var hiragana, out var consumeCount))
{
foreach (var c in hiragana)
{
result.Add(c);
}
remainCount -= consumeCount;
break;
}
}
}
if (remainCount == 0) return;
if ((start + remainCount) != count) continue;
result.Add(rawBuffer[start]);
remainCount--;
}
}
readonly List<char> resultCache = new();
public string Convert(ReadOnlySpan<char> text)
{
var result = resultCache;
result.Clear();
Convert(text, result);
return string.Create(result.Count, result, (span, list) =>
{
for (int i = 0; i < span.Length; i++)
{
span[i] = list[i];
}
list.Clear();
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment