Converti l'indice della colonna nella lettera della colonna corrispondente


88

Devo convertire un indice di colonna di un foglio di lavoro di Google nel valore della lettera corrispondente, ad esempio, dato un foglio di calcolo:

inserisci qui la descrizione dell'immagine

Ho bisogno di farlo (questa funzione ovviamente non esiste, è un esempio):

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

Ora, non ricordo esattamente se l'indice parte da 0o da 1, comunque il concetto dovrebbe essere chiaro.

Non ho trovato nulla su questo nella documentazione del gas .. sono cieco? Qualche idea?

Grazie


17
Come mai questo non è integrato ??
Cyril Duchon-Doris


1
X = (n) => (a = Math.floor (n / 26))> = 0? X (a-1) + String.fromCharCode (65+ (n% 26)): '';
Pascal DeMilly

Risposte:


158

Li ho scritti qualche tempo fa per vari scopi (restituirà i nomi delle colonne a doppia lettera per i numeri di colonna> 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
Il massimo è inferiore a ZZ?
Old Geezer

1
Proprio usato questo per numeri di colonna incremento: var column = letterToColumn(AA); columnToLetter(column + 1);. Potrebbe essere utile a qualcuno.
joshfindit

1
Suggerisco di passare column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);a column += (letter.toUpperCase().charCodeAt(i) - 64) * Math.pow(26, length - i - 1);per farlo funzionare se lettercontiene lettere minuscole, altrimenti averrà visualizzato al 33posto di1
tukusejssirs

fwiw - questa è stata un'intervista Q per me in uno dei grandi Cos
Taylor Halliday,

Penso String.fromCharCodeche non funzioni su Apps Script
c-an

70

Funziona bene

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

anche per colonne oltre Z.

Demo di funzione

Sostituisci semplicemente COLUMN()con il numero della tua colonna. Il valore di ROW()non importa.


4
stai usando formule, non GAS
BeNdErR

11
Funziona davvero bene. Anche se questo non utilizza GAS (con cui viene taggata la domanda), le funzioni integrate sono quasi sempre preferibili dato che non hanno bisogno di essere scritte e, secondo la mia esperienza, funzionano molto più velocemente.
kevinmicke

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

Questo prende la tua cella, ottiene il suo indirizzo come ad esempio C1 e rimuove l '"1".

inserisci qui la descrizione dell'immagine

Come funziona

  • COLUMN() dà il numero della colonna della cella.
  • ADDRESS(1, ..., <format>)fornisce un indirizzo di una cella, nel formato specificato dal <format>parametro. 4indica l'indirizzo che conosci, ad es C1.
  • Infine, SUBSTITUTE(..., "1", "")sostituisce la 1nell'indirizzo C1, quindi ti rimane la lettera della colonna.

3
Questa è una soluzione elegante, mi piace di più. Non sono sicuro del motivo per cui non ha più voti positivi.
singolarità

1
Ho ricevuto questo durante il tentativo: screencast.com/t/Jmc8L9W5LB . L'ho capito. L'ho risolto sostituendo tutte le virgole con punti e virgola. Questo è probabilmente un problema di localizzazione
David

@ David, per me funziona con le virgole. Forse è a causa delle impostazioni locali.
Ondra Žižka

1
La domanda sta chiedendo una funzione da utilizzare negli script mentre questa soluzione fornisce una formula da utilizzare nelle celle.
markshep

Soluzione davvero elegante.
Gabz

23

Funziona sugli intervalli A-Z

=char(64+column())


4
Questo è abbastanza complicato per le persone che non provengono da un background di programmazione e non lavoreranno su colonne oltre "Z" (cioè "AA") ma mi piace comunque perché è il calcolo più breve e veloce (ad es. Potresti avere 1.000 s di questi che vanno in una volta senza che il tuo computer sudi).
Dave

21

Non c'è bisogno di reinventare la ruota qui, usa invece la gamma 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"



3

Aggiungendo alla risposta di @ SauloAlessandre, questo funzionerà per le colonne dalla A alla ZZ.

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

Mi piacciono le risposte di @wronex e @Ondra Žižka. Tuttavia, mi piace molto la semplicità della risposta di @ SauloAlessandre.

Quindi, ho appena aggiunto il codice ovvio per consentire alla risposta di @ SauloAlessandre di funzionare per fogli di calcolo più ampi.

Come @Dave ha menzionato nel suo commento, aiuta avere un background di programmazione, in particolare uno in C dove abbiamo aggiunto il valore esadecimale di "A" a un numero per ottenere l'ennesima lettera dell'alfabeto come modello standard.

Risposta aggiornata per rilevare l'errore segnalato da @Sangbok Lee. Grazie!


1
@invece di Zquando viene utilizzato in Zcolonna.
Sangbok Lee

1
@Sangbok è corretto! Questo è stato aggiornato e testato per le colonne Z, AA, AZ, BB. Credo che funzionerà tramite ZZ.
Giardiniere

2

Stavo cercando una soluzione in PHP. Forse questo aiuterà qualcuno.

<?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'));

Produzione:

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

Stavo anche cercando una versione di Python qui è la mia che è stata testata su 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''
Ondra Žižka

Ad ogni modo, se non mi sbaglio, questo è base26. Tricky: il prossimo Zdovrebbe essere AA. Questo dà BA.
Ondra Žižka

1
La tua versione è quasi corretta, penso che dovrebbe essere: X=lambda n:~int(n) and X(int(n/26)-1)+chr(65+n%26)or''
hum3

Santo cielo, quella è stata una straordinaria funzione lambda che hai ottenuto, hum3. Grazie!
ViggoTW

Grazie ma stavo solo eseguendo il debug della soluzione di Ondra.
hum3

1

Un commento alla mia risposta dice che volevi una funzione di script per questo. Va bene, eccoci qui:

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('');
}

Questo può gestire qualsiasi numero che JS può gestire, credo.

Spiegazione:

Poiché non è base26, è necessario sottrarre l'ordine dei tempi base per ogni simbolo aggiuntivo ("cifra"). Quindi prima contiamo l'ordine del numero risultante e allo stesso tempo contiamo il numero da sottrarre. E poi lo convertiamo in base 26 e lo sottraiamo, quindi spostiamo i simboli su A-Zinvece di 0-P.

Comunque, questa domanda si sta trasformando in un codice da golf :)


0

Questo ti coprirà fino alla colonna 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

Modo semplice attraverso le funzioni di Google Sheet, dalla A alla Z.

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

È un modo complicato attraverso le funzioni di Google Sheet, ma è anche più di AA.

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

0

Una funzione per convertire un indice di colonna in combinazioni di lettere, in modo ricorsivo:

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

POI Java Apache

String columnLetter = CellReference.convertNumToColString(columnNumber);

-1

Ecco una versione generale scritta in Scala. È per un indice di colonna che inizia da 0 (è semplice da modificare per un indice che inizia da 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)
}

-1

In 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

Ecco una versione indicizzata zero (in Python):

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

Non è questo. La domanda non è di base26. Inizialmente sono stato anche attratto da quello :)
Ondra Žižka
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.