C#에서 Excel 열 문자를 가장 빠르게 생성하는 기능
엑셀 함수에서 사용하기 위해 문자가 포함된 문자열을 가져다가 들여보내고 반환하는 가장 빠른 c# 함수는 무엇입니까?예를 들어, 1은 "A"를 반환하고, 26은 "Z"를 반환하고, 27은 "AA"를 반환합니다.
이 작업은 수만 번의 작업으로 불리며, 많은 공식이 포함된 대규모 스프레드시트를 생성하는 데 필요한 시간의 25%가 소요됩니다.
public string Letter(int intCol) {
int intFirstLetter = ((intCol) / 676) + 64;
int intSecondLetter = ((intCol % 676) / 26) + 64;
int intThirdLetter = (intCol % 26) + 65;
char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
char ThirdLetter = (char)intThirdLetter;
return string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
}
저는 현재 Excel 2007에서 이것을 사용하고 있습니다.
public static string ExcelColumnFromNumber(int column)
{
string columnString = "";
decimal columnNumber = column;
while (columnNumber > 0)
{
decimal currentLetterNumber = (columnNumber - 1) % 26;
char currentLetter = (char)(currentLetterNumber + 65);
columnString = currentLetter + columnString;
columnNumber = (columnNumber - (currentLetterNumber + 1)) / 26;
}
return columnString;
}
그리고.
public static int NumberFromExcelColumn(string column)
{
int retVal = 0;
string col = column.ToUpper();
for (int iChar = col.Length - 1; iChar >= 0; iChar--)
{
char colPiece = col[iChar];
int colNum = colPiece - 64;
retVal = retVal + colNum * (int)Math.Pow(26, col.Length - (iChar + 1));
}
return retVal;
}
다른 게시물에서 언급한 것처럼 결과를 캐시할 수 있습니다.
가장 빠른 기능이 가장 예쁜 기능은 아닐 것이라고 말씀드릴 수 있습니다.여기 있습니다.
private string[] map = new string[]
{
"A", "B", "C", "D", "E" .............
};
public string getColumn(int number)
{
return map[number];
}
전혀 변환하지 마십시오.Excel은 A1 표기법뿐만 아니라 R1 C1 표기법에서도 작동할 수 있습니다.
그래서 (C#이 아닌 VBA를 사용한 경우 사과드립니다.)
Application.Worksheets("Sheet1").Range("B1").Font.Bold = True
다음과 같이 쉽게 쓸 수 있습니다.
Application.Worksheets("Sheet1").Cells(1, 2).Font.Bold = True
그Range, 속은성 A1 기용사는반면하을법표,,Cells속성은 (행 번호, 열 번호)을 사용합니다.
셀을 : 여러셀선는방법하Range(Cells(1, 1), Cells(4, 6))활성 를 사용하지 경우 어떤 합니다.)Range("A1:F4")
그Columns F) 6할 수 .
제 버전은 다음과 같습니다.이는 2글자 또는 3글자와 같은 제한이 없습니다.필요한 숫자만 전달(0부터 시작) 전달된 숫자에 대해 알파벳 순서와 같은 Excel 열 머리글을 반환합니다.
private string GenerateSequence(int num)
{
string str = "";
char achar;
int mod;
while (true)
{
mod = (num % 26) + 65;
num = (int)(num / 26);
achar = (char)mod;
str = achar + str;
if (num > 0) num--;
else if (num == 0) break;
}
return str;
}
저는 성능 테스트를 하지 않았습니다, 만약 누군가가 그것을 할 수 있다면 다른 사람들에게 좋을 것입니다. (나태해서 죄송합니다) :)
건배!
모든 값을 문자열 배열로 미리 생성할 수 있습니다.이 작업은 메모리가 거의 필요하지 않으며 첫 번째 호출 시 계산할 수 있습니다.
다음은 LINQ를 사용한 간결한 구현입니다.
static IEnumerable<string> GetExcelStrings()
{
string[] alphabet = { string.Empty, "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" };
return from c1 in alphabet
from c2 in alphabet
from c3 in alphabet.Skip(1) // c3 is never empty
where c1 == string.Empty || c2 != string.Empty // only allow c2 to be empty if c1 is also empty
select c1 + c2 + c3;
}
하면 이생성니다가 생성됩니다.AZ,그리고나서AAZZ,그리고나서AAAZZZ.
PC에서 내PC, 출PC에 GetExcelStrings().ToArray()약 30ms가 소요됩니다.그 후에 필요한 경우 이 문자열 배열을 수천 번 참조할 수 있습니다.
함수가 실행되면 결과를 사전에 캐시합니다.따라서 다시 계산할 필요가 없습니다.
예: Convert(27)는 27이 사전에 매핑/저장되어 있는지 확인합니다.그렇지 않은 경우, 계산을 수행하고 사전에 27에 "AA"를 저장합니다.
절대적으로 가장 빠른 방법은 Excel 스프레드시트가 고정된 수의 열만 사용하도록 자본화하는 것입니다. 따라서 룩업 테이블을 수행할 수 있습니다.256개 항목의 일정한 문자열 배열을 선언하고 "A"에서 "IV"까지의 문자열로 미리 채웁니다.그런 다음 단순한 인덱스 조회를 수행합니다.
이 기능을 사용해 보십시오.
// Returns name of column for specified 0-based index.
public static string GetColumnName(int index)
{
var name = new char[3]; // Assumes 3-letter column name max.
int rem = index;
int div = 17576; // 26 ^ 3
for (int i = 2; i >= 0; i++)
{
name[i] = alphabet[rem / div];
rem %= div;
div /= 26;
}
if (index >= 676)
return new string(name, 3);
else if (index >= 26)
return new string(name, 2);
else
return new string(name, 1);
}
이제 모든 인덱스에 대해 각 열 이름을 미리 생성하고 하나의 거대한 배열에 저장하는 데 그렇게 많은 메모리가 필요하지 않으므로 열 이름을 두 번 조회할 필요가 없습니다.
추가 최적화를 생각할 수 있다면 나중에 추가하겠습니다. 하지만 이 기능은 상당히 빨라야 한다고 생각합니다. 그리고 사전 세대를 수행하는 경우에도 이러한 속도가 필요할 것이라고 생각합니다.
첫 번째 문제는 메소드에 6개의 변수를 선언한다는 것입니다.메소드가 수천 번 호출되는 경우 함수 범위 대신 클래스 범위로 이동하는 것만으로도 처리 시간이 즉시 절반 이상 단축될 수 있습니다.
이것은 자바로 쓰여 있지만, 기본적으로 같은 것입니다.
다음 코드는 0 기반 인덱스를 사용하여 대문자로 열 레이블을 계산하는 것입니다.
public static String findColChars(long index) {
char[] ret = new char[64];
for (int i = 0; i < ret.length; ++i) {
int digit = ret.length - i - 1;
long test = index - powerDown(i + 1);
if (test < 0)
break;
ret[digit] = toChar(test / (long)(Math.pow(26, i)));
}
return new String(ret);
}
private static char toChar(long num) {
return (char)((num % 26) + 65);
}
다음은 대문자 레이블에서 열의 0 기반 인덱스를 계산하는 코드입니다.
public static long findColIndex(String col) {
long index = 0;
char[] chars = col.toCharArray();
for (int i = 0; i < chars.length; ++i) {
int cur = chars.length - i - 1;
index += (chars[cur] - 65) * Math.pow(26, i);
}
return index + powerDown(chars.length);
}
private static long powerDown(int limit) {
long acc = 0;
while (limit > 1)
acc += Math.pow(26, limit-- - 1);
return acc;
}
@Neil N -- 좋은 코드입니다. 제 생각에 세 번째 글자는 +65가 아니라 +64를 가져야 한다고 생각합니다. 제가 맞나요?
public string Letter(int intCol) {
int intFirstLetter = ((intCol) / 676) + 64;
int intSecondLetter = ((intCol % 676) / 26) + 64;
int intThirdLetter = (intCol % 26) + 65; ' SHOULD BE + 64?
char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
char ThirdLetter = (char)intThirdLetter;
return string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
}
우리가 요인화를 시도해 보는 게 어때요?
public static string GetColumnName(int index)
{
const string letters = "ZABCDEFGHIJKLMNOPQRSTUVWXY";
int NextPos = (index / 26);
int LastPos = (index % 26);
if (LastPos == 0) NextPos--;
if (index > 26)
return GetColumnName(NextPos) + letters[LastPos];
else
return letters[LastPos] + "";
}
캐슁은 실제로 10,000,000건의 랜덤 호출의 런타임을 1/3로 줄여줍니다. 단, 다음과 같은 이점이 있습니다.
static Dictionary<int, string> LetterDict = new Dictionary<int, string>(676);
public static string LetterWithCaching(int index)
{
int intCol = index - 1;
if (LetterDict.ContainsKey(intCol)) return LetterDict[intCol];
int intFirstLetter = ((intCol) / 676) + 64;
int intSecondLetter = ((intCol % 676) / 26) + 64;
int intThirdLetter = (intCol % 26) + 65;
char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
char ThirdLetter = (char)intThirdLetter;
String s = string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
LetterDict.Add(intCol, s);
return s;
}
최악의 경우(매 값 적중)의 캐싱은 250kb(가능한 값 17576개 *(size of(int)=4 + size of(char)*3 + string overhead=2)를 초과할 수 없습니다.
그것은 재귀적입니다.빠르고 정확하게:
class ToolSheet
{
//Not the prettyest but surely the fastest :
static string[] ColName = new string[676];
public ToolSheet()
{
ColName[0] = "A";
for (int index = 1; index < 676; ++index) Recurse(index, index);
}
private int Recurse(int i, int index)
{
if (i < 1) return 0;
ColName[index] = ((char)(65 + i % 26)).ToString() + ColName[index];
return Recurse(i / 26, index);
}
public string GetColName(int i)
{
return ColName[i - 1];
}
}
죄송합니다. 변경 사항이 있습니다. 수정되었습니다.
class ToolSheet
{
//Not the prettyest but surely the fastest :
static string[] ColName = new string[676];
public ToolSheet()
{
for (int index = 0; index < 676; ++index)
{
Recurse(index, index);
}
}
private int Recurse(int i, int index)
{
if (i < 1)
{
if (index % 26 == 0 && index > 0) ColName[index] = ColName[index - 1].Substring(0, ColName[index - 1].Length - 1) + "Z";
return 0;
}
ColName[index] = ((char)(64 + i % 26)).ToString() + ColName[index];
return Recurse(i / 26, index);
}
public string GetColName(int i)
{
return ColName[i - 1];
}
}
내 솔루션:
static class ExcelHeaderHelper
{
public static string[] GetHeaderLetters(uint max)
{
var result = new List<string>();
int i = 0;
var columnPrefix = new Queue<string>();
string prefix = null;
int prevRoundNo = 0;
uint maxPrefix = max / 26;
while (i < max)
{
int roundNo = i / 26;
if (prevRoundNo < roundNo)
{
prefix = columnPrefix.Dequeue();
prevRoundNo = roundNo;
}
string item = prefix + ((char)(65 + (i % 26))).ToString(CultureInfo.InvariantCulture);
if (i <= maxPrefix)
{
columnPrefix.Enqueue(item);
}
result.Add(item);
i++;
}
return result.ToArray();
}
}
바로크의 아이디어는 어떤 변환 함수보다 훨씬 편리하고 빠릅니다! 저는 그의 아이디어를 제가 사용하는 실제 c# 코드로 변환했습니다.
var start = m_xlApp.Cells[nRow1_P, nCol1_P];
var end = m_xlApp.Cells[nRow2_P, nCol2_P];
// cast as Range to prevent binding errors
m_arrRange = m_xlApp.get_Range(start as Range, end as Range);
object[] values = (object[])m_arrRange.Value2;
private String columnLetter(int column) {
if (column <= 0)
return "";
if (column <= 26){
return (char) (column + 64) + "";
}
if (column%26 == 0){
return columnLetter((column/26)-1) + columnLetter(26) ;
}
return columnLetter(column/26) + columnLetter(column%26) ;
}
Allen Wyatt(https://excel.tips.net/T003254_Alphabetic_Column_Designation.html) 에 따르면 UDF(사용자 정의 함수)나 다른 프로그램 대신 Excel 공식을 사용하면 됩니다.
=SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),"")
(우리 조직에서는 UDF를 사용하는 것이 매우 고통스러울 것입니다.)
제가 제공하는 코드는 C#(대신 파이썬)이 아니라 어떤 언어든 논리를 사용할 수 있습니다.
대부분의 이전 답은 정답입니다.열 번호를 Excel 열로 변환하는 또 다른 방법이 있습니다. 이것을 기본 변환으로 생각하면 솔루션은 매우 간단합니다.26자만 있으므로 열 번호를 기본 26으로 변환합니다.이를 위한 방법은 다음과 같습니다.
단계:
열을 지수로 설정합니다.
26으로 나누고 나머지를 구하세요.
- 나머지에 +97을 추가하고 char로 변환(97은 ASCII 테이블에서 "a"이므로)
- 지수가 새 지수가 됨/ 26(26열을 초과할 수 있으므로)
- 할당량이 0보다 클 때까지 이 작업을 계속한 다음 결과를 반환합니다.
여기 이것을 하는 코드가 있습니다 :)
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())
A1에서만 시작하는 문자가 아닌 문자를 생성해야 하는 경우
private static string GenerateCellReference(int n, int startIndex = 65)
{
string name = "";
n += startIndex - 65;
while (n > 0)
{
n--;
name = (char)((n % 26) + 65) + name;
n /= 26;
}
return name + 1;
}
언급URL : https://stackoverflow.com/questions/837155/fastest-function-to-generate-excel-column-letters-in-c-sharp
'programing' 카테고리의 다른 글
| Ubuntu에 설치된 MongoDB 버전 (0) | 2023.04.29 |
|---|---|
| 실행 중인 SQL Server 포트를 찾는 방법은 무엇입니까? (0) | 2023.04.29 |
| 손상된 WPF 데이터 바인딩을 탐지하는 방법은 무엇입니까? (0) | 2023.04.29 |
| Azure Max 지출 한도 또는 비용 CAP $ 금액을 설정하는 방법은 무엇입니까? (0) | 2023.04.29 |
| WPF 유효성 검사 오류 감지 (0) | 2023.04.29 |