template Encoding(string fname) { mixin("invariant wchar encToU[256] = " ~ mkEncToU(import(fname)) ~ ";"); mixin("char[wchar] UToEnc;"); static this() { mixin("UToEnc = " ~ mkUToEnc(import(fname)) ~ ";"); } wchar[] toU(const char[] s) { // newer versions of D would be better off using std.algorithm.map wchar[] ret = new wchar[s.length]; foreach(i, char c; s) ret[i] = encToU[c]; return ret; } char[] fromU(const wchar[] s) { char[] ret = new char[s.length]; foreach(i, wchar c; s) { auto m = c in UToEnc; if (m) ret[i] = *m; else throw new Exception("Character has no equivalent in this encoding."); } return ret; } } private string mkEncToU(string text) { string ret = "["; foreach(line; split(text, "\n\r")) { auto parts = split(line, "#"); if (parts.length == 0) continue; auto mapping = split(parts[0], " \t"); if (mapping.length < 1 || mapping[0] == "") continue; if (mapping.length < 2) mapping ~= "0"; // TODO: undefined characters! ret ~= mapping[1] ~ ","; } return ret ~ "]"; } private string mkUToEnc(string text) { string ret = "["; foreach(line; split(text, "\n\r")) { auto parts = split(line, "#"); if (parts.length == 0) continue; auto mapping = split(parts[0], " \t"); if (mapping.length < 2 || mapping[0] == "" || mapping[1] == "") continue; ret ~= mapping[1] ~ ": " ~ mapping[0] ~ ","; } return ret[0..$-1] ~ "]"; } private string[] split(string text, string sep = " ", bool compactSep = true) { int nl, st; string[] ret; while (nl < text.length) { while (nl < text.length && !anySep(text[nl], sep)) nl++; ret ~= text[st..nl]; if (compactSep) while (nl+1 < text.length && anySep(text[nl+1], sep)) nl++; nl = st = nl+1; } return ret; } private bool anySep(char c, string sep) { foreach(m; sep) if (c == m) return true; return false; }