10月 142017
タイトルの通り、キャメルケースの分割(split)をします。実装はC#。
正規表現で頑張る方法もあるようですが、ちょっとややこしいのとパフォーマンス的に嬉しくないことは容易に想像できるので、愚直な方法で実装します。
厳密なキャメルケースであれば、IDのような単語は、idやIdとなると思いますが、そのままIDと書くこともあるため、そのパターンにも対応します。スネークケースとの混用も対応します。先頭と末尾のアンダースコアは無視します。
例えば、_abcFOOBar123_456hoge__HOGE_
ならばabc
、FOO
、Bar
、123
、456
、hoge
、HOGE
に分割します。
実装
識別子として有効な文字種は、アルファベット大/小、数字、アンダースコアに限られるとして、これら文字種をenumで定義します。charの拡張メソッドで文字種判定を実装し、キャメルケース分割はstringの拡張メソッドとして実装します。
文字種判定はIsDigit()やIsUpper()、IsLower()が標準機能としてあるものの、ここではASCIIだけ見たいのにUnicodeでチェックされるのがイマイチなので自作処理で判定します。
想定外の文字が入力された時の動作は不定です。デバッグ時はとりあえずアサートにかかるようにしました(Unityのアサートなので都合悪ければいいように置き換えてください)。
public static class CharExtension
{
public static bool isNumber(this char c)
{
return '0' <= c && c <= '9';
}
public static bool isAlphabet(this char c)
{
return isLowerAlphabet(c) || isUpperAlphabet(c);
}
public static bool isLowerAlphabet(this char c)
{
return 'a' <= c && c <= 'z';
}
public static bool isUpperAlphabet(this char c)
{
return 'A' <= c && c <= 'Z';
}
}
public static class StringExtension
{
private enum IdCharType
{
Invalid,
LowerAlphabet,
UpperAlphabet,
Number,
Underscore,
}
public static List<string> splitCamelCase(this string str)
{
var length = str.Length;
var texts = new List<string>();
var last = IdCharType.Invalid;
var start = 0;
bool upperSequence = false;
for(var i = 0; i < length; ++i) {
var c = str[i];
var current = c.toCharType();
Assert.IsTrue(current != IdCharType.Invalid, "Invalid character.");
if(i == 0) {
last = current;
continue;
}
if(last == IdCharType.UpperAlphabet) {
if(current == IdCharType.UpperAlphabet) {
upperSequence = true;
continue;
}
if(upperSequence) {
upperSequence = false;
if(current == IdCharType.Underscore) {
texts.Add(str.Substring(start, i - start));
start = i;
}
else {
texts.Add(str.Substring(start, i - start - 1));
start = i - 1;
}
last = current;
continue;
}
if(current == IdCharType.LowerAlphabet) {
last = current;
continue;
}
}
upperSequence = false;
if(last == IdCharType.Underscore) {
start = i;
last = current;
continue;
}
if(last != current) {
texts.Add(str.Substring(start, i - start));
start = i;
}
last = current;
}
if(start < length && last != IdCharType.Underscore) {
texts.Add(str.Substring(start, length - start));
}
return texts;
}
private static IdCharType toCharType(this char c)
{
if(c.isLowerAlphabet()) return IdCharType.LowerAlphabet;
if(c.isUpperAlphabet()) return IdCharType.UpperAlphabet;
if(c.isNumber()) return IdCharType.Number;
if(c == '_') return IdCharType.Underscore;
return IdCharType.Invalid;
}
}