Как преобразовать номер столбца (например. 127) в столбец excel (например. ЗЕНИТНЫЙ)
Как преобразовать числовое число в имя столбца Excel в C# без использования автоматизации получения значения непосредственно из Excel.
Excel 2007 имеет возможный диапазон от 1 до 16384, то есть количество столбцов, которые он поддерживает. Полученные значения должны быть в виде имен столбцов excel, например A, AA, AAA и т. д.
30 ответов:
вот как я делаю это:
private string GetExcelColumnName(int columnNumber) { int dividend = columnNumber; string columnName = String.Empty; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; columnName = Convert.ToChar(65 + modulo).ToString() + columnName; dividend = (int)((dividend - modulo) / 26); } return columnName; }
Если кто-то должен сделать это в Excel без VBA, вот так:
=SUBSTITUTE(ADDRESS(1;colNum;4);"1";"")
где colNum-номер столбца
и в VBA:
Function GetColumnName(colNum As Integer) As String Dim d As Integer Dim m As Integer Dim name As String d = colNum name = "" Do While (d > 0) m = (d - 1) Mod 26 name = Chr(65 + m) + name d = Int((d - m) / 26) Loop GetColumnName = name End Function
извините, это Python вместо C#, но по крайней мере результаты верны:
def ColIdxToXlName(idx): if idx < 1: raise ValueError("Index is too small") result = "" while True: if idx > 26: idx, r = divmod(idx - 1, 26) result = chr(r + ord('A')) + result else: return chr(idx + ord('A') - 1) + result for i in xrange(1, 1024): print "%4d : %s" % (i, ColIdxToXlName(i))
вам может понадобиться преобразование в обоих направлениях, например, из адреса столбца Excel, такого как AAZ, в целое число и из любого целого числа в Excel. Два метода ниже будут делать именно это. Предполагается, что индексирование на основе 1, Первый элемент в ваших "массивах" - это элемент номер 1. Здесь нет ограничений по размеру, поэтому вы можете использовать адреса, такие как ошибка, и это будет номер столбца 2613824 ...
public static string ColumnAdress(int col) { if (col <= 26) { return Convert.ToChar(col + 64).ToString(); } int div = col / 26; int mod = col % 26; if (mod == 0) {mod = 26;div--;} return ColumnAdress(div) + ColumnAdress(mod); } public static int ColumnNumber(string colAdress) { int[] digits = new int[colAdress.Length]; for (int i = 0; i < colAdress.Length; ++i) { digits[i] = Convert.ToInt32(colAdress[i]) - 64; } int mul=1;int res=0; for (int pos = digits.Length - 1; pos >= 0; --pos) { res += digits[pos] * mul; mul *= 26; } return res; }
я обнаружил ошибку в моем первом посте, поэтому я решила сесть и сделать математику. Я обнаружил, что система счисления, используемая для идентификации столбцов Excel, не является базовой системой 26, Как написал другой человек. Рассмотрим следующее в базе 10. Вы также можете сделать это с буквами алфавита.
космос:.........................S1, S2, S3: S1, S2, S3
....................................0, 00, 000 :.. А, АА, ААА
....................................Один, 01, 001 :.. B, AB, AAB
.................................... ... , ...,...:.. ... ,...,...
....................................9, 99, 999 :.. З ЗЗ ЗЗЗ
Всего государств в космосе: 10, 100, 1000 : 26, 676, 17576
Всего Состояний:...............1110................18278Excel нумерует столбцы в отдельных алфавитных пробелах с помощью базы 26. Вы можете видеть, что в общем случае прогрессия пространства состояний равна a, a^2, A^3, ... для некоторого основания a и общего числа Штаты а + а^2 + а^3 + ... .
Предположим, вы хотите найти общее число состояний A в первых n пространствах. Формула для этого является a = (a) (a^N - 1) /(a-1). Это важно, потому что нам нужно найти пространство N, соответствующее нашему индексу K. Если я хочу узнать, где K лежит в системе счисления, мне нужно заменить A на K и решить для N. решение N = log{base a} (A (a-1)/a +1). Если я использую пример a = 10 и K = 192, я знаю, что N = 2.23804... . Этот говорит мне, что K лежит в начале третьего пространства, так как оно немного больше двух.
код C#, использующий базовый индекс нуля, равен
private string ExcelColumnIndexToName(int Index) { string range = string.Empty; if (Index < 0 ) return range; int a = 26; int x = (int)Math.Floor(Math.Log((Index) * (a - 1) / a + 1, a)); Index -= (int)(Math.Pow(a, x) - 1) * a / (a - 1); for (int i = x+1; Index + i > 0; i--) { range = ((char)(65 + Index % a)).ToString() + range; Index /= a; } return range; }
//Старый Пост
решение на основе нуля в C#.
private string ExcelColumnIndexToName(int Index) { string range = ""; if (Index < 0 ) return range; for(int i=1;Index + i > 0;i=0) { range = ((char)(65 + Index % 26)).ToString() + range; Index /= 26; } if (range.Length > 1) range = ((char)((int)range[0] - 1)).ToString() + range.Substring(1); return range; }
int nCol = 127; string sChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; string sCol = ""; while (nCol >= 26) { int nChar = nCol % 26; nCol = (nCol - nChar) / 26; // You could do some trick with using nChar as offset from 'A', but I am lazy to do it right now. sCol = sChars[nChar] + sCol; } sCol = sChars[nCol] + sCol;
обновление:Петркомментарий прав. Вот что я получаю за написание кода в браузере. :- ) Мое решение не компилировалось, в нем отсутствовала самая левая буква, и он строил строку в обратном порядке-все теперь исправлено.
ошибки в сторону, алгоритм в основном преобразует число из базы 10 в базу 26.
обновление 2:Joel Coehoorn правильно-приведенный выше код вернет AB для 27. Если бы это было реальное базовое число 26, AA было бы равно A, а следующее число после Z было бы BA.
int nCol = 127; string sChars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"; string sCol = ""; while (nCol > 26) { int nChar = nCol % 26; if (nChar == 0) nChar = 26; nCol = (nCol - nChar) / 26; sCol = sChars[nChar] + sCol; } if (nCol != 0) sCol = sChars[nCol] + sCol;
легко с помощью рекурсии.
public static string GetStandardExcelColumnName(int columnNumberOneBased) { int baseValue = Convert.ToInt32('A'); int columnNumberZeroBased = columnNumberOneBased - 1; string ret = ""; if (columnNumberOneBased > 26) { ret = GetStandardExcelColumnName(columnNumberZeroBased / 26) ; } return ret + Convert.ToChar(baseValue + (columnNumberZeroBased % 26) ); }
этот ответ находится в javaScript:
function getCharFromNumber(columnNumber){ var dividend = columnNumber; var columnName = ""; var modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; columnName = String.fromCharCode(65 + modulo).toString() + columnName; dividend = parseInt((dividend - modulo) / 26); } return columnName; }
Я удивлен, что все решения до сих пор содержат либо итерацию, либо рекурсию.
вот мое решение, которое работает в постоянное время (без циклов). Это решение работает для всех возможных столбцов Excel и проверок, которые могут быть превращены в столбец Excel. Возможные столбцы находятся в диапазоне [A, XFD] или [1, 16384]. (Это зависит от вашей версии Excel)
private static string Turn(uint col) { if (col < 1 || col > 16384) //Excel columns are one-based (one = 'A') throw new ArgumentException("col must be >= 1 and <= 16384"); if (col <= 26) //one character return ((char)(col + 'A' - 1)).ToString(); else if (col <= 702) //two characters { char firstChar = (char)((int)((col - 1) / 26) + 'A' - 1); char secondChar = (char)(col % 26 + 'A' - 1); if (secondChar == '@') //Excel is one-based, but modulo operations are zero-based secondChar = 'Z'; //convert one-based to zero-based return string.Format("{0}{1}", firstChar, secondChar); } else //three characters { char firstChar = (char)((int)((col - 1) / 702) + 'A' - 1); char secondChar = (char)((col - 1) / 26 % 26 + 'A' - 1); char thirdChar = (char)(col % 26 + 'A' - 1); if (thirdChar == '@') //Excel is one-based, but modulo operations are zero-based thirdChar = 'Z'; //convert one-based to zero-based return string.Format("{0}{1}{2}", firstChar, secondChar, thirdChar); } }
..И преобразуется в PHP:
function GetExcelColumnName($columnNumber) { $columnName = ''; while ($columnNumber > 0) { $modulo = ($columnNumber - 1) % 26; $columnName = chr(65 + $modulo) . $columnName; $columnNumber = (int)(($columnNumber - $modulo) / 26); } return $columnName; }
та же реализация в Java
public String getExcelColumnName (int columnNumber) { int dividend = columnNumber; int i; String columnName = ""; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; i = 65 + modulo; columnName = new Character((char)i).toString() + columnName; dividend = (int)((dividend - modulo) / 26); } return columnName; }
после просмотра всех представленных здесь версий, я решил сделать один сам, используя рекурсию.
вот мой vb.net версия:
Function CL(ByVal x As Integer) As String If x >= 1 And x <= 26 Then CL = Chr(x + 64) Else CL = CL((x - x Mod 26) / 26) & Chr((x Mod 26) + 1 + 64) End If End Function
немного поздно для игры, но вот код, который я использую (в C#):
private static readonly string _Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public static int ColumnNameParse(string value) { // assumes value.Length is [1,3] // assumes value is uppercase var digits = value.PadLeft(3).Select(x => _Alphabet.IndexOf(x)); return digits.Aggregate(0, (current, index) => (current * 26) + (index + 1)); }
просто бросая простую двухстрочную реализацию C# с использованием рекурсии, потому что все ответы здесь кажутся гораздо более сложными, чем это необходимо.
/// <summary> /// Gets the column letter(s) corresponding to the given column number. /// </summary> /// <param name="column">The one-based column index. Must be greater than zero.</param> /// <returns>The desired column letter, or an empty string if the column number was invalid.</returns> public static string GetColumnLetter(int column) { if (column < 1) return String.Empty; return GetColumnLetter((column - 1) / 26) + (char)('A' + (column - 1) % 26); }
Если вы просто хотите его для Формулы ячейки без кода, вот формула для него:
IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
В Delphi (Паскаль):
function GetExcelColumnName(columnNumber: integer): string; var dividend, modulo: integer; begin Result := ''; dividend := columnNumber; while dividend > 0 do begin modulo := (dividend - 1) mod 26; Result := Chr(65 + modulo) + Result; dividend := (dividend - modulo) div 26; end; end;
Я хотел добавить свой статический класс, который я использую, для взаимодействия между индексом col и меткой col. Я использую измененный принятый ответ для моего метода ColumnLabel
public static class Extensions { public static string ColumnLabel(this int col) { var dividend = col; var columnLabel = string.Empty; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; columnLabel = Convert.ToChar(65 + modulo).ToString() + columnLabel; dividend = (int)((dividend - modulo) / 26); } return columnLabel; } public static int ColumnIndex(this string colLabel) { // "AD" (1 * 26^1) + (4 * 26^0) ... var colIndex = 0; for(int ind = 0, pow = colLabel.Count()-1; ind < colLabel.Count(); ++ind, --pow) { var cVal = Convert.ToInt32(colLabel[ind]) - 64; //col A is index 1 colIndex += cVal * ((int)Math.Pow(26, pow)); } return colIndex; } }
использовать это как...
30.ColumnLabel(); // "AD" "AD".ColumnIndex(); // 30
private String getColumn(int c) { String s = ""; do { s = (char)('A' + (c % 26)) + s; c /= 26; } while (c-- > 0); return s; }
его не совсем база 26, Нет 0 в системе. Если там был, 'з' состоится 'БА' не 'АА'.
уточнение исходного решения (в C#):
public static class ExcelHelper { private static Dictionary<UInt16, String> l_DictionaryOfColumns; public static ExcelHelper() { l_DictionaryOfColumns = new Dictionary<ushort, string>(256); } public static String GetExcelColumnName(UInt16 l_Column) { UInt16 l_ColumnCopy = l_Column; String l_Chars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String l_rVal = ""; UInt16 l_Char; if (l_DictionaryOfColumns.ContainsKey(l_Column) == true) { l_rVal = l_DictionaryOfColumns[l_Column]; } else { while (l_ColumnCopy > 26) { l_Char = l_ColumnCopy % 26; if (l_Char == 0) l_Char = 26; l_ColumnCopy = (l_ColumnCopy - l_Char) / 26; l_rVal = l_Chars[l_Char] + l_rVal; } if (l_ColumnCopy != 0) l_rVal = l_Chars[l_ColumnCopy] + l_rVal; l_DictionaryOfColumns.ContainsKey(l_Column) = l_rVal; } return l_rVal; } }
вот версия Actionscript:
private var columnNumbers:Array = ['A', 'B', 'C', 'D', 'E', 'F' , 'G', 'H', 'I', 'J', 'K' ,'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']; private function getExcelColumnName(columnNumber:int) : String{ var dividend:int = columnNumber; var columnName:String = ""; var modulo:int; while (dividend > 0) { modulo = (dividend - 1) % 26; columnName = columnNumbers[modulo] + columnName; dividend = int((dividend - modulo) / 26); } return columnName; }
На JavaScript Решение
/** * Calculate the column letter abbreviation from a 1 based index * @param {Number} value * @returns {string} */ getColumnFromIndex = function (value) { var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); var remainder, result = ""; do { remainder = value % 26; result = base[(remainder || 26) - 1] + result; value = Math.floor(value / 26); } while (value > 0); return result; };
в perl, для входного сигнала 1 (A), 27 (AA), etc.
sub excel_colname { my ($idx) = @_; # one-based column number --$idx; # zero-based column index my $name = ""; while ($idx >= 0) { $name .= chr(ord("A") + ($idx % 26)); $idx = int($idx / 26) - 1; } return scalar reverse $name; }
вот моя супер поздняя реализация в PHP. Это один рекурсивный. Я написал его как раз перед тем, как нашел этот пост. Я хотел посмотреть, если другие уже решили эту проблему...
public function GetColumn($intNumber, $strCol = null) { if ($intNumber > 0) { $intRem = ($intNumber - 1) % 26; $strCol = $this->GetColumn(intval(($intNumber - $intRem) / 26), sprintf('%s%s', chr(65 + $intRem), $strCol)); } return $strCol; }
Я пытаюсь сделать то же самое в Java... Я написал следующий код:
private String getExcelColumnName(int columnNumber) { int dividend = columnNumber; String columnName = ""; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; char val = Character.valueOf((char)(65 + modulo)); columnName += val; dividend = (int)((dividend - modulo) / 26); } return columnName; }
теперь, как только я запустил его с columnNumber = 29, он дает мне результат = " CA "(вместо " AC") любые комментарии, что я упускаю? Я знаю, что могу отменить его с помощью StringBuilder.... Но, глядя на ответ Грэма, я немного смущен....
другой способ VBA
Public Function GetColumnName(TargetCell As Range) As String GetColumnName = Split(CStr(TargetCell.Address), "$")(1) End Function
эти мои коды для преобразования определенного числа (индекс начинается с 1) в столбец Excel.
public static string NumberToExcelColumn(uint number) { uint originalNumber = number; uint numChars = 1; while (Math.Pow(26, numChars) < number) { numChars++; if (Math.Pow(26, numChars) + 26 >= number) { break; } } string toRet = ""; uint lastValue = 0; do { number -= lastValue; double powerVal = Math.Pow(26, numChars - 1); byte thisCharIdx = (byte)Math.Truncate((columnNumber - 1) / powerVal); lastValue = (int)powerVal * thisCharIdx; if (numChars - 2 >= 0) { double powerVal_next = Math.Pow(26, numChars - 2); byte thisCharIdx_next = (byte)Math.Truncate((columnNumber - lastValue - 1) / powerVal_next); int lastValue_next = (int)Math.Pow(26, numChars - 2) * thisCharIdx_next; if (thisCharIdx_next == 0 && lastValue_next == 0 && powerVal_next == 26) { thisCharIdx--; lastValue = (int)powerVal * thisCharIdx; } } toRet += (char)((byte)'A' + thisCharIdx + ((numChars > 1) ? -1 : 0)); numChars--; } while (numChars > 0); return toRet; }
Мой Модульный Тест:
[TestMethod] public void Test() { Assert.AreEqual("A", NumberToExcelColumn(1)); Assert.AreEqual("Z", NumberToExcelColumn(26)); Assert.AreEqual("AA", NumberToExcelColumn(27)); Assert.AreEqual("AO", NumberToExcelColumn(41)); Assert.AreEqual("AZ", NumberToExcelColumn(52)); Assert.AreEqual("BA", NumberToExcelColumn(53)); Assert.AreEqual("ZZ", NumberToExcelColumn(702)); Assert.AreEqual("AAA", NumberToExcelColumn(703)); Assert.AreEqual("ABC", NumberToExcelColumn(731)); Assert.AreEqual("ACQ", NumberToExcelColumn(771)); Assert.AreEqual("AYZ", NumberToExcelColumn(1352)); Assert.AreEqual("AZA", NumberToExcelColumn(1353)); Assert.AreEqual("AZB", NumberToExcelColumn(1354)); Assert.AreEqual("BAA", NumberToExcelColumn(1379)); Assert.AreEqual("CNU", NumberToExcelColumn(2413)); Assert.AreEqual("GCM", NumberToExcelColumn(4823)); Assert.AreEqual("MSR", NumberToExcelColumn(9300)); Assert.AreEqual("OMB", NumberToExcelColumn(10480)); Assert.AreEqual("ULV", NumberToExcelColumn(14530)); Assert.AreEqual("XFD", NumberToExcelColumn(16384)); }
извините, это Python вместо C#, но по крайней мере результаты верны:
def excel_column_number_to_name(column_number): output = "" index = column_number-1 while index >= 0: character = chr((index%26)+ord('A')) output = output + character index = index/26 - 1 return output[::-1] for i in xrange(1, 1024): print "%4d : %s" % (i, excel_column_number_to_name(i))
прошли эти тестовые случаи:
- номер столбца: 494286 = > ABCDZ
- номер столбца: 27 = > AA
- номер столбца: 52 = > AZ
Я использую этот в VB.NET 2003 и он работает хорошо...
Private Function GetExcelColumnName(ByVal aiColNumber As Integer) As String Dim BaseValue As Integer = Convert.ToInt32(("A").Chars(0)) - 1 Dim lsReturn As String = String.Empty If (aiColNumber > 26) Then lsReturn = GetExcelColumnName(Convert.ToInt32((Format(aiColNumber / 26, "0.0").Split("."))(0))) End If GetExcelColumnName = lsReturn + Convert.ToChar(BaseValue + (aiColNumber Mod 26)) End Function
другое решение:
private void Foo() { l_ExcelApp = new Excel.ApplicationClass(); l_ExcelApp.ReferenceStyle = Excel.XlReferenceStyle.xlR1C1; // ... now reference by R[row]C[column], Ex. A1 <==> R1C1, C6 <==> R3C6, ... }
посмотреть подробнее здесь - ссылки на ячейки в Excel для всех! доктор Нитин семинара принял участие заместитель
public static string ConvertToAlphaColumnReferenceFromInteger(int columnReference) { int baseValue = ((int)('A')) - 1 ; string lsReturn = String.Empty; if (columnReference > 26) { lsReturn = ConvertToAlphaColumnReferenceFromInteger(Convert.ToInt32(Convert.ToDouble(columnReference / 26).ToString().Split('.')[0])); } return lsReturn + Convert.ToChar(baseValue + (columnReference % 26)); }