Page 1 of 1

Text to XLSX

Posted: Sun Mar 26, 2017 9:37 am
by said
Hi,

Recently i needed to convert a text to xlsx .... so here is my work, this is a module that converts text files to xlsx files
Only text and numbers (no date, no time ...) and creates only sheet1 :D
It is quite basic and it seems to serve my needs very well :D feel free to use and please report any bug you might face ( i wont be surprised :mrgreen: )

Said

Code: Select all

; XLSX module
; mainly to write Text files as XLSX files, no charts, no pivot-tables, ....
; Only one sheet of data, only text and numbers!
; Mar-2017

DeclareModule XLSX
    
    Declare.i TextToXLSX(FileNameTxt.s, FileNameXLSX.s, ColSep.s = #TAB$)
    
EndDeclareModule

;-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;-......... CORE MODULE
;-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


Module XLSX
    
    EnableExplicit
    UseZipPacker()
    
    #Base26$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    Global  NewMap SharedStrings.s()
    Global  SharedStringsCount.i, LastCol.i, LastRow.i
    
    Structure TBigStr
        *Pointer
        CurOffset.i ; <= next offset (we write at that position at next append)
        ;    when < 0 then allocation (re-allocation) is no more possible!
    EndStructure
    
    Procedure   My_IsNumber(txt.s)
        ; sign +/- : is accepted at the begining or after e (begining <=> prv = 0)
        ; dot   .  : is accepted anywhere but once only
        ; exp   e  : is validated if preceeded by a digit and ( followed by a digit or followed by a sign digit)
        ; A valid number will have its ValD() correct
        ;
        Protected   cur.c, prv.c, *p.Character, i, n, nbr_dot, nbr_exp, vld_exp, nbr_dgt
        n = Len(txt)
        If n = 0 : ProcedureReturn #False : EndIf
        For i=1 To n
            prv = cur
            *p  = @txt + (i-1) * SizeOf(Character)
            cur = *p\c
            
            Select cur
                Case '+', '-'
                    If (prv <> 'e') And (prv <> 0) : ProcedureReturn #False : EndIf
                    
                Case '.'
                    nbr_dot + 1
                    If nbr_exp > 0  : ProcedureReturn #False : EndIf
                    
                Case 'e'
                    If (prv = '.') Or ((prv >= '0') And (prv <= '9'))
                        nbr_exp + 1
                        vld_exp = -1                        ; an 'e' has started
                    Else
                        ProcedureReturn #False
                    EndIf
                    
                Case '0' To '9'
                    If vld_exp = -1 : vld_exp + 1 : EndIf   ; closing started 'e' if any
                    nbr_dgt + 1
                Default
                    ProcedureReturn #False
            EndSelect
            If (nbr_dot > 1) Or (nbr_exp > 1) : ProcedureReturn #False : EndIf
        Next
        
        If vld_exp <> 0 : ProcedureReturn #False : EndIf
        If nbr_dgt <= 0 : ProcedureReturn #False : EndIf
        ProcedureReturn #True
        
    EndProcedure
    Procedure.s TrimZeros(txt.s)
        Protected   *p.Character, i,j,n
        n = Len(txt)
        If n = 0 : ProcedureReturn "" : EndIf
        
        For i=1 To n
            *p = @txt + ((i-1)* SizeOf(Character))
            If *p\c = '.'
                For j=n To i Step -1
                    *p = @txt + ((j-1)* SizeOf(Character))
                    If (*p\c <> '0') And (*p\c <> '.') : Break : EndIf
                    *p\c = 0
                Next
            EndIf
        Next
        ProcedureReturn txt
        
    EndProcedure
    
    Procedure.i BigStrAppend(*me.TBigStr, nwStr.s)
        ; the fastest! saves a lot of time by avoiding repetitive memory allocation/move!
        ; the price is the reservation of a decent block of memory ~ 10 KB !
        Protected chunk,addReq,totSize, *p
        chunk = 10240
        
        If *me\CurOffset < 0    : ProcedureReturn  #False : EndIf
        If *me\Pointer = 0      : *me\Pointer = ReAllocateMemory(*me\Pointer, chunk) : EndIf
        
        ;addReq = Len(nwStr) * SizeOf(Character)    ; bit faster than: 
        addReq = StringByteLength(nwStr) 
        
        If addReq = 0           : ProcedureReturn  #True : EndIf
        totSize = MemorySize(*me\Pointer) 
        If totSize < *me\curOffset + addReq + 2
            ;*me\Pointer = ReAllocateMemory(*me\Pointer,*me\CurOffset + chunk + addReq + 2)
            *p = ReAllocateMemory(*me\Pointer,*me\CurOffset + chunk + addReq + 2)
            If *p
                *me\Pointer = *p
            Else
                *me\curOffset = -1
                ProcedureReturn #False
            EndIf
            totSize = MemorySize(*me\Pointer) 
        EndIf
        
        If *me\curOffset + addReq > totSize
            MessageRequester("XXXXXX"," >>>>>>>>>>>>>>>>>>> BigStrAppend")
        EndIf
        
        PokeS(*me\Pointer + *me\curOffset, nwStr) ; -1,#PB_Ascii)
        *me\curOffset = *me\curOffset + addReq
        ProcedureReturn #True
        
    EndProcedure
    Procedure.s BigStrGetString(*me.TBigStr)
        Protected strRet.s
        If *me\Pointer
            strRet = PeekS(*me\Pointer)
            *me\CurOffset = 0
            FreeMemory(*me\Pointer)
            ClearStructure(*me,TBigStr)
        EndIf
        
        ProcedureReturn strRet
    EndProcedure
    Procedure.i BigStrClear(*me.TBigStr)
        If *me\Pointer
            *me\CurOffset = 0
            FreeMemory(*me\Pointer)
            ClearStructure(*me,TBigStr)
        EndIf
    EndProcedure
    
    Procedure.i SplitString(s.s, multiCharSep.s, Array a.s(1))
        ; last substring is not necesseraly followed by a char-sep
        ; retrun 0 on empty string and return 1 on string with no sep at all
        Protected count, i, soc, lnStr,lnBStr, lnSep,lnBSep, ss, ee
        
        soc     = SizeOf(Character)
        lnSep   = Len(multiCharSep) :   lnBSep  = lnSep * soc
        lnStr   = Len(s)            :   lnBStr  = lnStr * soc
        If lnStr <= 0               :   ProcedureReturn 0       : EndIf
        
        count   = CountString(s,multiCharSep)
        If count <= 0
            Dim a(1) : a(1) = s : ProcedureReturn 1
        EndIf
        
        If Right(s,lnSep) <> multiCharSep : count + 1 : EndIf 
        
        Dim a(count) ; a(0) is ignored
        
        i = 1: ss = 0: ee = 0
        While ee < lnBStr And i <= count
            If CompareMemory(@s + ee, @multiCharSep, lnBSep)
                a(i) = PeekS(@s + ss, (ee-ss)/soc)
                ss = ee + lnBSep: ee = ss: i+1
            Else
                ee + soc
            EndIf
        Wend
        
        If i < count+1: a(count) = PeekS(@s + ss, (ee-ss)/soc) : EndIf
        
        ProcedureReturn count ;return count of substrings
        
    EndProcedure
    
    ;----------------------------------------------------------------------------
    Procedure   FirstPass(FileNameTxt.s, ColSep.s = #TAB$)
        Protected   fNbr, fmt, iWrd, nWrd, Dim tWrd.s(0), n, txt.s
        
        ; global variables
        ClearMap(SharedStrings())
        LastCol = 0
        LastRow = 0
        SharedStringsCount = 0
        
        fNbr = ReadFile(#PB_Any, FileNameTxt)
        If fNbr
            fmt = ReadStringFormat(fNbr)
            While Not Eof(fNbr)
                txt  = ReadString(fNbr, fmt) : LastRow + 1
                nWrd = SplitString(txt, ColSep, tWrd())
                If LastCol < nWrd : LastCol = nWrd : EndIf      ; needed in BuildSheet1Data
                For iWrd=1 To nWrd
                    If tWrd(iWrd) = ""          : Continue : EndIf
                    If  My_IsNumber(tWrd(iWrd)) : Continue : EndIf
                    
                    SharedStringsCount + 1
                    If Not FindMapElement(SharedStrings(), tWrd(iWrd))
                        n = MapSize(SharedStrings())
                        SharedStrings(tWrd(iWrd)) = Str(n)     ; 0-based index
                    EndIf
                Next
            Wend
            CloseFile(fNbr)
        EndIf
        ProcedureReturn SharedStringsCount
    EndProcedure
    
    Procedure.s ExcelColRef(x.i)
        ; adapted from skywalk code: http://www.purebasic.fr/english/viewtopic.php?f=12&t=55799
        ; SF_IntToBase()
        Protected.i p, BaseLen = 26
        Protected.s r$
        If x > 0
            While x <> 0
                p = (x % BaseLen)
                If p = 0 : p = 26 : EndIf ; 1 .. 26
                r$ = Mid(#Base26$, p, 1) + r$
                x = (x-1) / BaseLen
            Wend
        Else
            r$ = ""
        EndIf
        ProcedureReturn r$
    EndProcedure
    
    Procedure.s RefOfCell(Row.i, Col.i)
        ; returns A1, ....
        
        ProcedureReturn ExcelColRef(Col) + Str(Row)
        
    EndProcedure
    
    ; _R_ : refers to row # 
    ; _C_ : refers to col # 
    ; _V_ : is a 'stringified' value
    ; in __CellDataText : the V parameter refers to the Value in the map SharedStrings()
    Macro __CellDataText(_R_,_C_,_V_)
        "<c r=" +#DQUOTE$+ RefOfCell(_R_,_C_) +#DQUOTE$+ " t=" +#DQUOTE$+"s"+#DQUOTE$+ "><v>" + _V_ + "</v></c>"
    EndMacro
    Macro __CellDataNumber(_R_,_C_,_V_)
        "<c r=" +#DQUOTE$+ RefOfCell(_R_,_C_) +#DQUOTE$+ "><v>" + TrimZeros(_V_) + "</v></c>"
    EndMacro
    Procedure.s CleanTextXML(txt.s)
        ; txt should not contain >, <, &
        ; each special character should be replaced with: > < & 
        Protected   *mb, i, n, found_1, found_2, found_3, ret.s
        Protected.c curChr, asc_1, asc_2, asc_3
        
        n = Len(txt)
        If n <=0   : ProcedureReturn "" : EndIf
        
        asc_1   = Asc(">")
        asc_2   = Asc("<")
        asc_3   = Asc("&")
        
        *mb = @txt
        For i=0 To n-1
            curChr = PeekC(*mb + (i * SizeOf(Character)) )
            If curChr = asc_1 : found_1 = #True : EndIf
            If curChr = asc_2 : found_2 = #True : EndIf
            If curChr = asc_3 : found_3 = #True : EndIf
        Next
        ret = txt
        If found_1 : ret = ReplaceString(txt, ">", ">") : EndIf
        If found_2 : ret = ReplaceString(txt, "<", "<") : EndIf
        If found_3 : ret = ReplaceString(txt, "&", "&") : EndIf
        ProcedureReturn ret
        
    EndProcedure
    
    Procedure.s BuildSheet1Data(FileNameTxt.s, ColSep.s = #TAB$)
        Protected   fNbr, fmt
        Protected   iWrd, nWrd, Dim tWrd.s(0)
        Protected.s txt, txt_hdr, txt_row, txt_cel, ret
        Protected   Row, Col
        Protected   bs.TBigStr, *bs.TBigStr = @bs
        
        fNbr = ReadFile(#PB_Any, FileNameTxt)
        If fNbr
            fmt = ReadStringFormat(fNbr)
        
            ;<?xml version='1.0' encoding='UTF-8' standalone='yes'?><worksheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' mc:Ignorable='x14ac' xmlns:x14ac='http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'>
            txt_hdr = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<worksheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' mc:Ignorable='x14ac' xmlns:x14ac='http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'>"
            ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
            BigStrAppend(*bs, txt_hdr)
            
            txt_hdr = "<dimension ref='A1:" + RefOfCell(LastRow, LastCol) + "'/>"
            ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
            BigStrAppend(*bs, txt_hdr)
            
            ; <sheetViews><sheetView tabSelected='1' workbookViewId='0'/></sheetViews><sheetFormatPr defaultRowHeight='15' x14ac:dyDescent='0.25'/>
            txt_hdr = "<sheetViews><sheetView tabSelected='1' workbookViewId='0'/></sheetViews><sheetFormatPr defaultRowHeight='15' x14ac:dyDescent='0.25'/>"
            ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
            BigStrAppend(*bs, txt_hdr)
            
            BigStrAppend(*bs, "<sheetData>")
            
            While Not Eof(fNbr)
                txt  = ReadString(fNbr, fmt) : Row + 1
            
                nWrd = SplitString(txt, ColSep, tWrd())
                If nWrd = 0 : Continue : EndIf
                
                ;<row r='4' spans='1:6' x14ac:dyDescent='0.25'>
                txt_row = "<row r='" + Str(Row) + "' spans='1:" + Str(LastCol) +"' x14ac:dyDescent='0.25'>"
                ReplaceString(txt_row, "'", #DQUOTE$, #PB_String_InPlace)
                BigStrAppend(*bs, txt_row)
                
                For iWrd=1 To nWrd
                    If tWrd(iWrd) = "" : Continue : EndIf
                    
                    Col = iWrd
                    If  My_IsNumber(tWrd(iWrd))
                        txt_cel = __CellDataNumber(Row, Col, tWrd(iWrd))
                        
                    Else
                        ; anything else is a text (for now at least)
                        txt_cel = __CellDataText(Row, Col, SharedStrings(tWrd(iWrd)) )
                    EndIf
                    BigStrAppend(*bs, txt_cel)
                Next
                BigStrAppend(*bs, "</row>")     ; ending the row-text
                
                
            Wend
            
            ; ending the file header text
            ;</sheetData><pageMargins left='0.7' right='0.7' top='0.75' bottom='0.75' header='0.3' footer='0.3'/></worksheet>
            txt_hdr = "</sheetData><pageMargins left='0.7' right='0.7' top='0.75' bottom='0.75' header='0.3' footer='0.3'/></worksheet>"
            ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
            BigStrAppend(*bs, txt_hdr)
            
            CloseFile(fNbr)
        EndIf
        
        ret = BigStrGetString(*bs)
        
        ProcedureReturn ret
        
    EndProcedure
    Procedure.s BuildSharedStrings()
        ; uses the global map SharedStrings() to build the string section: sharedStrings.xml
        Protected.s txt_hdr, txt_row, ret
        Protected   i,n, Dim t.s(0)
        Protected   bs.TBigStr, *bs.TBigStr = @bs
        
        n = MapSize(SharedStrings())
        ; <?xml version="1.0" encoding="UTF-8" standalone="yes"?><sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="15" uniqueCount="9">
        txt_hdr = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<sst xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main'"
        ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
        BigStrAppend(*bs, txt_hdr)
        
        txt_hdr = " count='" +Str(SharedStringsCount) + "' uniqueCount='" +Str(n) +"'>"
        ReplaceString(txt_hdr, "'", #DQUOTE$, #PB_String_InPlace)
        BigStrAppend(*bs, txt_hdr)
        
        ; moving the map into an array
        If n > 0
            Dim t(n-1)
            ForEach SharedStrings()
                i = Val(SharedStrings())     ; 0 .. n-1
                t(i) = CleanTextXML( MapKey(SharedStrings()) )
            Next
            For i=0 To ArraySize(t())
                ; <si><t>1a</t></si>
                txt_row = "<si><t>"+ t(i)+ "</t></si>"
                BigStrAppend(*bs, txt_row)
            Next
        EndIf
        
        BigStrAppend(*bs, "</sst>")
        ret = BigStrGetString(*bs)
        
        ProcedureReturn ret
    EndProcedure
    
    Procedure.i FreshXLSX(Pkr.i)
        ; builds from scratch a new empty xlsx
        Protected   org_txt.s, section.s, i,n, Dim buffer.a(0)
        
        ;         "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Types xmlns='http://schemas.openxmlformats.org/package/2006/content-types'><Default Extension='rels' ContentType='application/vnd.openxmlformats-package.relationships+xml'/><Default Extension='xml' ContentType='application/xml'/><Override PartName='/xl/workbook.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'/><Override PartName='/xl/worksheets/sheet1.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml'/><Override PartName='/xl/theme/theme1.xml' ContentType='application/vnd.openxmlformats-officedocument.theme+xml'/><Override PartName='/xl/styles.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml'/><Override PartName='/xl/sharedStrings.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml'/><Override PartName='/docProps/core.xml' ContentType='application/vnd.openxmlformats-package.core-properties+xml'/><Override PartName='/docProps/app.xml' ContentType='application/vnd.openxmlformats-officedocument.extended-properties+xml'/></Types>
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Types xmlns='http://schemas.openxmlformats.org/package/2006/content-types'><Default Extension='rels' ContentType='application/vnd.openxmlformats-package.relationships+xml'/><Default Extension='xml' ContentType='application/xml'/><Override PartName='/xl/workbook.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'/><Override PartName='/xl/worksheets/sheet1.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml'/><Override PartName='/xl/theme/theme1.xml' ContentType='application/vnd.openxmlformats-officedocument.theme+xml'/><Override PartName='/xl/styles.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml'/><Override PartName='/xl/sharedStrings.xml' ContentType='application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml'/><Override PartName='/docProps/core.xml' ContentType='application/vnd.openxmlformats-package.core-properties+xml'/><Override PartName='/docProps/app.xml' ContentType='application/vnd.openxmlformats-officedocument.extended-properties+xml'/></Types>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "[Content_Types].xml" )
        
        ;<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'><Relationship Id='rId3' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties' Target='docProps/app.xml'/><Relationship Id='rId2' Type='http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties' Target='docProps/core.xml'/><Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='xl/workbook.xml'/></Relationships>        
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'><Relationship Id='rId3' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties' Target='docProps/app.xml'/><Relationship Id='rId2' Type='http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties' Target='docProps/core.xml'/><Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='xl/workbook.xml'/></Relationships>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "_rels/.rels" )
        
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Properties xmlns='http://schemas.openxmlformats.org/officeDocument/2006/extended-properties' xmlns:vt='http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'><Application>Microsoft Excel</Application><DocSecurity>0</DocSecurity><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size='2' baseType='variant'><vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size='1' baseType='lpstr'><vt:lpstr>Sheet1</vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>15.0300</AppVersion></Properties>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "docProps/app.xml" )
        
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<cp:coreProperties xmlns:cp='http://schemas.openxmlformats.org/package/2006/metadata/core-properties' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:dcterms='http://purl.org/dc/terms/' xmlns:dcmitype='http://purl.org/dc/dcmitype/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>"
        org_txt = org_txt + "<dc:creator>PB_XLSX_Module</dc:creator></cp:coreProperties>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "docProps/core.xml" )
        
        ; xl
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<styleSheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' mc:Ignorable='x14ac' xmlns:x14ac='http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'><fonts count='1' x14ac:knownFonts='1'><font><sz val='11'/><color theme='1'/><name val='Calibri'/><family val='2'/><scheme val='minor'/></font></fonts><fills count='2'><fill><patternFill patternType='none'/></fill><fill><patternFill patternType='gray125'/></fill></fills><borders count='1'><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count='1'><xf numFmtId='0' fontId='0' fillId='0' borderId='0'/></cellStyleXfs><cellXfs count='1'><xf numFmtId='0' fontId='0' fillId='0' borderId='0' xfId='0'/></cellXfs><cellStyles count='1'><cellStyle name='Normal' xfId='0' builtinId='0'/></cellStyles><dxfs count='0'/><tableStyles count='0' defaultTableStyle='TableStyleMedium2' defaultPivotStyle='PivotStyleLight16'/><extLst><ext uri='{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}' xmlns:x14='http://schemas.microsoft.com/office/spreadsheetml/2009/9/main'><x14:slicerStyles defaultSlicerStyle='SlicerStyleLight1'/></ext><ext uri='{9260A510-F301-46a8-8635-F512D64BE5F5}' xmlns:x15='http://schemas.microsoft.com/office/spreadsheetml/2010/11/main'><x15:timelineStyles defaultTimelineStyle='TimeSlicerStyleLight1'/></ext></extLst></styleSheet>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "xl/styles.xml" )
        
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<workbook xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' mc:Ignorable='x15' xmlns:x15='http://schemas.microsoft.com/office/spreadsheetml/2010/11/main'><fileVersion appName='xl' lastEdited='6' lowestEdited='6' rupBuild='14420'/><workbookPr defaultThemeVersion='153222'/><mc:AlternateContent xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'><mc:Choice Requires='x15'><x15ac:absPath url='C:\Temp\xlsx\' xmlns:x15ac='http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac'/></mc:Choice></mc:AlternateContent><bookViews><workbookView xWindow='0' yWindow='0' windowWidth='20490' windowHeight='7755'/></bookViews><sheets><sheet name='Sheet1' sheetId='1' r:id='rId1'/></sheets><calcPr calcId='152511'/><extLst><ext uri='{140A7094-0E35-4892-8432-C4D2E57EDEB5}' xmlns:x15='http://schemas.microsoft.com/office/spreadsheetml/2010/11/main'><x15:workbookPr chartTrackingRefBase='1'/></ext></extLst></workbook>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "xl/workbook.xml" )
        
        ; xl/_rels
        ; "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'><Relationship Id='rId3' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles' Target='styles.xml'/><Relationship Id='rId2' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' Target='theme/theme1.xml'/><Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet' Target='worksheets/sheet1.xml'/><Relationship Id='rId4' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings' Target='sharedStrings.xml'/></Relationships>"
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'><Relationship Id='rId3' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles' Target='styles.xml'/><Relationship Id='rId2' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' Target='theme/theme1.xml'/><Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet' Target='worksheets/sheet1.xml'/><Relationship Id='rId4' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings' Target='sharedStrings.xml'/></Relationships>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_Ascii)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "xl/_rels/workbook.xml.rels" )
        
        ; xl/theme
        org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<a:theme xmlns:a='http://schemas.openxmlformats.org/drawingml/2006/main' name='Office Theme'><a:themeElements><a:clrScheme name='Office'><a:dk1><a:sysClr val='windowText' lastClr='000000'/></a:dk1><a:lt1><a:sysClr val='window' lastClr='FFFFFF'/></a:lt1><a:dk2><a:srgbClr val='44546A'/></a:dk2><a:lt2><a:srgbClr val='E7E6E6'/></a:lt2><a:accent1><a:srgbClr val='5B9BD5'/></a:accent1><a:accent2><a:srgbClr val='ED7D31'/></a:accent2><a:accent3><a:srgbClr val='A5A5A5'/></a:accent3><a:accent4><a:srgbClr val='FFC000'/></a:accent4><a:accent5><a:srgbClr val='4472C4'/></a:accent5><a:accent6><a:srgbClr val='70AD47'/></a:accent6><a:hlink><a:srgbClr val='0563C1'/></a:hlink><a:folHlink><a:srgbClr val='954F72'/></a:folHlink></a:clrScheme><a:fontScheme name='Office'><a:majorFont><a:latin typeface='Calibri Light' panose='020F0302020204030204'/><a:ea typeface=''/><a:cs typeface=''/><a:font script='Jpan' typeface='MS Pゴシック'/><a:font script='Hang' typeface='맑은 고딕'/><a:font script='Hans' typeface='宋体'/><a:font script='Hant' typeface='新細明體'/><a:font script='Arab' typeface='Times New Roman'/><a:font script='Hebr' typeface='Times New Roman'/><a:font script='Thai' typeface='Tahoma'/><a:font script='Ethi' typeface='Nyala'/><a:font script='Beng' typeface='Vrinda'/><a:font script='Gujr' typeface='Shruti'/><a:font script='Khmr' typeface='MoolBoran'/><a:font script='Knda' typeface='Tunga'/><a:font script='Guru' typeface='Raavi'/><a:font script='Cans' typeface='Euphemia'/><a:font script='Cher' typeface='Plantagenet Cherokee'/><a:font script='Yiii' typeface='Microsoft Yi Baiti'/><a:font script='Tibt' typeface='Microsoft Himalaya'/><a:font script='Thaa' typeface='MV Boli'/><a:font script='Deva' typeface='Mangal'/><a:font script='Telu' typeface='Gautami'/><a:font script='Taml' typeface='Latha'/><a:font script='Syrc' typeface='Estrangelo Edessa'/><a:font script='Orya' typeface='Kalinga'/><a:font script='Mlym' typeface='Kartika'/><a:font script='Laoo' typeface='DokChampa'/><a:font script='Sinh' typeface='Iskoola Pota'/><a:font script='Mong' typeface='Mongolian Baiti'/><a:font script='Viet' typeface='Times New Roman'/><a:font script='Uigh' typeface='Microsoft Uighur'/><a:font script='Geor' typeface='Sylfaen'/></a:majorFont><a:minorFont><a:latin typeface='Calibri' panose='020F0502020204030204'/><a:ea typeface=''/><a:cs typeface=''/><a:font script='Jpan' typeface='MS Pゴシック'/><a:font script='Hang' typeface='맑은 고딕'/><a:font script='Hans' typeface='宋体'/><a:font script='Hant' typeface='新細明體'/><a:font script='Arab' typeface='Arial'/><a:font script='Hebr' typeface='Arial'/><a:font script='Thai' typeface='Tahoma'/><a:font script='Ethi' typeface='Nyala'/><a:font script='Beng' typeface='Vrinda'/><a:font script='Gujr' typeface='Shruti'/><a:font script='Khmr' typeface='DaunPenh'/><a:font script='Knda' typeface='Tunga'/><a:font script='Guru' typeface='Raavi'/><a:font script='Cans' typeface='Euphemia'/><a:font script='Cher' typeface='Plantagenet Cherokee'/><a:font script='Yiii' typeface='Microsoft Yi Baiti'/><a:font script='Tibt' typeface='Microsoft Himalaya'/><a:font script='Thaa' typeface='MV Boli'/><a:font script='Deva' typeface='Mangal'/><a:font script='Telu' typeface='Gautami'/><a:font script='Taml' typeface='Latha'/><a:font script='Syrc' typeface='Estrangelo Edessa'/><a:font script='Orya' typeface='Kalinga'/><a:font script='Mlym' typeface='Kartika'/><a:font script='Laoo' typeface='DokChampa'/><a:font script='Sinh' typeface='Iskoola Pota'/><a:font script='Mong' typeface='Mongolian Baiti'/><a:font script='Viet' typeface='Arial'/><a:font script='Uigh' typeface='Microsoft Uighur'/><a:font script='Geor' typeface='Sylfaen'/></a:minorFont></a:fontScheme><a:fmtScheme name='Office'><a:fillStyleLst><a:solidFill><a:schemeClr val='phClr'/></a:solidFill><a:gradFill rotWithShape='1'><a:gsLst><a:gs pos='0'><a:schemeClr val='phClr'><a:lumMod val='110000'/><a:satMod val='105000'/><a:tint val='67000'/></a:schemeClr></a:gs><a:gs pos='50000'><a:schemeClr val='phClr'><a:lumMod val='105000'/><a:satMod val='103000'/><a:tint val='73000'/></a:schemeClr></a:gs><a:gs pos='100000'><a:schemeClr val='phClr'><a:lumMod val='105000'/><a:satMod val='109000'/><a:tint val='81000'/></a:schemeClr></a:gs></a:gsLst><a:lin ang='5400000' scaled='0'/></a:gradFill><a:gradFill rotWithShape='1'><a:gsLst><a:gs pos='0'><a:schemeClr val='phClr'><a:satMod val='103000'/><a:lumMod val='102000'/><a:tint val='94000'/></a:schemeClr></a:gs><a:gs pos='50000'><a:schemeClr val='phClr'><a:satMod val='110000'/><a:lumMod val='100000'/><a:shade val='100000'/></a:schemeClr></a:gs><a:gs pos='100000'><a:schemeClr val='phClr'><a:lumMod val='99000'/><a:satMod val='120000'/><a:shade val='78000'/></a:schemeClr></a:gs></a:gsLst><a:lin ang='5400000' scaled='0'/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w='6350' cap='flat' cmpd='sng' algn='ctr'><a:solidFill><a:schemeClr val='phClr'/></a:solidFill><a:prstDash val='solid'/><a:miter lim='800000'/></a:ln><a:ln w='12700' cap='flat' cmpd='sng' algn='ctr'><a:solidFill><a:schemeClr val='phClr'/></a:solidFill><a:prstDash val='solid'/><a:miter lim='800000'/></a:ln><a:ln w='19050' cap='flat' cmpd='sng' algn='ctr'><a:solidFill><a:schemeClr val='phClr'/></a:solidFill><a:prstDash val='solid'/><a:miter lim='800000'/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad='57150' dist='19050' dir='5400000' algn='ctr' rotWithShape='0'><a:srgbClr val='000000'><a:alpha val='63000'/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val='phClr'/></a:solidFill><a:solidFill><a:schemeClr val='phClr'><a:tint val='95000'/><a:satMod val='170000'/></a:schemeClr></a:solidFill><a:gradFill rotWithShape='1'><a:gsLst><a:gs pos='0'><a:schemeClr val='phClr'><a:tint val='93000'/><a:satMod val='150000'/><a:shade val='98000'/><a:lumMod val='102000'/></a:schemeClr></a:gs><a:gs pos='50000'><a:schemeClr val='phClr'><a:tint val='98000'/><a:satMod val='130000'/><a:shade val='90000'/><a:lumMod val='103000'/></a:schemeClr></a:gs><a:gs pos='100000'><a:schemeClr val='phClr'><a:shade val='63000'/><a:satMod val='120000'/></a:schemeClr></a:gs></a:gsLst><a:lin ang='5400000' scaled='0'/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri='{05A4C25C-085E-4340-85A3-A5531E510DB2}'><thm15:themeFamily xmlns:thm15='http://schemas.microsoft.com/office/thememl/2012/main' name='Office Theme' id='{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}' vid='{4A3C46E8-61CC-4603-A589-7422A47A8E4A}'/></a:ext></a:extLst></a:theme>"
        ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        n = StringByteLength(org_txt, #PB_UTF8)
        Dim buffer(n-1)
        PokeS(@buffer(0), org_txt, -1, #PB_UTF8|#PB_String_NoZero)
        i = AddPackMemory(Pkr, @buffer(0), n, "xl/theme/theme1.xml" )
        
        ; xl/worksheets
        ;org_txt = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +#CRLF$+ "<worksheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' mc:Ignorable='x14ac' xmlns:x14ac='http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'><dimension ref='A1'/><sheetViews><sheetView tabSelected='1' workbookViewId='0'/></sheetViews><sheetFormatPr defaultRowHeight='15' x14ac:dyDescent='0.25'/><sheetData/><pageMargins left='0.7' right='0.7' top='0.75' bottom='0.75' header='0.3' footer='0.3'/></worksheet>"
        ;ReplaceString(org_txt, "'", #DQUOTE$, #PB_String_InPlace)
        ;n = StringByteLength(org_txt, #PB_Ascii)
        ;Dim buffer(n-1)
        ;PokeS(@buffer(0), org_txt, -1, #PB_Ascii|#PB_String_NoZero)
        ;i = AddPackMemory(Pkr, @buffer(0), n, "xl/worksheets/sheet1.xml" )
        
        
    EndProcedure
    
    ;----------------------------------------------------------------------------
    
    Procedure.i TextToXLSX(FileNameTxt.s, FileNameXLSX.s, ColSep.s = #TAB$)
        Protected   pth.s, fName.s, section.s, f1.s, f2.s
        Protected   pkr_nbr, n, j, Dim buffer.a(0)
        
        fName = FileNameXLSX
        pkr_nbr = CreatePack(#PB_Any, fName, #PB_PackerPlugin_Zip)
        If pkr_nbr
            FreshXLSX(pkr_nbr)
            FirstPass(FileNameTxt, ColSep)
            
            section = BuildSharedStrings()
            n = StringByteLength(section, #PB_UTF8)
            Dim buffer(n)
            PokeS(@buffer(0), section, -1, #PB_UTF8)
            j = AddPackMemory(pkr_nbr, @buffer(0), n, "xl/sharedStrings.xml" )
        
            section = BuildSheet1Data(FileNameTxt, ColSep)
            n = StringByteLength(section, #PB_UTF8)
            Dim buffer(n)
            PokeS(@buffer(0), section, -1, #PB_UTF8)
            j = AddPackMemory(pkr_nbr, @buffer(0), n, "xl/worksheets/sheet1.xml" )
            
            ClosePack(pkr_nbr)
        EndIf
        
    EndProcedure
    
    
EndModule

CompilerIf #PB_Compiler_IsMainFile
    Global  xlsx_file.s, text_file.s = GetTemporaryDirectory() + "test.txt"
    Global  fNbr, i,j,n,m, txt.s
    
    n = 10 : m = 7
    fNbr = CreateFile(#PB_Any, text_file)
    If fNbr
        For i=1 To n
            txt = ""
            For j=1 To m
                txt = txt + "cell (" + Str(i) + ", " + Str(j) + ")"
                If j < m : txt + #TAB$ : EndIf
            Next
            WriteStringN(fNbr, txt)
        Next
        ;txt = "888	274	91626	274/23262	1.00	1.00	27/02/2017	64I/KUMER	1.56	AR-BLUE	28	OBSEQUIO CLIENTE	9E"
        ;WriteStringN(fNbr, txt)
        
        CloseFile(fNbr)
    EndIf
    xlsx_file = GetTemporaryDirectory() + "test.xlsx"
    XLSX::TextToXLSX(text_file, xlsx_file)
    RunProgram( xlsx_file )
CompilerEndIf

Edit: replaced the My_IsNumber() procedure with a new one ... the new one matches Excel way
Edit2: replaced again that same routine with a new and faster My_IsNumer() again .... hopefully the last one :mrgreen:

Re: Text to XLSX

Posted: Mon Mar 27, 2017 1:56 pm
by Kwai chang caine
Waoouh !!! great job, works fine here !! :shock:
Again an example of the big simplicity of CROSOFT :wink:

Thanks a lot for sharing your very hard and useful code 8)

Re: Text to XLSX

Posted: Mon Mar 27, 2017 9:35 pm
by Lunasole
Thanks, looks useful ^^
I'm rarely needing similar things, but when they are needed that always becomes a pain in PB, maybe next time your stuff will help

Re: Text to XLSX

Posted: Fri Mar 31, 2017 11:42 am
by graves
Hi Said,
Great job! Very useful!

But I found a problem on it, try with this values on a txt file:

Code: Select all

888	274	91626	274/23262	1.00	1.00	27/02/2017	64I/KUMER 1.56 AR-BLUE	28	OBSEQUIO CLIENTE	9E	
It produces an error in the sheet, at least with my Excel 2010.
If you delete the final "9E" value, everything is fine.

BR

Re: Text to XLSX

Posted: Fri Mar 31, 2017 1:20 pm
by Kiffi
graves wrote:If you delete the final "9E" value, everything is fine.
Excel 'thinks' that you want to write an exponent number. Therefore (because of the missing number after 'E') Excel assumes, that the cell is corrupt.

Greetings ... Peter

Re: Text to XLSX

Posted: Fri Mar 31, 2017 2:24 pm
by said
Hi,

@KCC, @Lunasole, @graves you are welcome :D

@graves, i think this bug is due to the procedure My_IsNumber() this routine accepts scientific form as well and as pointed by Kiffi (with thanks) 9E is accepted as a number and passed as such to Excel but then Excel is not accepting it as anumber! I should fix this issue ... let me check!

Edit: ok, I found one routine on the forums that matches the Excel way (there are many routines that fail in one or either case!) ... credits to his creator AKJ! First post updated, should fix that 9E bug, thanks for your feedback :D

Re: Text to XLSX

Posted: Sat Apr 01, 2017 9:07 am
by graves
Hi, Said
OK. It works correctly now.
Sorry for the "9E" but it's a product features code, and I need to use it there.

Best Regards
Joaquin

Re: Text to XLSX

Posted: Sat Apr 01, 2017 4:47 pm
by said
Replaced that buggy routine My_IsNumber() with a new one that supposed to be more reliable (at lest i hope so) ...

first post updated :D

@graves, you found a fishy behavior, i did not know the exact behavior of ValD() until now :cry: ... so i sincerely thank you for your that :D