Преобразование индекса столбца в соответствующую букву столбца


86

Мне нужно преобразовать индекс столбца Google Spreadsheet в соответствующее буквенное значение, например, для электронной таблицы:

введите описание изображения здесь

Мне нужно это сделать (такой функции явно не существует, это пример):

getColumnLetterByIndex(4);  // this should return "D"
getColumnLetterByIndex(1);  // this should return "A"
getColumnLetterByIndex(6);  // this should return "F"

Я не помню точно, начинается ли индекс с 0или с 1, в любом случае концепция должна быть ясной.

Я не нашел ничего об этом в документации по газу .. я слепой? Любая идея?

Спасибо


14
Почему это не встроено ??
Сирил Дюшон-Дорис



1
X = (n) => (a = Math.floor (n / 26))> = 0? X (a-1) + String.fromCharCode (65+ (n% 26)): '';
Паскаль ДеМилли 07

Ответы:


154

Я написал это некоторое время назад для различных целей (верну двухбуквенные имена столбцов для номеров столбцов> 26):

function columnToLetter(column)
{
  var temp, letter = '';
  while (column > 0)
  {
    temp = (column - 1) % 26;
    letter = String.fromCharCode(temp + 65) + letter;
    column = (column - temp - 1) / 26;
  }
  return letter;
}

function letterToColumn(letter)
{
  var column = 0, length = letter.length;
  for (var i = 0; i < length; i++)
  {
    column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
  }
  return column;
}

1
Максимум меньше ZZ?
Old Geezer

1
Просто использовал это для увеличения числа столбцов: var column = letterToColumn(AA); columnToLetter(column + 1);. Может быть кому-то полезно.
joshfindit

1
Я предлагаю изменить column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);на, column += (letter.toUpperCase().charCodeAt(i) - 64) * Math.pow(26, length - i - 1);чтобы заставить его работать, если он letterсодержит строчные буквы, иначе aон будет выводить 33вместо1
tukusejssirs

fwiw - это было интервью Q для меня на одном из больших Cos
Тейлор Холлидей

Я думаю, String.fromCharCodeчто не работает в Apps Script
c-an

69

Это хорошо работает

=REGEXEXTRACT(ADDRESS(ROW(); COLUMN()); "[A-Z]+")

даже для столбцов за Z.

Демонстрация функции

Просто замените его COLUMN()номером столбца. Значение ROW()не имеет значения.


4
вы используете формулы, а не ГАЗ
BeNdErR 02

11
Это действительно хорошо работает. Несмотря на то, что здесь не используется GAS (которым помечен вопрос), встроенные функции почти всегда предпочтительнее, поскольку их вообще не нужно писать и, по моему опыту, они работают значительно быстрее.
kevinmicke

37
=SUBSTITUTE(ADDRESS(1,COLUMN(),4), "1", "")

Это берет вашу ячейку, получает ее адрес, например, C1, и удаляет "1".

введите описание изображения здесь

Как это работает

  • COLUMN() дает номер столбца ячейки.
  • ADDRESS(1, ..., <format>)дает адрес ячейки в формате, заданном <format>параметром. 4означает адрес, который вы знаете - например C1.
    • Строка здесь не имеет значения, поэтому мы используем 1.
    • См. ADDRESSДокументы
  • Наконец, SUBSTITUTE(..., "1", "")заменяет 1в адресе C1, так что остается буква столбца.

3
Это элегантное решение - оно мне нравится больше всего. Не уверен, почему он не набирает больше голосов.
сингулярность

1
Получил при попытке: screencast.com/t/Jmc8L9W5LB . Я понял это. Решил, заменив все запятые на точки с запятой. Вероятно, это проблема локализации,
Дэвид,

@ Дэвид, у меня с запятыми работает. Может это из-за настроек локали.
Ондра Жижка

1
Вопрос запрашивает функцию для использования в скриптах, тогда как это решение дает формулу для использования в ячейках.
markhep

Действительно элегантное решение.
Gabz

23

Это работает на диапазонах A-Z

=char(64+column())


3
Это довольно сложно для людей, которые не имеют опыта программирования и не будут работать со столбцами за пределами "Z" (т.е. "AA"), но мне это все равно нравится, потому что это самый короткий и быстрый расчет (например, у вас может быть 1000 из них сразу же, даже если ваш компьютер не вспотел).
Дэйв

21

Здесь не нужно изобретать велосипед, используйте вместо этого гамму GAS:

 var column_index = 1; // your column to resolve
 
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var sheet = ss.getSheets()[0];
 var range = sheet.getRange(1, column_index, 1, 1);

 Logger.log(range.getA1Notation().match(/([A-Z]+)/)[0]); // Logs "A"


6

В javascript:

X = (n) => (a=Math.floor(n/26)) >= 0 ? X(a-1) + String.fromCharCode(65+(n%26)) : '';
console.assert (X(0) == 'A')
console.assert (X(25) == 'Z')
console.assert (X(26) == 'AA')
console.assert (X(51) == 'AZ')
console.assert (X(52) == 'BA')

Хотелось бы, чтобы он работал в скриптах Google, но замечательный маленький фрагмент кода.
Джампаоло

1
@Giam Работает в скрипте приложений. Это должен быть принятый ответ
TheMaster


3

Добавив к ответу @SauloAlessandre, это будет работать для столбцов от A до ZZ.

=if(column() >26,char(64+(column()-1)/26),) & char(65 + mod(column()-1,26))

Мне нравятся ответы @wronex и @Ondra ižka. Однако мне очень нравится простота ответа @SauloAlessandre.

Итак, я просто добавил очевидный код, чтобы позволить ответу @SauloAlessandre работать с более широкими таблицами.

Как отметил @Dave в своем комментарии, это действительно помогает иметь опыт программирования, особенно в C, где мы добавили шестнадцатеричное значение 'A' к числу, чтобы получить n-ю букву алфавита в качестве стандартного шаблона.

Ответ обновлен, чтобы уловить ошибку, указанную @Sangbok Lee. Спасибо!


1
Он дает @вместо того, Zкогда используется в Zстолбце.
Сангбок Ли

1
@Sangbok правильный! Это было обновлено и протестировано для столбцов Z, AA, AZ, BB. Верю через ZZ заработает.
Gardener

2

Я также искал версию Python, вот моя, которая была протестирована на Python 3.6.

def columnToLetter(column):
    character = chr(ord('A') + column % 26)
    remainder = column // 26
    if column >= 26:
        return columnToLetter(remainder-1) + character
    else:
        return character

1
X=lambda n:~n and X(n/26-1)+chr(65+n%26)or''
Ондра Жижка

Во всяком случае, если не ошибаюсь, это base26. Сложно: рядом Zдолжно быть AA. Это дает БА.
Ондра Жижка

1
Ваша версия почти X=lambda n:~int(n) and X(int(n/26)-1)+chr(65+n%26)or''
верна

Черт возьми, это была потрясающая лямбда-функция, hum3. Благодарность!
ViggoTW

Спасибо, но я просто отлаживал решение Ондры.
hum3

2

Искал решение на PHP. Может это кому-то поможет.

<?php

$numberToLetter = function(int $number)
{
    if ($number <= 0) return null;

    $temp; $letter = '';
    while ($number > 0) {
        $temp = ($number - 1) % 26;
        $letter = chr($temp + 65) . $letter;
        $number = ($number - $temp - 1) / 26;
    }
    return $letter;
};

$letterToNumber = function(string $letters) {
    $letters = strtoupper($letters);
    $letters = preg_replace("/[^A-Z]/", '', $letters);

    $column = 0; 
    $length = strlen($letters);
    for ($i = 0; $i < $length; $i++) {
        $column += (ord($letters[$i]) - 64) * pow(26, $length - $i - 1);
    }
    return $column;
};

var_dump($numberToLetter(-1));
var_dump($numberToLetter(26));
var_dump($numberToLetter(27));
var_dump($numberToLetter(30));

var_dump($letterToNumber('-1A!'));
var_dump($letterToNumber('A'));
var_dump($letterToNumber('B'));
var_dump($letterToNumber('Y'));
var_dump($letterToNumber('Z'));
var_dump($letterToNumber('AA'));
var_dump($letterToNumber('AB'));

Выход:

NULL
string(1) "Z"
string(2) "AA"
string(2) "AD"
int(1)
int(1)
int(2)
int(25)
int(26)
int(27)
int(28)

1

В комментарии к моему ответу говорится, что вам нужна функция сценария для этого. Хорошо, поехали:

function excelize(colNum) {
    var order = 1, sub = 0, divTmp = colNum;
    do {
        divTmp -= order; sub += order; order *= 26;
        divTmp = (divTmp - (divTmp % 26)) / 26;
    } while(divTmp > 0);

    var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
    var tr = c => symbols[symbols.indexOf(c)+10];
    return Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
}

Я думаю, это может обработать любое количество, которое может обработать JS.

Пояснение:

Поскольку это не base26, нам нужно вычесть порядок базового времени для каждого дополнительного символа («цифры»). Итак, сначала мы подсчитываем порядок полученного числа и в то же время подсчитываем число для вычитания. Затем мы преобразуем его в основание 26 и вычитаем из него, а затем сдвигаем символы на A-Zвместо 0-P.

Так или иначе, этот вопрос превращается в кодовый гольф :)



0

Это охватит вас до столбца AZ:

=iferror(if(match(A2,$A$1:$AZ$1,0)<27,char(64+(match(A2,$A$1:$AZ$1,0))),concatenate("A",char(38+(match(A2,$A$1:$AZ$1,0))))),"No match")

0

Вот общая версия, написанная на Scala. Это для индекса столбца, начинающегося с 0 (его просто изменить для начала индекса с 1):

def indexToColumnBase(n: Int, base: Int): String = {
  require(n >= 0, s"Index is non-negative, n = $n")
  require(2 <= base && base <= 26, s"Base in range 2...26, base = $base")

  def digitFromZeroToLetter(n: BigInt): String =
    ('A' + n.toInt).toChar.toString

  def digitFromOneToLetter(n: BigInt): String =
    ('A' - 1 + n.toInt).toChar.toString

  def lhsConvert(n: Int): String = {
    val q0: Int = n / base
    val r0: Int = n % base

    val q1 = if (r0 == 0) (n - base) / base else q0
    val r1 = if (r0 == 0) base else r0

    if (q1 == 0)
      digitFromOneToLetter(r1)
    else
      lhsConvert(q1) + digitFromOneToLetter(r1)
  }

  val q: Int = n / base
  val r: Int = n % base

  if (q == 0)
    digitFromZeroToLetter(r)
  else
    lhsConvert(q) + digitFromZeroToLetter(r)
}

def indexToColumnAtoZ(n: Int): String = {
  val AtoZBase = 26
  indexToColumnBase(n, AtoZBase)
}

0

Простой способ использования функций Google Sheet, от А до Я.

=column(B2) : value is 2
=address(1, column(B2)) : value is $B$1
=mid(address(1, column(B2)),2,1) : value is B

Это сложный способ использования функций Google Sheet, но это также больше, чем AA.

=mid(address(1, column(AB3)),2,len(address(1, column(AB3)))-3) : value is AB

0

Функция для рекурсивного преобразования индекса столбца в комбинации букв:

function lettersFromIndex(index, curResult, i) {

  if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
  if (curResult == undefined) curResult = "";

  var factor = Math.floor(index / Math.pow(26, i)); //for the order of magnitude 26^i

  if (factor > 0 && i > 0) {
    curResult += String.fromCharCode(64 + factor);
    curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);

  } else if (factor == 0 && i > 0) {
    curResult = lettersFromIndex(index, curResult, i - 1);

  } else {
    curResult += String.fromCharCode(64 + index % 26);

  }
  return curResult;
}



-1

В PowerShell:

function convert-IndexToColumn
{
    Param
    (
        [Parameter(Mandatory)]
        [int]$col
    )
    "$(if($col -gt 26){[char][int][math]::Floor(64+($col-1)/26)})$([char](65 + (($col-1) % 26)))"
}


-2

Вот версия с нулевым индексом (на Python):

letters = []
while column >= 0:
    letters.append(string.ascii_uppercase[column % 26])
    column = column // 26 - 1
return ''.join(reversed(letters))

Это не то. Вопрос не в базе26. Я тоже изначально был втянут в это :)
Ондра Жижка
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.