Wie konvertiert man eine numerische Zahl in einen Excel-Spaltennamen in C #, ohne dass die Automatisierung den Wert direkt aus Excel bezieht.
Excel 2007 hat einen möglichen Bereich von 1 bis 16384, also der Anzahl der unterstützten Spalten. Die resultierenden Werte sollten in Form von Excel-Spaltennamen sein, z. A, AA, AAA usw.
So mache ich es:
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;
}
Wenn dies in Excel ohne VBA erforderlich ist, können Sie Folgendes tun:
=SUBSTITUTE(ADDRESS(1;colNum;4);"1";"")
dabei steht colNum für die Spaltennummer
Und in 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
Sorry, das ist Python statt C #, aber zumindest sind die Ergebnisse korrekt
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))
Möglicherweise müssen Sie beide Arten konvertieren, z. B. von einer Excel-Spaltenadresse wie AAZ in eine Ganzzahl und von einer beliebigen Ganzzahl in Excel. Die beiden folgenden Methoden werden genau das tun. Angenommen, die 1-basierte Indizierung, das erste Element in Ihren "Arrays" ist die Elementnummer 1 . Hier gibt es keine Größenbeschränkung. Daher können Sie Adressen wie ERROR verwenden. Das wäre die Spaltennummer 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;
}
In meinem ersten Beitrag habe ich einen Fehler entdeckt, also habe ich mich entschieden, mich hinzusetzen und die Mathematik zu machen. Was ich fand, ist, dass das Zahlensystem, das zum Identifizieren von Excel-Spalten verwendet wird, kein Basis-26-System ist, wie es von einer anderen Person gepostet wurde. Betrachten Sie Folgendes in Basis 10. Sie können dies auch mit den Buchstaben des Alphabets tun.
Leerzeichen: ......................... S1, S2, S3: S1, S2, S3
.................................... 0, 00, 000: .. A, AA AAA
.................................... 1, 01, 001: .. B, AB AAB
....................................…,…,…:……,… ,…
.................................... 9, 99, 999: .. Z, ZZ ZZZ
Gesamtzustände im Raum: 10, 100, 1000: 26, 676, 17576
Staaten insgesamt: ............... 1110 ................ 18278
Excel nummeriert die Spalten in den einzelnen alphabetischen Räumen anhand der Basis 26. Sie können sehen, dass die Zustandsraumprogression im Allgemeinen a, a ^ 2, a ^ 3,… für einige Basis a ist und die Gesamtzahl der Zustände a + a ist ^ 2 + a ^ 3 +….
Angenommen, Sie möchten die Gesamtzahl der Zustände A in den ersten N Leerzeichen ermitteln. Die Formel dafür ist A = (a) (a ^ N - 1)/(a-1). Dies ist wichtig, weil wir den Raum N suchen müssen, der unserem Index K entspricht. Wenn ich herausfinden möchte, wo K im Zahlensystem liegt, muss ich A durch K ersetzen und nach N suchen. Die Lösung ist N = log { Basis a} (A (a-1)/a + 1). Wenn ich das Beispiel von a = 10 und K = 192 verwende, weiß ich, dass N = 2.23804…. Dies sagt mir, dass K am Anfang des dritten Feldes liegt, da es etwas größer als zwei ist.
Der nächste Schritt besteht darin, herauszufinden, wie weit wir uns im aktuellen Bereich befinden. Um dies herauszufinden, subtrahieren Sie von K das A, das unter Verwendung des Stockwerks von N erzeugt wird. In diesem Beispiel beträgt der Stock von N zwei. Also ist A = (10) (10 ^ 2 - 1)/(10-1) = 110, wie erwartet, wenn Sie die Zustände der ersten beiden Räume kombinieren. Dies muss von K abgezogen werden, da diese ersten 110 Zustände bereits in den ersten beiden Feldern berücksichtigt worden wären. Damit bleiben uns 82 Staaten. In diesem Zahlensystem ist die Darstellung von 192 in der Basis 10 also 082.
Der C # -Code, der einen Basisindex von Null verwendet, lautet
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;
}
// Alte Post
Eine nullbasierte Lösung in 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;
}
Einfach mit Rekursion.
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) );
}
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;
Update: Der Kommentar von Peter ist richtig. Das ist was ich für das Schreiben von Code im Browser bekomme. :-) Meine Lösung wurde nicht kompiliert, es fehlte der am weitesten links stehende Buchstabe und der Aufbau der Zeichenfolge in umgekehrter Reihenfolge - alles jetzt behoben.
Abgesehen von den Fehlern konvertiert der Algorithmus im Wesentlichen eine Zahl von Basis 10 in Basis 26.
Update 2: Joel Coehoorn ist richtig - der obige Code gibt AB für 27 zurück. Wenn es sich um eine echte Basis 26-Nummer handelt, wäre AA gleich A und die nächste Nummer nach Z wäre 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;
Diese Antwort ist in 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;
}
..Und in PHP umgewandelt:
function GetExcelColumnName($columnNumber) {
$columnName = '';
while ($columnNumber > 0) {
$modulo = ($columnNumber - 1) % 26;
$columnName = chr(65 + $modulo) . $columnName;
$columnNumber = (int)(($columnNumber - $modulo) / 26);
}
return $columnName;
}
Ich bin überrascht, dass alle Lösungen bisher entweder Iteration oder Rekursion enthalten.
Hier ist meine Lösung, die in konstanter Zeit läuft (keine Schleifen). Diese Lösung funktioniert für alle möglichen Excel-Spalten und überprüft, ob die Eingabe in eine Excel-Spalte umgewandelt werden kann. Mögliche Spalten liegen im Bereich [A, XFD] oder [1, 16384]. (Dies ist abhängig von Ihrer Version von 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);
}
}
Gleiche Implementierung in 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;
}
Ein bisschen spät im Spiel, aber hier ist der Code, den ich verwende (in 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));
}
Ich wollte meine statische Klasse verwenden, die ich benutze, um zwischen Col-Index und Col-Label zu wechseln. Ich verwende eine modifizierte akzeptierte Antwort für meine ColumnLabel-Methode
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;
}
}
Verwenden Sie dies wie ...
30.ColumnLabel(); // "AD"
"AD".ColumnIndex(); // 30
Fügen Sie einfach eine einfache zweizeilige C # -Implementierung mit Rekursion ein, da alle Antworten hier viel komplizierter erscheinen als notwendig.
/// <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);
}
Nachdem ich mir alle mitgelieferten Versionen angesehen hatte, ging ich hinunter, um eine selbst zu machen, indem ich Rekursion verwendete.
Hier ist meine vb.net-Version:
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
wenn Sie es nur für eine Zellenformel ohne Code wünschen, hier eine Formel dafür:
IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
In Delphi (Pascal):
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;
private String getColumn(int c) {
String s = "";
do {
s = (char)('A' + (c % 26)) + s;
c /= 26;
} while (c-- > 0);
return s;
}
Es ist nicht genau die Basis 26, es gibt keine 0 im System. Wenn ja, würde auf 'Z' 'BA' folgen, nicht 'AA'.
In Perl für eine Eingabe von 1 (A), 27 (AA) usw.
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;
}
JavaScript-Lösung
/**
* 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;
};
Verfeinern der ursprünglichen Lösung (in 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;
}
}
Hier ist eine Actionscript-Version:
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;
}
Ein anderer VBA-Weg
Public Function GetColumnName(TargetCell As Range) As String
GetColumnName = Split(CStr(TargetCell.Address), "$")(1)
End Function
Dies ist eine Javascript-Version gemäß dem Code von Graham
function (columnNumber) {
var dividend = columnNumber;
var columnName = "";
var modulo;
while (dividend > 0) {
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo) + columnName;
dividend = parseInt((dividend - modulo) / 26);
}
return columnName;
};
Ich versuche dasselbe in Java zu tun ....__ Ich habe folgenden Code geschrieben:
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;
}
Sobald ich es mit columnNumber = 29 ausgeführt habe, gibt es das Ergebnis = "CA" (anstelle von "AC") Gibt es irgendwelche Kommentare, die mir fehlen? Aber als ich die Antwort des Graham sah, bin ich wenig verwirrt ....
Dies ist die Frage, die von allen anderen sowie von Google weitergeleitet wird. Ich poste dies hier.
Viele dieser Antworten sind korrekt, aber für einfache Situationen zu umständlich, beispielsweise wenn Sie nicht über 26 Spalten haben. Wenn Sie Zweifel haben, ob Sie in doppelte Zeichensäulen gehen, ignorieren Sie diese Antwort. Wenn Sie sich jedoch sicher sind, dass Sie dies nicht tun, können Sie dies in C # so einfach wie folgt tun:
public static char ColIndexToLetter(short index)
{
if (index < 0 || index > 25) throw new ArgumentException("Index must be between 0 and 25.");
return (char)('A' + index);
}
Heck, wenn Sie sich sicher sind, was Sie übergeben, können Sie die Validierung sogar entfernen und diese Inline verwenden:
(char)('A' + index)
Dies wird in vielen Sprachen sehr ähnlich sein, sodass Sie es bei Bedarf anpassen können.
Auch hier gilt nur dann, wenn Sie zu 100% sicher sind, dass Sie nicht mehr als 26 Spalten haben werden.
Sorry, das ist Python statt C #, aber zumindest sind die Ergebnisse korrekt
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))
Bestanden diese Testfälle:
Obwohl ich zu spät komme, ist Grahams Antwort alles andere als optimal. Insbesondere müssen Sie nicht die Variable modulo
verwenden, ToString()
aufrufen und (int)
cast anwenden. Wenn man bedenkt, dass in den meisten Fällen in der C # -Welt Sie mit der Nummerierung von 0 beginnen würden, hier meine Überarbeitung:
public static string GetColumnName(int index) // zero-based
{
const byte BASE = 'Z' - 'A' + 1;
string name = String.Empty;
do
{
name = Convert.ToChar('A' + index % BASE) + name;
index = index / BASE - 1;
}
while (index >= 0);
return name;
}
Mit diesen Codes kann eine bestimmte Nummer (Indexstart von 1) in eine Excel-Spalte umgewandelt werden.
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;
}
Mein Unit-Test:
[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));
}
Bereits mehr als 30 Lösungen, aber hier ist meine einzeilige C # -Lösung ...
public string IntToExcelColumn(int i)
{
return ((i<16926? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<2730? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<26? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + ((char)((i%26)+65)));
}
Hier ist meine super späte Implementierung in PHP. Dies ist rekursiv. Ich habe es geschrieben, bevor ich diesen Beitrag gefunden habe. Ich wollte sehen, ob andere dieses Problem bereits gelöst hatten ...
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;
}
Prägnant und elegant Ruby Version:
def col_name(col_idx)
name = ""
while col_idx>0
mod = (col_idx-1)%26
name = (65+mod).chr + name
col_idx = ((col_idx-mod)/26).to_i
end
name
end
NodeJS-Implementierung:
/**
* getColumnFromIndex
* Helper that returns a column value (A-XFD) for an index value (integer).
* The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
* See https://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-Excel-column-eg-aa/3444285#3444285
* @param numVal: Integer
* @return String
*/
getColumnFromIndex: function(numVal){
var dividend = parseInt(numVal);
var columnName = '';
var modulo;
while (dividend > 0) {
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo) + columnName;
dividend = parseInt((dividend - modulo) / 26);
}
return columnName;
},
Dank Konvertieren Sie das Excel-Spaltenalphabet (z. B. AA) in die Zahl (z. B. 25) . Und umgekehrt:
/**
* getIndexFromColumn
* Helper that returns an index value (integer) for a column value (A-XFD).
* The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
* See https://stackoverflow.com/questions/9905533/convert-Excel-column-alphabet-e-g-aa-to-number-e-g-25
* @param strVal: String
* @return Integer
*/
getIndexFromColumn: function(val){
var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
for (i = 0, j = val.length - 1; i < val.length; i += 1, j -= 1) {
result += Math.pow(base.length, j) * (base.indexOf(val[i]) + 1);
}
return result;
}
Eine andere Lösung:
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, ...
}
mehr dazu hier - Zellreferenzierung in Excel für alle! von Dr Nitin Paranjape
Ich musste diese Arbeit heute nur machen, meine Implementierung verwendet Rekursion:
private static string GetColumnLetter(string colNumber)
{
if (string.IsNullOrEmpty(colNumber))
{
throw new ArgumentNullException(colNumber);
}
string colName = String.Empty;
try
{
var colNum = Convert.ToInt32(colNumber);
var mod = colNum % 26;
var div = Math.Floor((double)(colNum)/26);
colName = ((div > 0) ? GetColumnLetter((div - 1).ToString()) : String.Empty) + Convert.ToChar(mod + 65);
}
finally
{
colName = colName == String.Empty ? "A" : colName;
}
return colName;
}
Dies betrachtet die Zahl als Zeichenfolge, die Methode und die Zahlen, die mit "0" beginnen (A = 0).
Eine weitere VBA-Antwort sah - dies kann in Excel-vba mit einer 1-Zeilen-UDF:.
Function GetColLetter(ByVal colID As Integer) As String
GetColLetter = Split(Cells(1, colID).Address, "$")(1)
End Function
Hier ist, was es wert ist, Grahams Code in Powershell:
function ConvertTo-ExcelColumnID {
param (
[parameter(Position = 0,
HelpMessage = "A 1-based index to convert to an Excel column ID. e.g. 2 => 'B', 29 => 'AC'",
Mandatory = $true)]
[int]$index
);
[string]$result = '';
if ($index -le 0 ) {
return $result;
}
while ($index -gt 0) {
[int]$modulo = ($index - 1) % 26;
$character = [char]($modulo + [int][char]'A');
$result = $character + $result;
[int]$index = ($index - $modulo) / 26;
}
return $result;
}
Verwenden Sie dies in VB.Net 2005:
Private Function ColumnName(ByVal ColumnIndex As Integer) As String
Dim Name As String = ""
Name = (New Microsoft.Office.Interop.Owc11.Spreadsheet).Columns.Item(ColumnIndex).Address(False, False, Microsoft.Office.Interop.Owc11.XlReferenceStyle.xlA1)
Name = Split(Name, ":")(0)
Return Name
End Function
Die meisten vorherigen Antworten sind korrekt. Hier ist eine weitere Möglichkeit, die Spaltennummer in Excel-Spalten umzuwandeln. Die Lösung ist ziemlich einfach, wenn wir dies als Basisumwandlung betrachten. Wandeln Sie einfach die Spaltennummer in Basis 26 um, da nur 26 Buchstaben vorhanden sind ..__ So können Sie dies tun:
Schritte:
setzen Sie die Spalte als Quotienten
subtrahieren Sie eins von der Quotientenvariablen (vom vorherigen Schritt), da wir auf ascii table enden müssen, wobei 97 a ist.
durch 26 teilen und den Rest erhalten.
hier ist der Code, der das tut :)
def convert_num_to_column(column_num):
result = ""
quotient = column_num
remainder = 0
while (quotient >0):
quotient = quotient -1
remainder = quotient%26
result = chr(int(remainder)+97)+result
quotient = int(quotient/26)
return result
print("--",convert_num_to_column(1).upper())
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));
}
Danke für die Antworten hier !! Ich habe mit diesen Hilfsfunktionen für die Interaktion mit der Google Sheets-API gearbeitet, an der ich in Elixir/Phoenix arbeite
hier ist, was ich kam (könnte wahrscheinlich etwas zusätzliche Validierung und Fehlerbehandlung verwenden)
In Elixir:
def number_to_column(number) do
cond do
(number > 0 && number <= 26) ->
to_string([(number + 64)])
(number > 26) ->
div_col = number_to_column(div(number - 1, 26))
remainder = rem(number, 26)
rem_col = cond do
(remainder == 0) ->
number_to_column(26)
true ->
number_to_column(remainder)
end
div_col <> rem_col
true ->
""
end
end
Und die Umkehrfunktion:
def column_to_number(column) do
column
|> to_charlist
|> Enum.reverse
|> Enum.with_index
|> Enum.reduce(0, fn({char, idx}, acc) ->
((char - 64) * :math.pow(26,idx)) + acc
end)
|> round
end
Und einige Tests:
describe "test Excel functions" do
@excelTestData [{"A", 1}, {"Z",26}, {"AA", 27}, {"AB", 28}, {"AZ", 52},{"BA", 53}, {"AAA", 703}]
test "column to number" do
Enum.each(@excelTestData, fn({input, expected_result}) ->
actual_result = BulkOnboardingController.column_to_number(input)
assert actual_result == expected_result
end)
end
test "number to column" do
Enum.each(@excelTestData, fn({expected_result, input}) ->
actual_result = BulkOnboardingController.number_to_column(input)
assert actual_result == expected_result
end)
end
end
So würde ich es in Python machen. Der Algorithmus wird unten erklärt:
alph = ('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')
def labelrec(n, res):
if n<26:
return alph[n]+res
else:
rem = n%26
res = alph[rem]+res
n = n/26-1
return labelrec(n, res)
Die Funktion labelrec kann mit der Nummer und einer leeren Zeichenfolge aufgerufen werden:
print labelrec(16383, '')
Deshalb funktioniert es: Wenn Dezimalzahlen auf dieselbe Weise wie Excel-Arbeitsblattspalten geschrieben würden, würde die Zahl 0-9 normal geschrieben, aber 10 würde '00' und dann 20 '10' und so weiter. Einige Zahlen zuordnen:
0 - 0
9 - 9
10 - 00 Uhr
20 - 10
100 - 90
110 - 000
1110 - 0000
Das Muster ist also klar. Wenn an der Stelle der Einheit eine Zahl kleiner als 10 ist, entspricht ihre Darstellung der Zahl selbst. Andernfalls müssen Sie die verbleibende Zahl anpassen, indem Sie sie um 1 subtrahieren und erneut rekursieren. Sie können anhalten, wenn die Anzahl weniger als 10 beträgt.
Die gleiche Logik wird für die Nummern der Basis 26 in der obigen Lösung angewendet.
P.S. Wenn Sie möchten, dass die Zahlen bei 1 beginnen, rufen Sie dieselbe Funktion für die Eingangsnummer auf, nachdem Sie sie um 1 verringert haben.
Wenn Sie die Zelle progmatisch referenzieren möchten, erhalten Sie viel besser lesbaren Code, wenn Sie die Cells-Methode eines Arbeitsblatts verwenden. Statt einer traditionellen Zellreferenz wird ein Zeilen- und Spaltenindex verwendet. Es ist der Offset-Methode sehr ähnlich.
(Mir ist klar, dass sich die Frage auf C # bezieht. Wenn jedoch jemand mit Java dasselbe tun muss, kann Folgendes hilfreich sein.
Es stellt sich heraus, dass dies mit der Klasse "CellReference" in Jakarta POI problemlos möglich ist. Die Konvertierung kann auch auf zwei Arten erfolgen.
// Convert row and column numbers (0-based) to an Excel cell reference
CellReference numbers = new CellReference(3, 28);
System.out.println(numbers.formatAsString());
// Convert an Excel cell reference back into digits
CellReference reference = new CellReference("AC4");
System.out.println(reference.getRow() + ", " + reference.getCol());
F # -Version jedes Weges
let rec getExcelColumnName x = if x<26 then int 'A'+x|>char|>string else (x/26-1|>c)+ c(x%26)
verzeihung der Minimierung, arbeitete an einer besseren Version von https://stackoverflow.com/a/4500043/57883
// return values start at 0
let getIndexFromExcelColumnName (x:string) =
let a = int 'A'
let fPow len i =
Math.Pow(26., len - 1 - i |> float)
|> int
let getValue len i c =
int c - a + 1 * fPow len i
let f i = getValue x.Length i x.[i]
[0 .. x.Length - 1]
|> Seq.map f
|> Seq.sum
|> fun x -> x - 1
Ich verwende dieses in VB.NET 2003 und es funktioniert gut ...
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
Ziel-C-Implementierung:
-(NSString*)getColumnName:(int)n {
NSString *name = @"";
while (n>0) {
n--;
char c = (char)('A' + n%26);
name = [NSString stringWithFormat:@"%c%@",c,name];
n = n/26;
}
return name;
}
Schnelle Implementierung:
func getColumnName(n:Int)->String{
var columnName = ""
var index = n
while index>0 {
index--
let char = Character(UnicodeScalar(65 + index%26))
columnName = "\(char)\(columnName)"
index = index / 26
}
return columnName
}
Die Antwort basiert auf: https://stackoverflow.com/a/4532562/2231118