C2011 6.4.8.2p3 требует, чтобы каждое выражение метки случая было выражением целочисленной константы . Целочисленные константные выражения являются ограниченным подмножеством константных выражений, определенных в § 6.6p6 . Строковые литералы могут не появляться в целочисленных константных выражениях.
6.4.8.2p3 является абзацем «ограничений», поэтому эта программа некорректна.
Таким образом, ответ на ваш вопрос, как его буквально задают, таков: компилятор может уменьшить "string"[0]
до 's'
, но это не разрешено; вместо этого требуется отклонить вашу программу.
Я написал это давным-давно для какого-то скрипта Python:
def index_to_int(index):
s = 0
pow = 1
for letter in index[::-1]:
d = int(letter,36) - 9
s += pow * d
pow *= 26
# excel starts column numeration from 1
return s
def ExcelColumnToNumber(ColumnName):
ColNum = 0
for i in range(0, len(ColumnName)):
# Easier once formula determined: 'PositionValue * Base^Position'
# i.e. AA=(1*26^1)+(1*26^0) or 792=(7*10^2)+(9*10^1)+(2*10^0)
ColNum += (int(ColumnName[i],36) -9) * (pow(26, len(ColumnName)-i-1))
return ColNum
ps Мой первый скрипт на Python!
Slightly related, the better challenge is the other way around: given the column number, find the column label as string.
Qt version as what I implemented for KOffice:
QString columnLabel( unsigned column )
{
QString str;
unsigned digits = 1;
unsigned offset = 0;
column--;
for( unsigned limit = 26; column >= limit+offset; limit *= 26, digits++ )
offset += limit;
for( unsigned c = column - offset; digits; --digits, c/=26 )
str.prepend( QChar( 'A' + (c%26) ) );
return str;
}
Delphi:
// convert EXcel column name to column number 1..256
// case-sensitive; returns 0 for illegal column name
function cmColmAlfaToNumb( const qSRC : string ) : integer;
var II : integer;
begin
result := 0;
for II := 1 to length(qSRC) do begin
if (qSRC[II]<'A')or(qSRC[II]>'Z') then begin
result := 0;
exit;
end;
result := result*26+ord(qSRC[II])-ord('A')+1;
end;
if result>256 then result := 0;
end;
-Al.
another [more cryptic] erlang example:
col2int(String) -> col2int(0,String).
col2int(X,[A|L]) when A >= 65, A =< 90 ->
col2int(26 * X + A - 65 + 1, L);
col2int(X,[]) -> X.
and inverse function:
int2col(Y) when Y > 0 -> int2col(Y,[]).
int2col(0,L) -> L;
int2col(Y,L) when Y rem 26 == 0 ->
int2col(Y div 26 - 1,[(26+65-1)|L]);
int2col(Y,L) ->
P = Y rem 26,
int2col((Y - P) div 26,[P + 65-1|L]).
Вот CFML:
<cffunction name="ColToNum" returntype="Numeric">
<cfargument name="Input" type="String" />
<cfset var Total = 0 />
<cfset var Pos = 0 />
<cfloop index="Pos" from="1" to="#Len(Arguments.Input)#">
<cfset Total += 26^(Pos-1) * ( Asc( UCase( Mid(Arguments.Input,Pos,1) ) ) - 64 ) />
</cfloop>
<cfreturn Total />
</cffunction>
<cfoutput>
#ColToNum('AABCCE')#
</cfoutput>
А поскольку я в странном настроении, вот версия CFScript:
function ColToNum ( Input )
{
var Total = 0;
for ( var Pos = 1 ; Pos <= Len(Arguments.Input) ; Pos++ )
{
Total += 26^(Pos-1) * ( Asc( UCase( Mid(Arguments.Input,Pos,1) ) ) - 64 );
}
return Total;
}
WriteOutput( ColToNum('AABCCE') );
Предполагается, что столбец A = 1
int GetColumnNumber(string columnName)
{
int sum = 0;
int exponent = 0;
for(int i = columnName.Length - 1; i>=0; i--)
{
sum += (columnName[i] - 'A' + 1) * (GetPower(26, exponent));
exponent++;
}
return sum;
}
int GetPower(int number, int exponent)
{
int power = 1;
for(int i=0; i<exponent; i++)
power *= number;
return power;
}
Ха-ха - написал это уже в нашей базе кода - примерно в 3 разных раза: (
%% @doc Convert an string to a decimal integer
%% @spec b26_to_i(string()) -> integer()
b26_to_i(List) when is_list(List) ->
b26_to_i(string:to_lower(lists:reverse(List)),0,0).
%% private functions
b26_to_i([], _Power, Value) ->
Value;
b26_to_i([H|T],Power,Value)->
NewValue = case (H > 96) andalso (H < 123) of
true ->
round((H - 96) * math:pow(26, Power));
_ ->
exit([H | T] ++ " is not a valid base 26 number")
end,
b26_to_i(T, Power + 1, NewValue + Value).
Загадка в том, что это на самом деле не является представлением числа в Base26 (мы лжем себе в названии нашей функции здесь), потому что в нем нет 0.
Последовательность: A, B, C ... Z, AA, AB, AC
, а не: A, B, C ... Z, BA, BB, BC
(язык Erlang, mais oui).
Считать имя столбца из STDIN и распечатать его соответствующий номер:
perl -le '$x = $x * 26 - 64 + ord for <> =~ /./g; print $x'
Предостережения: Предполагается ASCII.
РЕДАКТИРОВАТЬ: Заменить "
на '
, чтобы ваша оболочка не интерполировала $ x
в строке.
Common Lisp:
(defun excel->number (string)
"Converts an Excel column name to a column number."
(reduce (lambda (a b) (+ (* a 26) b))
string
:key (lambda (x) (- (char-int x) 64))))
edit: the inverse operation:
(defun number->excel (number &optional acc)
"Converts a column number to Excel column name."
(if (zerop number)
(concatenate 'string acc)
(multiple-value-bind (rest current) (floor number 26)
(if (zerop current)
(number->excel (- rest 1) (cons #\Z acc))
(number->excel rest (cons (code-char (+ current 64)) acc))))))
Это в основном число в базе 26, с той разницей, что число не использует 0-9, а затем буквы, но только буквы.
Помогает ли это думать о строке как об обратном номеру столбца в базе 26 с цифрами, представленными A, B, ... Z?
Эта версия является чисто функциональной и допускает альтернативные "кодовые" последовательности, например, если вы хотели использовать только буквы от «A» до «C». В Scala по предложению dcsobral.
def columnNumber(name: String) = {
val code = 'A' to 'Z'
name.foldLeft(0) { (sum, letter) =>
(sum * code.length) + (code.indexOf(letter) + 1)
}
}
Caveat: both of these versions assume only uppercase letters A to Z. Anything else causes a miscalculation. It wouldn't be hard to add a bit of error checking and/or uppercasing to improve them.
Scala
def excel2Number(excel : String) : Int =
(0 /: excel) ((accum, ch) => accum * 26 + ch - 'A' + 1)
Haskell
excel2Number :: String -> Int
excel2Number = flip foldl 0 $ \accum ch -> accum * 26 + fromEnum ch - fromEnum 'A' + 1
You can do this in C like this:
unsigned int coltonum(char * string)
{
unsigned result = 0;
char ch;
while(ch = *string++)
result = result * 26 + ch - 'A' + 1;
return result;
}
No error checking, only works for upper case strings, string must be null terminated.
Sounds like a standard reduce to me:
Python:
def excel2num(x):
return reduce(lambda s,a:s*26+ord(a)-ord('A')+1, x, 0)
C#:
int ExcelToNumber(string x) {
return x.Aggregate(0, (s, c) => s * 26 + c - 'A' + 1 );
}
Получить номер столбца из его имени
Java:
public int getColNum (String colName) {
//remove any whitespace
colName = colName.trim();
StringBuffer buff = new StringBuffer(colName);
//string to lower case, reverse then place in char array
char chars[] = buff.reverse().toString().toLowerCase().toCharArray();
int retVal=0, multiplier=0;
for(int i = 0; i < chars.length;i++){
//retrieve ascii value of character, subtract 96 so number corresponds to place in alphabet. ascii 'a' = 97
multiplier = (int)chars[i]-96;
//mult the number by 26^(position in array)
retVal += multiplier * Math.pow(26, i);
}
return retVal;
}
Получить имя столбца из int в Java ( подробнее здесь ):
public String getColName (int colNum) {
String res = "";
int quot = colNum;
int rem;
/*1. Subtract one from number.
*2. Save the mod 26 value.
*3. Divide the number by 26, save result.
*4. Convert the remainder to a letter.
*5. Repeat until the number is zero.
*6. Return that bitch...
*/
while(quot > 0)
{
quot = quot - 1;
rem = quot % 26;
quot = quot / 26;
//cast to a char and add to the beginning of the string
//add 97 to convert to the correct ascii number
res = (char)(rem+97) + res;
}
return res;
}