คุณแปลงตัวเลขให้เป็นชื่อคอลัมน์ Excel ใน C # ได้อย่างไรโดยไม่ต้องใช้ระบบอัตโนมัติรับค่าโดยตรงจาก Excel
Excel 2007 มีช่วงที่เป็นไปได้ตั้งแต่ 1 ถึง 16384 ซึ่งเป็นจำนวนคอลัมน์ที่รองรับ ค่าผลลัพธ์ควรอยู่ในรูปแบบชื่อคอลัมน์ excel เช่น A, AA, AAA เป็นต้น
คุณแปลงตัวเลขให้เป็นชื่อคอลัมน์ Excel ใน C # ได้อย่างไรโดยไม่ต้องใช้ระบบอัตโนมัติรับค่าโดยตรงจาก Excel
Excel 2007 มีช่วงที่เป็นไปได้ตั้งแต่ 1 ถึง 16384 ซึ่งเป็นจำนวนคอลัมน์ที่รองรับ ค่าผลลัพธ์ควรอยู่ในรูปแบบชื่อคอลัมน์ excel เช่น A, AA, AAA เป็นต้น
คำตอบ:
นี่คือวิธีที่ฉันทำ:
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;
}
StringBuilder
ก็พยายามออกมาใช้ ใช้เวลาประมาณสองเท่า มันเป็นสตริงที่สั้นมาก (สูงสุด 3 ตัวอักษร - Excel 2010 ขึ้นอยู่กับคอลัมน์ XFD) ดังนั้นการต่อกันของสตริงสูงสุด 2 รายการ (ฉันใช้การวนซ้ำ 100 ครั้งในการแปลจำนวนเต็ม 1 ถึง 16384 เช่นคอลัมน์ Excel A ถึง XFD เป็นการทดสอบ)
modulo
โทรToString()
และสมัคร(int)
นักแสดง พิจารณาว่าในกรณีส่วนใหญ่ในโลก C # คุณจะเริ่มนับจาก 0 นี่คือการแก้ไขของฉัน: <! - language: c # -> สตริงคงที่สาธารณะ GetColumnName (ดัชนี int) // zero-based {const ไบต์ฐาน = 'Z '-' A '+ 1; string name = String.Empty; ทำ {name = Convert.ToChar ('A' + ดัชนี% BASE) + ชื่อ index = index / BASE - 1; } while (ดัชนี> = 0); ชื่อส่งคืน; }
หากใครต้องการทำสิ่งนี้ใน 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 คุณสามารถทำได้ด้วยตัวอักษรของตัวอักษร
Space: ......................... S1, S2, S3: S1, S2, S3
............ ........................ 0, 00, 000: .. A, AA, AAA
............. ....................... 1, 01, 001: .. B, AB, AAB
.............. ...................... …, …, …: ……, …, …, …
............... ..................... 9, 99, 999: .. Z, ZZ, ZZZ
สถานะรวมทั้งหมดในอวกาศ: 10, 100, 1000: 26, 676, 17576
รวมรัฐ: ............... 1110 ................ 18278
คอลัมน์ตัวเลข Excel ในช่องว่างตัวอักษรแต่ละตัวโดยใช้ฐาน 26 คุณจะเห็นได้ว่าโดยทั่วไปความก้าวหน้าของพื้นที่ของรัฐคือ a, a ^ 2, a ^ 3, …สำหรับบางฐาน a และจำนวนทั้งหมดของรัฐคือ a + a ^ 2 + a ^ 3 + ….
สมมติว่าคุณต้องการค้นหาจำนวนสถานะทั้งหมดในช่องว่าง N แรก สูตรในการทำเช่นนี้คือ A = (a) (a ^ N - 1) / (a-1) สิ่งนี้มีความสำคัญเนื่องจากเราต้องการค้นหาพื้นที่ N ที่สอดคล้องกับดัชนี K ของเราถ้าฉันต้องการหาที่ K อยู่ในระบบจำนวนฉันต้องแทนที่ A ด้วย K และแก้หา N วิธีแก้ปัญหาคือ N = log { ฐาน a} (A (a-1) / a +1) ถ้าฉันใช้ตัวอย่างของ a = 10 และ K = 192 ฉันรู้ว่า N = 2.23804 … นี่บอกฉันว่า K อยู่ที่จุดเริ่มต้นของช่องว่างที่สามเนื่องจากมันใหญ่กว่าสองเล็กน้อย
ขั้นตอนต่อไปคือการค้นหาว่าเราอยู่ไกลแค่ไหนในพื้นที่ปัจจุบัน หากต้องการค้นหาสิ่งนี้ให้ลบออกจาก K a ที่สร้างโดยใช้ชั้นของ N ในตัวอย่างนี้พื้นของ N คือสอง ดังนั้น A = (10) (10 ^ 2 - 1) / (10-1) = 110 ตามที่คาดไว้เมื่อคุณรวมสถานะของช่องว่างสองช่องแรก จำเป็นต้องลบออกจาก K เนื่องจาก 110 รัฐแรกเหล่านี้จะถูกนำมาใช้ในสองช่องว่างแรกแล้ว สิ่งนี้ทำให้เรามี 82 รัฐ ดังนั้นในระบบจำนวนนี้การแทนค่า 192 ในฐาน 10 คือ 082
รหัส 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;
}
// โพสต์เก่า
วิธีการแก้ปัญหา zero-based ใน 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;
Update : ความคิดเห็นของPeterถูกต้อง นั่นคือสิ่งที่ฉันได้รับจากการเขียนโค้ดในเบราว์เซอร์ :-) วิธีการแก้ปัญหาของฉันไม่ได้รวบรวมมันก็หายไปตัวอักษรซ้ายสุดและมันก็สร้างสตริงในลำดับที่กลับกัน - ทั้งหมดตอนนี้ได้รับการแก้ไข
ขั้นตอนวิธีจะทำการแปลงจำนวนจากฐาน 10 เป็นฐาน 26
อัปเดต 2 : Joel Coehoornถูกต้อง - โค้ดด้านบนจะคืนค่า AB เป็น 27 ถ้าเป็นฐาน 26 จริง AA จะเท่ากับ A และ 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) );
}
เพียงแค่ใช้งาน 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);
}
.. และแปลงเป็น php:
function GetExcelColumnName($columnNumber) {
$columnName = '';
while ($columnNumber > 0) {
$modulo = ($columnNumber - 1) % 26;
$columnName = chr(65 + $modulo) . $columnName;
$columnNumber = (int)(($columnNumber - $modulo) / 26);
}
return $columnName;
}
ord('A')
แทน 65.
ฉันประหลาดใจที่วิธีแก้ปัญหาทั้งหมดมีการทำซ้ำหรือเรียกซ้ำ
นี่คือทางออกของฉันที่ทำงานในเวลาคงที่ (ไม่มีลูป) วิธีนี้ใช้ได้กับคอลัมน์ 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);
}
}
int
s ชื่อคอลัมน์ที่เกิดขึ้นอาจจะเป็นพลยาว (เป็นกรณีของคำตอบหลามตัวอย่างเช่น)
คำตอบนี้อยู่ในจาวาสคริปต์:
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;
}
implementaion เดียวกันใน 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));
}
IndexOf
ค่อนข้างช้าคุณควรคาดคะเนการทำแผนที่ย้อนกลับดีกว่า
ฉันต้องการที่จะโยนในระดับคงที่ของฉันที่ฉันใช้สำหรับการสอดแทรกระหว่างดัชนีสีและฉลากสี ฉันใช้คำตอบที่ได้รับการยอมรับสำหรับวิธีการแก้ไขแบบคอลัมน์ของฉัน
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
หากคุณต้องการใช้สำหรับสูตรเซลล์ที่ไม่มีโค้ดนี่เป็นสูตรสำหรับ:
IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
ใน 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;
}
มันไม่ได้เป็นฐานที่ 26 แน่นอนว่าไม่มี 0 ในระบบ หากมี 'Z' จะตามด้วย 'BA' ไม่ใช่ 'AA'
ใน perl สำหรับอินพุต 1 (A), 27 (AA) ฯลฯ
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;
}
การปรับแต่งโซลูชันดั้งเดิม (ใน 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;
};
รหัสของฉันสำหรับแปลงจำนวนเฉพาะ (ดัชนีเริ่มต้นจาก 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));
}
แม้ว่าฉันจะเล่นเกมช้า แต่คำตอบของเกรแฮมก็ยังห่างไกลจากความเหมาะสม โดยเฉพาะอย่างยิ่งคุณไม่จำเป็นต้องใช้การmodulo
โทรToString()
และสมัครการ(int)
ส่ง พิจารณาว่าในกรณีส่วนใหญ่ในโลก C # คุณจะเริ่มนับจาก 0 นี่คือการแก้ไขของฉัน:
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;
}
อีกวิธี VBA
Public Function GetColumnName(TargetCell As Range) As String
GetColumnName = Split(CStr(TargetCell.Cells(1, 1).Address), "$")(1)
End Function
นี่คือการใช้งานช่วงท้ายสุดของฉันใน 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 .... แต่ดูคำตอบของเกรแฮมฉันสับสนเล็กน้อย ....
columnName = Convert.ToChar(65 + modulo).ToString() + columnName
(เช่นค่า + ColName) Hasan พูดว่า: columnName += val;
(เช่น ColName + value)
columnName = columnName + val
ควรจะเป็น
รุ่นRuby ที่สอดคล้องกันและสง่างาม:
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
นี่คือคำถามอื่น ๆ ทั้งหมดรวมทั้ง Google เปลี่ยนเส้นทางไปดังนั้นฉันโพสต์ที่นี่
หลายคำตอบเหล่านี้ถูกต้อง แต่ยุ่งยากเกินไปสำหรับสถานการณ์แบบง่ายเช่นเมื่อคุณไม่มีคอลัมน์มากกว่า 26 คอลัมน์ หากคุณมีข้อสงสัยว่าคุณอาจเข้าไปในคอลัมน์ตัวละครสองตัวแล้วไม่ต้องสนใจคำตอบนี้ แต่ถ้าคุณแน่ใจว่าคุณจะไม่ทำเช่นนั้นคุณสามารถทำได้ง่าย ๆ เช่นนี้ใน C #:
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 หากคุณมั่นใจในสิ่งที่คุณส่งผ่านคุณสามารถลบการตรวจสอบและใช้ inline นี้:
(char)('A' + index)
สิ่งนี้จะคล้ายกันมากในหลายภาษาเพื่อให้คุณสามารถปรับได้ตามต้องการ
อีกครั้งเพียงใช้นี้หากคุณกำลัง 100% แน่ใจว่าคุณจะไม่ได้มีมากกว่า 26 คอลัมน์
ขอบคุณสำหรับคำตอบที่นี่ !! ช่วยฉันคิดหาฟังก์ชั่นตัวช่วยเหล่านี้สำหรับการโต้ตอบกับ Google ชีต API ที่ฉันทำงานใน Elixir / Phoenix
นี่คือสิ่งที่ฉันมาด้วย (อาจจะใช้การตรวจสอบและการจัดการข้อผิดพลาดพิเศษบางอย่าง)
ใน 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
และฟังก์ชันผกผัน:
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
และการทดสอบบางอย่าง:
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