Excelの列名のようなアルファベットと数値を相互変換するメソッド
AtCoderのABC171を解いていて、もっと分かりやすい書き方があるなと思ったので修正しました (2020/6/28)。
/// <summary>
/// アルファベットを返す。
/// 例えば、引数が1の時はA、2の時はB、27の時はAAとなる。
/// 引数が不正な場合は<see cref="string.Empty"/>を返す。
/// </summary>
/// <param name="index">インデックス。1以上の値が有効</param>
/// <returns>アルファベット</returns>
public static string ToAlphabet(int index)
{
string alphabet = string.Empty;
if (index < 1) return alphabet;
while(index > 0)
{
// A-Zの変換を0-25にするため1を引く
index--;
// ASCIIではAは10進数で65
alphabet = Convert.ToChar(index % 26 + 65) + alphabet;
index = index / 26;
}
return alphabet;
}
/// <summary>
/// AからZのインデックスを返す。
/// 例えば、引数がAの時は1、Bの時は2、AAの時は27となる。
/// 引数が不正な場合は-1を返す。
/// </summary>
/// <param name="name">アルファベット。半角大文字のみ有効</param>
/// <returns>インデックス</returns>
public static int ToAlphabetIndex(string alphabet)
{
if (string.IsNullOrEmpty(alphabet))
{
return -1;
}
if (new Regex("^[A-Z]+$").IsMatch(alphabet))
{
int index = 0;
for (int i = 0; i < alphabet.Length; i++)
{
// ASCIIではAは10進数で65
int num = Convert.ToChar(alphabet[alphabet.Length - i - 1]) - 65;
// A-Zの変換が0-25になっているため1を足して、A-Zが1-26になるようにする
num++;
index += (int)(num * Math.Pow(26, i));
}
return index;
}
return -1;
}
Excelの列名変換のようなアルファベットを数値から取得したり、アルファベットから数値に変換できるようにしたかったため作成しました。
/// <summary>
/// アルファベットを返す。
/// 例えば、引数が1の時はA、2の時はB、27の時はAAとなる。
/// 引数が不正な場合は<see cref="string.Empty"/>を返す。
/// </summary>
/// <param name="index">インデックス。1以上の値が有効</param>
/// <returns>アルファベット</returns>
public static string ToAlphabet(int index)
{
string alphabet = string.Empty;
if (index < 1) return alphabet;
index--;
do
{
alphabet = Convert.ToChar(index % 26 + 0x41) + alphabet;
}
while
((index = index / 26 - 1) != -1);
return alphabet;
}
/// <summary>
/// AからZのインデックスを返す。
/// 例えば、引数がAの時は1、Bの時は2、AAの時は27となる。
/// 引数が不正な場合は-1を返す。
/// </summary>
/// <param name="name">アルファベット。半角大文字のみ有効</param>
/// <returns>インデックス</returns>
public static int ToAlphabetIndex(string alphabet)
{
if (string.IsNullOrEmpty(alphabet))
{
return -1;
}
if (new Regex("^[A-Z]+$").IsMatch(alphabet))
{
int index = 0;
for (int i = 0; i < alphabet.Length; i++)
{
int num = Convert.ToChar(alphabet[alphabet.Length - i - 1]) - 64;
index += (int)(num * Math.Pow(26, i));
}
return index;
}
return -1;
}
@albireo さんより、拡張メソッドの方が使いやすいとのコメントをいただきましたので拡張メソッドバージョンも載せておきます。(2020/4/26 追記)
/// <summary>
/// アルファベットを返す。
/// 例えば、引数が1の時はA、2の時はB、27の時はAAとなる。
/// 引数が不正な場合は<see cref="string.Empty"/>を返す。
/// </summary>
/// <param name="index">インデックス。1以上の値が有効</param>
/// <returns>アルファベット</returns>
public static string ToAlphabet(this int index)
{
string alphabet = string.Empty;
if (index < 1) return alphabet;
index--;
do
{
alphabet = Convert.ToChar(index % 26 + 0x41) + alphabet;
}
while
((index = index / 26 - 1) != -1);
return alphabet;
}
/// <summary>
/// AからZのインデックスを返す。
/// 例えば、引数がAの時は1、Bの時は2、AAの時は27となる。
/// 引数が不正な場合は-1を返す。
/// </summary>
/// <param name="name">アルファベット。半角大文字のみ有効</param>
/// <returns>インデックス</returns>
public static int ToAlphabetIndex(this string alphabet)
{
if (string.IsNullOrEmpty(alphabet))
{
return -1;
}
if (new Regex("^[A-Z]+$").IsMatch(alphabet))
{
int index = 0;
for (int i = 0; i < alphabet.Length; i++)
{
int num = Convert.ToChar(alphabet[alphabet.Length - i - 1]) - 64;
index += (int)(num * Math.Pow(26, i));
}
return index;
}
return -1;
}
参考
https://memo-c-sharp.blogspot.com/2015/09/excel.html
http://devlabo.blogspot.com/2009/04/c.html