注册 登录
编程论坛 VFP论坛

EXCEL中如何求得单元格所在列的标题字母

wengjl 发布于 2020-08-27 11:31, 5699 次点击
用上OFFICE2007后,从第703列开始,EXCEL的列标题有3个字母组成(从 AAA 到 XFD 止,相应的单元格表示为:AAA1,AAA2,……)。

在VFP对EXCEL的操作中,如:测得最后一个数据所在列为 1378,对应的列标号是 AZZ。  对应单元格就为:AZZ1,AZZ,……,AZZn,……

请问 VF 如何用 1378 转换出 AZZ 来?
22 回复
#2
吹水佬2020-08-27 12:01
只有本站会员才能查看附件,请 登录

程序代码:
Private Sub CommandButton1_Click()
    Dim nCol As Integer
    nCol = InputBox("输入列号")
    cCol = Replace(Cells(1, nCol).Address(False, False), "1", "")
    MsgBox ("列号" & nCol & "转为对应的字母: " & cCol)
End Sub
#3
sdta2020-08-27 12:28
VFP表最多可用列也就254列,不管什么版本的EXCEL,VFP也只能转换254列,知道254列的转换方法就可以了。
EXCEL2007可用行1048576,可用列16384

[此贴子已经被作者于2020-8-27 12:30编辑过]

#4
wengjl2020-08-27 13:09
@吹水佬
VFP的代码如何写?
#5
wengjl2020-08-27 13:15
以下是引用sdta在2020-8-27 12:28:54的发言:

VFP表最多可用列也就254列,不管什么版本的EXCEL,VFP也只能转换254列,知道254列的转换方法就可以了。
EXCEL2007可用行1048576,可用列16384


您说得非常正确。 只是作为技术,还是值得钻研的
#6
wengjl2020-08-27 13:34
以下是引用吹水佬在2020-8-27 12:01:26的发言:


Private Sub CommandButton1_Click()
    Dim nCol As Integer
    nCol = InputBox("输入列号")
    cCol = Replace(Cells(1, nCol).Address(False, False), "1", "")
    MsgBox ("列号" & nCol & "转为对应的字母: " & cCol)
End Sub

你是VFP高手,EXCEL也是个高手
#7
厨师王德榜2020-08-27 13:59
有两种方式,
一、是利用excel自身的单元格对象,返回其address属性即可,这种方法必须要求用户电脑上安装有excel
二、纯数学方法,也就是你所说的“做为技术来钻研”。以前用VBA写过一个函数,供你参考:
程序代码:
Function GetColumName(lie0 As Integer) As String
'根据列序号,返回列字母名,本模块是数学方式计算。
'WDB  [2014.10.11]
Dim str1 As String, lie1, lie2, liew As Integer, iMsg As Integer
Const STR0 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If lie0 > 0 And lie0 <= 16384 And lie0 - Int(lie0) = 0 Then
    lie0 = Int(lie0)
    '最大支持:XFD=16384
    Select Case lie0
        Case Is <= 26
            
'1位字母
            str1 = Mid(STR0, lie0, 1)
        Case 27 To 702
            '2位字母
            lie2 = (lie0 - 1) \ 26
            liew = IIf(lie0 Mod 26 = 0, 26, lie0 Mod 26)
            str1 = Mid(STR0, lie2, 1) & Mid(STR0, liew, 1)
        Case Is > 702
            
'3位字母
            lie1 = Int((Int((lie0 - 1) / 26) - 1) / 26) Mod 26
            lie2 = IIf(Int((lie0 - 1) / 26) Mod 26 = 0, 26, Int((lie0 - 1) / 26) Mod 26)
            liew = IIf(lie0 Mod 26 = 0, 26, lie0 Mod 26)
            str1 = Mid(STR0, lie1, 1) & Mid(STR0, lie2, 1) & Mid(STR0, liew, 1)
    End Select
Else
    str1 = "数值不是合理值(负数、小数或>16384)!"
End If
GetColumName = str1
End Function


注意,代码是VBA写的,不过不复杂,转成VFP代码不难。
#8
wengjl2020-08-27 14:04
以下是引用厨师王德榜在2020-8-27 13:59:04的发言:

有两种方式,
一、是利用excel自身的单元格对象,返回其address属性即可,这种方法必须要求用户电脑上安装有excel
二、纯数学方法,也就是你所说的“做为技术来钻研”。以前用VBA写过一个函数,供你参考:
Function GetColumName(lie0 As Integer) As String
'根据列序号,返回列字母名,本模块是数学方式计算。
'WDB  [2014.10.11]
Dim str1 As String, lie1, lie2, liew As Integer, iMsg As Integer
Const STR0 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If lie0 > 0 And lie0 <= 16384 And lie0 - Int(lie0) = 0 Then
    lie0 = Int(lie0)
    '最大支持:XFD=16384
    Select Case lie0
        Case Is <= 26
            '1位字母
            str1 = Mid(STR0, lie0, 1)
        Case 27 To 702
            '2位字母
            lie2 = (lie0 - 1) \ 26
            liew = IIf(lie0 Mod 26 = 0, 26, lie0 Mod 26)
            str1 = Mid(STR0, lie2, 1) & Mid(STR0, liew, 1)
        Case Is > 702
            '3位字母
            lie1 = Int((Int((lie0 - 1) / 26) - 1) / 26) Mod 26
            lie2 = IIf(Int((lie0 - 1) / 26) Mod 26 = 0, 26, Int((lie0 - 1) / 26) Mod 26)
            liew = IIf(lie0 Mod 26 = 0, 26, lie0 Mod 26)
            str1 = Mid(STR0, lie1, 1) & Mid(STR0, lie2, 1) & Mid(STR0, liew, 1)
    End Select
Else
    str1 = "数值不是合理值(负数、小数或>16384)!"
End If
GetColumName = str1
End Function

注意,代码是VBA写的,不过不复杂,转成VFP代码不难。

谢谢!
#9
schtg2020-08-27 17:00
回复 7楼 厨师王德榜
好用,谢谢分享!
只有本站会员才能查看附件,请 登录
#10
sdta2020-08-28 06:17
* EXCEL2007 列号转列标(请大家测试)
程序代码:
CREATE CURSOR T1 (xh n(5), zm c(3))
FOR lnj = 1 TO 16384
    INSERT INTO t1 VALUES (lnj, SZTOZM(lnj))
ENDFOR
BROWSE
FUNCTION SZTOZM
    PARAMETERS ln
    IF NOT BETWEEN(ln, 1, 16384)
        RETURN ""
    ENDIF
    LOCAL ln0, ln1, ln2, ln3
    STORE 0 TO ln0, ln1, ln2, ln3
    ln0 = CEILING(ln / 26) - 1
    ln1 = IIF(ln0 > 26, CEILING(ln0 / 26) - 1, 0)
    ln2 = IIF(ln0 > 26, ICASE(MOD(ln0, 26) = 0, 26, MOD(ln0, 26)), ln0)
    ln3 = IIF(MOD(ln, 26) = 0, 26, MOD(ln, 26))
    RETURN IIF(ln1 = 0, "", CHR(ln1 + 64)) + IIF(ln2 = 0, "", CHR(ln2 + 64)) + CHR(ln3 + 64)
ENDFUNC
RETURN
#11
schtg2020-08-28 07:17
回复 10楼 sdta
好用,谢谢!
#12
吹水佬2020-08-28 09:34
以下是引用wengjl在2020-8-27 13:09:18的发言:

@吹水佬
VFP的代码如何写?

有用的就一句,加个EXCEL对象就是了。
也试写个VFP代码硬算:
只有本站会员才能查看附件,请 登录

程序代码:
MESSAGEBOX(GetColumName(1378))
RETURN

FUNCTION GetColumName(sz)
    LOCAL m,zm
    zm = ""
    DO WHILE sz > 0
        m = sz%26
        sz = INT(sz/26)
        IF m==0
            m = 26
            sz = sz-1
        ENDIF
        zm = CHR(m+64) + zm
    ENDDO
    RETURN zm
ENDFUNC
#13
wengjl2020-08-28 10:09
向大佬们汇报一下:
这是在发贴前,花了2天时间弄好的代码。但感觉太繁,又想不出简化的办法,所以发贴了
程序代码:
SET SAFETY OFF
CREATE TABLE CS (id n(6),zdmzm c(3))
CLOSE DATABASES
SELECT 0
USE cs ALIAS bmk
ZAP
_x=16384
FOR _i=1 TO _x
  DO CASE  
    CASE _i<=26                      &&& 一个字母标号
      dygz=CHR(64+_i)
      
    CASE _i>=27 AND _i<=702          &&& 二个字母标号
      IF  MOD(_i,26)=0
        _zm1=CHR(64+INT(_i/26)-1)
        _zm2=CHR(64+MOD(_i,26)+26)
        dygz= _zm1+_zm2
      ELSE
        _zm1=CHR(64+INT(_i/26))
        _zm2=CHR(64+MOD(_i,26))
        dygz=_zm1+_zm2
      ENDIF
      
    CASE _i>=703                     &&& 三个字母标号
      IF MOD(_i,676)=0
        _zm1=CHR(64+INT(_i/676)-1)
        _zm2=CHR(64+MOD(INT(_i/26),26)+25)   
        _zm3=CHR(64+MOD(_i,26)+26)   
        dygz= _zm1+_zm2+_zm3
      ELSE
        IF MOD(_i,26)=0 AND MOD(INT(_i/26),26)<>0         
          _zm1=CHR(64+int(INT(_i/26)/26))
          _zm2=CHR(64+MOD(INT(_i/26),26)-1)
          _zm3=CHR(64+MOD(_i,26)+26)   
          IF  MOD(INT(_i/26),26)=1
            _zm1=CHR(64+INT(INT(_i/26)/26)-1)
            _zm2=CHR(64+MOD(INT(_i/26),26)+25)
          ENDIF
          dygz= _zm1+_zm2+_zm3
        ELSE
          IF MOD(INT(_i/26),26)=0
            _zm1=CHR(64+INT((_i-26)/676))
            _zm2=CHR(64+MOD(INT(_i/26),26)+26)
            _zm3=CHR(64+MOD(_i,26))
            dygz= _zm1+_zm2+_zm3
          ELSE
            _zm1=CHR(64+INT((_i-26)/676))
            _zm2=CHR(64+MOD(INT(_i/26),26))
            _zm3=CHR(64+MOD(_i-26,26))
            dygz= _zm1+_zm2+_zm3   
          ENDIF
        ENDIF
      ENDIF
      
    OTHERWISE
      
  ENDCASE   
  SELECT bmk
  APPEND BLANK
  REPLACE zdmzm WITH dygz
ENDFOR
SELECT bmk
REPLACE id WITH RECNO() ALL
BROWSE

RETURN


**********************
以下是根据7楼王大厨的VBA改变的,具有可读性。他的精要点在于:1、准备了26个字母的文本字符串,2、在于 减1 后再除以26再取整的思维,3、遇到整除时,用IIF切换
程序代码:
SET SAFETY OFF
PUBLIC cTXT
CREATE TABLE CS (id n(6),zdmzm c(3))
CLOSE DATABASES
SELECT 0
USE cs ALIAS bmk
ZAP
cTXT="ABCDEFGHIJKLMNOPQRSTUVWXYZ"    &&& 思路决定出路,这一句定义非常重要,使得后面的代码简化了很多。
_x=16384                             &&& EXCEL2007 的表共有 16384 列
FOR _i=1 TO _x
  DO CASE  
    CASE _i<=26                      &&& 一个字母标号
      dygz=SUBSTR(cTXT,_i,1)
      
    CASE _i>=27 AND _i<=702          &&& 二个字母标号 
      _zm1=INT((_i-1)/26)            &&& 27-52,均为A,取cTXT中的第一个,为避开52/262,所以要 ( _i-1) / 26,整数部分
      _zm2=IIF(MOD(_i,26)=0,26,MOD(_i,26))    &&& 从27-52,除以26的余数为1-25和0,0时为最后一个字母,故用IIF来转换成26。
      dygz=SUBSTR(cTXT,_zm1,1)+SUBSTR(cTXT,_zm2,1)
      
    CASE _i>=703                     &&& 三个字母标号 
      _zm1=IIF(MOD(INT((INT((_i-1)/26)-1)/26),26)=0,26, MOD(INT((INT((_i-1)/26)-1)/26),26))
      _zm2=IIF(MOD(INT((_i-1)/26),26)=0,26,MOD(INT((_i-1)/26),26))
      _zm3=IIF(MOD(_i,26)=0,26,MOD(_i,26))   
      dygz=SUBSTR(cTXT,_zm1,1)+SUBSTR(cTXT,_zm2,1)+SUBSTR(cTXT,_zm3,1)
      
    OTHERWISE
      
  ENDCASE   
  SELECT bmk
  APPEND BLANK
  REPLACE zdmzm WITH dygz
ENDFOR
SELECT bmk
REPLACE id WITH RECNO() ALL  
BROWSE

RETURN
#14
schtg2020-08-28 11:26
好!都是大拿,谢谢分享!
#15
wengjl2020-08-28 15:39
这帖子的逆运算,可以用来计算几个字母组合的位次号

如:B为2号、BB为54号,BBB为1406号,BBBB为36558号,……
#16
sdta2020-08-29 10:02
回复 15楼 wengjl
想法是美好的,现实是残酷的!
#17
sdta2020-08-30 09:46
等级分排名最多12门科目
最大值:9999999999999998
#18
wengjl2020-08-31 08:14
逆向运算

MESSAGEBOX(GetColName("Xfd"))
RETURN

FUNCTION GetColName(sz)
    LOCAL m,zm
    zm = 0
    FOR nvar=1 TO LEN(sz)
       m=ASC(SUBSTR(UPPER(sz),nvar,1))-64
       zm=zm*26+m
    ENDFOR        
    RETURN zm
ENDFUNC
#19
sdta2020-09-02 07:30
回复 18楼 wengjl
假如有6门科目(等级分分别为AAAAAA-FFFFFF)
AAAAAA = 12356631
FFFFFF = 74139786
共有61783156种排列方式
但你现在只有1W名以内的学生,不知道你用这样的方法计算出来的位次(你说的位次应该是我们平时所说的名次吧)有什么意义
#20
wengjl2020-11-23 09:24
  发这个帖子最后实现的目标如下,是为了动态复制有数据的区域(win7.0+vfp8.0+office2007通过)

    ……
    Mx_UsedRange =Mx_excel.worksheets(Mx_SheetName).UsedRange
    Mx_rows=Mx_UsedRange.rows.count  
    Mx_cols=Mx_UsedRange.columns.count  
    IF Mx_cols<=26
        dygz=CHR(Mx_cols+64)+ALLTRIM(STR(Mx_rows))  
    ELSE
      IF MOD(Mx_cols,26)=0  
          dygz=CHR(64+INT(Mx_cols/26)-1)+CHR(64+MOD(Mx_cols,26)+26)+ALLTRIM(STR(Mx_rows))
      ELSE
         dygz=CHR(64+INT(Mx_cols/26))+CHR(64+MOD(Mx_cols,26))+ALLTRIM(STR(Mx_rows))
      ENDIF
    ENDIF
    Mx_excel.ActiveSheet.Range("A2:"+dygz).Copy
    ……
#21
sdta2021-03-20 21:59
以下是引用wengjl在2020-11-23 09:24:05的发言:

  发这个帖子最后实现的目标如下,是为了动态复制有数据的区域(win7.0+vfp8.0+office2007通过)

    ……
    Mx_UsedRange =Mx_excel.worksheets(Mx_SheetName).UsedRange
    Mx_rows=Mx_UsedRange.rows.count  
    Mx_cols=Mx_UsedRange.columns.count  
    IF Mx_cols<=26
        dygz=CHR(Mx_cols+64)+ALLTRIM(STR(Mx_rows))  
    ELSE
      IF MOD(Mx_cols,26)=0  
          dygz=CHR(64+INT(Mx_cols/26)-1)+CHR(64+MOD(Mx_cols,26)+26)+ALLTRIM(STR(Mx_rows))
      ELSE
         dygz=CHR(64+INT(Mx_cols/26))+CHR(64+MOD(Mx_cols,26))+ALLTRIM(STR(Mx_rows))
      ENDIF
    ENDIF
    Mx_excel.ActiveSheet.Range("A2:"+dygz).Copy
    ……

EXCEL中相获取指定区域的代码:
多个单元格:cells(左上角行,左上角列).Resize(行数,列数)
#22
wengjl2021-03-22 15:18
谢谢!又学一招
#23
sxcl78992024-06-17 15:16
前几天使用一款小众软件操作数据库, 希望在导入数据前先调用vfp对excel进行拆分或合并,也是遇到了楼主这个问题,我把自己的代码放上来,请各位前辈指正:
clear
mycm=16384
c0=""
c1="A"
c2="B"
c3="C"
c4="D"
c5="E"
c6="F"
c7="G"
c8="H"
c9="I"
c10="J"
c11="K"
c12="L"
c13="M"
c14="N"
c15="O"
c16="P"
c17="Q"
c18="R"
c19="S"
c20="T"
c21="U"
c22="V"
c23="W"
c24="X"
c25="Y"
c26="Z"

qz1=INT(mycm/676)
qy1=mycm%676

IF qz1>0
    IF qy1=0
        qz1=qz1-1
        qy1=qy1+676
    ENDIF
ENDIF
qz2=INT(qy1/26)
qy2=qy1%26
IF qz2>0
    IF qy2=0
        qz2=qz2-1
        qy2=qy2+26
    ENDIF
ENDIF
cm1="c"+ALLTRIM(STR(qz1))
cm2="c"+ALLTRIM(STR(qz2))
cm3="c"+ALLTRIM(STR(qy2))
cm=&cm1+&cm2+&cm3
?cm
1