VBA将Excel样式列名称(带有52个字符集)转换为原始编号

时间:2016-05-03 20:19:17

标签: c++ vba excel-vba excel

我有一个c ++程序,它接受一个整数并将其转换为小写和大写字母,类似于excel将列索引转换为列号但也包括小写字母的内容。

#include <string>
#include <iostream>
#include <climits>
using namespace std;
string ConvertNum(unsigned long v)
{
    char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    size_t const base = sizeof(digits) - 1;
    char result[sizeof(unsigned long)*CHAR_BIT + 1];
    char* current = result + sizeof(result);
    *--current = '\0';

    while (v != 0) {
        v--;
        *--current = digits[v % base];
        v /= base;
    }
    return current;
}

// for testing


int main()
{
    cout<< ConvertNum(705);

    return 0;
}

我需要vba函数将其反转回原始数字。我没有很多使用C ++的经验,所以我无法弄清楚在vba中反转这个的逻辑。任何人都可以帮忙。

更新1:我不需要编写代码,只需要一些逻辑帮助来反转它。我会尝试将逻辑转换为代码。

更新2:根据答案中提供的精彩解释和帮助,很明显代码没有将数字转换为通常的基数52,这是误导性的。所以我更改了功能名称,以消除未来读者的困惑。

2 个答案:

答案 0 :(得分:2)

编辑:通过下面描述的代码转换为十进制的字符串格式不是标准的base-52架构。架构不包括 0 或任何其他数字。因此,不应使用此代码将标准base-52值转换为decimal。

O.K。这是基于在长字符串中根据其位置转换单个字符。字符串是:

chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

InStr()函数告诉我们 A 位于 1 位置, Z 就位 26 a 位于 27 。所有字符都以相同的方式转换。

我使用的不是 Asc(),因为 Asc()在大写和小写字母之间有间隙。

最不重要的字符值乘以52 ^ 0左下一个字符的值乘以52 ^ 1
第三个字符的值乘以由52 ^ 3等代码:

Public Function deccimal(s As String) As Long
    Dim chSET As String, arr(1 To 52) As String
    Dim L As Long, i As Long, K As Long, CH As String

    chSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    deccimal = 0
    L = Len(s)
    K = 0
    For i = L To 1 Step -1
        CH = Mid(s, i, 1)
        deccimal = deccimal + InStr(1, chSET, CH) * (52 ^ K)
        K = K + 1
    Next i
End Function

一些例子:

enter image description here

<强> 注:

这不是通常编码碱基的方式。通常基数以 0 开头,并且在任何编码值的位置允许 0 。在我之前的所有 UDF()中,chSET中的第一个字符是 0 ,我必须使用{{ 1}}

答案 1 :(得分:2)

Gary的学生提供了一种简单易懂的方式来获取我所称的数字&#34; Excel风格基础52&#34;这就是你想要的。

然而,这与通常的基数52略有不同。我将尝试解释常规基数52及其转换的差异。可能有一种更简单的方法,但这是我能想到的最好的方法,也解释了您提供的代码。

作为示例:数字zz..zz表示常规基数52中的51 *(1 + 52 + 52 ^ 2 + ... 52 ^(n-1))和52 *(1 + 52 + 52 ^ Excel样式库52中的2 + ... 52 ^(n-1))因此Excel样式的数字越多,数字越少。 Here是基于位数的差异。这怎么可能?它使用前导零,因此1,01,001等都是不同的数字。为什么我们不这样做呢?它会破坏普通系统的简单算法。

我们不能在基数变化之后将所有数字移位一,我们不能在基数变化之前减去1来反击我们从1开始而不是0的事实.I&#39 ; ll概述了基数10的问题。如果我们使用Excel样式的基数10来对列进行编号,我们必须计算像&#34; 0,1,2,...,9,00,01 ,02,...&#34;。乍一看,看起来我们只需要移动数字,所以我们从1开始计数,但这只能达到第10个数字。

1  2 .. 10  11 .. 20  21  ..  99  100 .. 110  111 //normal counting
0  1 ..  9  00 .. 09  10  ..  88   89 ..  99  000 //excel style counting

你注意到每当我们添加一个新数字时,我们再次转移。为了解决这个问题,我们必须在计算每个数字之前进行1次移位,而不是在计算数字后移位。 (如果我们在52 ^ k,这只会产生影响)请注意,我们仍然将A分配给0,B分配给1等。

通常情况下,你要改变基础的方法是循环使用类似

的东西
nextDigit = x mod base //determining the last digit
x = x/base             //removing the last digit
//terminate if x = 0

但是现在它是

x = x - 1
nextDigit = x mod base
x = x/base
//terminate if x = 0

所以x先减1!我们快速检查x = 52:

常规基地52:

nextDigit = x mod 52 //52 mod 52 = 0 so the next digit is A
x = x/52 //x is now 1
//next iteration
nextDigit = x mod 52 //1 mod 52 = 1 so the next digit is B
x = x/52 //1/52 = 0 in integer arithmetic
//terminate because x = 0
//result is BA

Excel样式:

x = x-1 //x is now 51
nextDigit = x mod 52 //51 mod 52 = 51 so the next digit is z
x = x/52 //51/52 = 0 in integer arithmetic
//terminate because x=0
//result is z

有效!

第2部分:您的C ++代码

现在让我们阅读您的代码:

  • x % y表示x mod y

  • 使用整数进行计算时,结果将是一个整数,通过向下舍入来实现。因此39/10将产生3等。

    • x++++x都将x增加1.

您可以在其他语句中使用它来保存一行代码。 x++表示在评估语句后x递增,++x表示在评估语句之前递增

y=f(x++);

相同
y = f(x);
x = x + 1;

y=f(++x);

相同
x = x + 1; 
y = f(x);

这与--

的方式相同
  • Char* p创建指向char
  • 的指针

指针指向内存中的某个位置。如果更改指针,则指向其他位置。例如。执行p--将指针向左移动一个。要读取或写入在该位置保存的值,请使用*p。例如。 *p="a";&#34; a&#34;被写入p指向的内存位置。 *p--="a";&#34; a&#34;写入内存,但指针向后移动到左边,所以* p现在是&#34; a&#34;左边的内存中的任何内容。

  • 字符串只是char类型的数组。

字符串的结尾总是&#39; \ 0&#39;如果计算机读取一个字符串,它会继续,直到找到&#39; \ 0&#39;

希望能够理解代码。这是

#include <string>
#include <iostream>
#include <climits>
using namespace std;
string base52(unsigned long v)
{
    char const digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; //The digits. (Arrays start at 0)
    size_t const base = sizeof(digits) - 1; //The base, based on the digits that were given
    char result[sizeof(unsigned long)*CHAR_BIT + 1]; //The array that holds the answer 
        //sizeof(unsigned long)*CHAR_BIT is the number of bits of an unsigned long
        //which means it is the absolute longest that v can be in any base.
        //The +1 is to hold the terminating character '\0' 
    char* current = result + sizeof(result); //This is a pointer that is supposed to point to the next digit. It points to the first byte after the result array (because its start + length)
        //(i.e. it will go through the memory from high to low)
    *--current = '\0';  //The pointer gets moved one to the left (to the last char of result and the terminating char is added
        //the pointer has to be moved to the left first because it was actually pointing to the first byte after the result.

    while (v != 0) {  //loop until v is zero (until there are no more digits left.
        v--; //v = v - 1. This is the important part that does the 1 -> A part
        *--current = digits[v % base];  // the pointer is moved one to the left and the corresponding digit is saved
        v /= base; //the last digit is dropped
    }
    return current; //current is returned, which points at the last saved digit. The rest of the result array (before current) is not used.
}

// for testing


int main()
{
    cout<< base52(705);

    return 0;
}