TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: S.Langhammer on March 25, 2013, 06:46:47 AM

Title: Ignoring certain blocks on output
Post by: S.Langhammer on March 25, 2013, 06:46:47 AM
Hello again!
Those of you, who followed my questions here might know, that I'm working on a BricsCAD to custom file Lisp-Interface.
With the great help of you guys here on the swamp (specially Lee May and roy_043) I've worked my way through the Basic process of getting it up and running. Now it's optimization time!
Since I ignore certain entities on reading the File (such as viewports, 3Dsolids, Images and so on) it happens to me, that I give out empty blocks and inserts, that point to empty blocks.
These don't actually enlarge the interface's temp-file very much, but they slow down the visualization, since they are still being red in and calculated on the Delphi side of the Interface.

Now I thought there must be a way, to properly make a list of all "empty" blocks and only print those blocks and inserts to the file, who are not in that list.

I tried something with the length of the list of subentities within the block but my check function always got caught up on an endless loop.
I'll just post all my block and insert related code and if anyone gets an idea I'd be happy to hear it!


Code - Auto/Visual Lisp: [Select]
  1. (defun getBlockList(/ listBlock entName T)
  2.         (while (setq listBlock (tblnext "BLOCK" T))
  3.                 (while (setq entName (cdr(assoc -2 listBlock)))
  4.                         (getBlkRefData listBlock)
  5.                         (setq listBlock (entnext entName))
  6.                 )
  7.         )
  8.         (princ)
  9. )
  10. (defun Block_EnameListNested (blockName / ename ret blockName)
  11.         (if (setq ename (tblobjname "BLOCK" blockName))
  12.                 (while (setq ename (entnext ename))
  13.                         (setq ret (append ret (list ename)))
  14.                 )
  15.         )
  16.         ret
  17. )
  18.  
  19. (defun getBlkData(/ entName entPoint entX entY entZ entLay entRot dStr entScaX entScaY entScaZ endMark entNorm entNormStr)     
  20.         (setq entLay    (cdr(assoc 8 entity))
  21.                 entName (cdr(assoc 2 entity))
  22.                 entPoint        (cdr(assoc 10 entity))
  23.                 entX            (rtos (car   entPoint) 2 4)
  24.                 entY            (rtos (cadr  entPoint) 2 4)
  25.                 entZ    (rtos (caddr entPoint) 2 4)
  26.                 entScaX (rtos (cdr(assoc 41 entity)) 2 4)
  27.                 entScaY (rtos (cdr(assoc 42 entity)) 2 4)
  28.                 entScaZ (rtos (cdr(assoc 43 entity)) 2 4)
  29.                 entNorm (cdr(assoc 210 entity))
  30.                 entNormStr(strcat (rtos(car entNorm)2 4)spcr(rtos(cadr entNorm)2 4)spcr(rtos(caddr entNorm)2 4))
  31.         )
  32.         (if (setq entRot (cdr(assoc 50 entity)))
  33.                 (setq entRot (angtos (degtorad entRot) 0 4))
  34.                 (setq entRot "0.0000")
  35.         )
  36.         (if (= (substr entName 1 1) "*")  ; if theres an anonymus/autogenerated insert found (such as copies or from SAT entities the script converted) all its block information including subentities are written to the file
  37.                 (progn
  38.                         (setq dStr (strcat              "BLOCK" spcr)
  39.                                   dStr (strcat dStr entName spcr)
  40.                                   dStr (strcat dStr "\n")
  41.                                   endMark (strcat "End of " entName "\n")
  42.                         )
  43.                         (fileWriteString dStr)
  44.                         (getinfo (Block_EnameListNested entName))
  45.                         (fileWriteString endMark)
  46.                 )
  47.         )
  48.         (setq dStr (strcat      "INSERT"               spcr)
  49.                   dStr (strcat dStr entLay       spcr)
  50.                   dStr (strcat dStr entName    spcr)
  51.                   dStr (strcat dStr entX spcr entY spcr entZ spcr)
  52.                   dStr (strcat dStr entScaX      spcr)
  53.                   dStr (strcat dStr entScaY      spcr)
  54.                   dStr (strcat dStr entScaZ      spcr)
  55.                   dStr (strcat dStr entRot        spcr)
  56.                   dStr (strcat dStr entNormStr "\n")
  57.         )
  58.         (fileWriteString dStr)
  59.         (princ)
  60. )       ;;; ende getBlkData
  61.  
  62. (defun getBlkRefData(inBlock / entLyr dstr entPt entPtStr entName endMark)
  63.         (setq entName(cdr(assoc 2 inBlock)))
  64.         (if (/= (substr entName 1 1) "*")      ; ignoring anonymus/automatic generated blocks to prevent accedently reading blocks creatated by entities (as I red, dimensions generate blocks beginning with a * for example)
  65.                 (progn
  66.                         (setq dStr (strcat              "BLOCK" spcr)
  67.                                   dStr (strcat dStr entName "\n")
  68.                                   endMark (strcat "End of " entName "\n")
  69.                         )
  70.                         (fileWriteString dStr)
  71.                         (getinfo (Block_EnameListNested entName))
  72.                         (fileWriteString endMark)
  73.                 )
  74.         )
  75.         (princ)
  76. )
  77.  

Please excuse if there are some right parenthesis missing. I copied the code directly from the file and removed the German comments. I might have caught some parenthesis as well.
Title: Re: Ignoring certain blocks on output
Post by: roy_043 on March 25, 2013, 08:10:07 AM
Your problem is perhaps* caused by the first function (getBlockList).
There are two issues with the function.
First this is how (I think) it should look:
Code - Auto/Visual Lisp: [Select]
  1. (defun getBlockList(/ listBlock entName)
  2.   (while (setq listBlock (tblnext "BLOCK" (not listBlock))) ; (not listBlock) only returns T once.
  3.     (getBlkRefData listBlock)
  4.   )
  5.   (princ)
  6. )

Issue 1:
(getBlockList) will probably only work once. You are declaring T as a local variable. This means** that inside the function T has a value of nil. This means that your function is using this code (tblnext "BLOCK" nil) every time. When it should be using (tblnext "BLOCK" T) to 'rewind' the symbol table for the first entry and then (tblnext "BLOCK" nil) for the next entries.
See:
http://docs.autodesk.com/ACD/2011/ENU/filesALR/WS1a9193826455f5ff1a32d8d10ebc6b7ccc-6917.htm

Issue 2:
When you use this code: (setq listBlock (entnext entName)), listBlock is no longer a list and (cdr(assoc -2 listBlock)) will return nil.

* The endless loop may be due to the occurence to (tblsearch) somewhere else in your code.

** I think this is a bug in BricsCAD since T should have an immutable binding.
Title: Re: Ignoring certain blocks on output
Post by: S.Langhammer on March 25, 2013, 08:40:34 AM
Looks like i expressed myself the wrong way. The functions you see there work perfectly fine, what I was searching for was more of an add-on to the existing code.
You are entirely right about the first issue. It actually does work only once. Yet that is just about right. The outer algorithm works about like this:
-choose a file
-create the temporary file
-start BricsCAD as Background procedure
-let it load the chosen file
-run the Lisp script
-close the file
-read the info from he file

About the second issue:
This is weird since it actually worked just fine so far. I never noticed an error around it. I'll definitely try your code, thank you.

... this actually surprises me since i find a lot of blocks in my temporary file. roy you made my day i got something to think of now!
Title: Re: Ignoring certain blocks on output
Post by: S.Langhammer on March 26, 2013, 10:04:00 AM
I just recognized, that I can only identify a block, that holds no non-ignored entity, if I only collect the entity names of non-ignored entities with Block_EnameListNested, when I load each complete entity, filter its entity type and check if I should ignore it or not. Doing that for every single entity would take ages especially in huge files.
Thanks for the help anyway. Looks like we have to build some kind of ignore function into the Delphi code.
Title: Re: Ignoring certain blocks on output
Post by: roy_043 on March 26, 2013, 12:50:19 PM
... In theory you can change your (getinfo) function so that instead of writing directly to file it returns a string or nil (= all entities have been ignored). Your (getBlkData) would then have to be rewritten to contain something like this:
Code - Auto/Visual Lisp: [Select]
  1. (setq entName (cdr (assoc 2 entity)))
  2. (if (set tmpInfo (getinfo (Block_EnameListNested entName)))
  3.   (progn
  4.     (fileWriteString
  5.       (strcat
  6.         "BLOCK" spcr
  7.         entName spcr
  8.         "\n"
  9.       )
  10.     )
  11.     (fileWriteString tmpInfo)
  12.     (fileWriteString (strcat "End of " entName "\n")) ; endMark
  13.     ; ... code from line 20 etc.
  14.     ; ... code from line 48 etc.
  15.     ; ...
  16.   )
  17. )

Title: Re: Ignoring certain blocks on output
Post by: S.Langhammer on March 27, 2013, 03:46:46 AM
The problem about making one LARGE info-string is, well its size.
I've tried this Kind of solution, when I first wrote getInfo. Basically lining up all red out entities to one sting. The problem here was the limitation given by the hardware. The process ate... devoured a large amount of ram and CPU capacity, causing it to slow down drastically. I'll try your solution but I have a bad feeling bout it. I should also mention, it's not the getInfo function itself, who writes to the file, it's every single get[entity type] who does that.
Title: Re: Ignoring certain blocks on output
Post by: roy_043 on March 27, 2013, 06:42:55 AM
I can imagine that:
Code - Auto/Visual Lisp: [Select]
  1. (setq outputString (strcat outputString "Something new"))
slows your program down when the outputString becomes extremely long.

When I write string data to a file I typically work with a list of strings.
This approach may also work for you:
Code - Auto/Visual Lisp: [Select]
  1. (setq outputStringList (cons  "Something new" outputStringList)) ; Note: using cons is much faster than append!
  2. ; ...
  3. ; ...
  4. (foreach line (reverse outputStringList) ; Reverse is required because of the use of cons.
  5.   (write-line line file)
  6. )
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 28, 2013, 11:06:28 PM
The problem about making one LARGE info-string is, well its size.
I've tried this Kind of solution, when I first wrote getInfo. Basically lining up all red out entities to one sting. The problem here was the limitation given by the hardware. The process ate... devoured a large amount of ram and CPU capacity, causing it to slow down drastically. I'll try your solution but I have a bad feeling bout it. I should also mention, it's not the getInfo function itself, who writes to the file, it's every single get[entity type] who does that.

Regarding this:

Quote
Code: [Select]
(setq dStr (strcat "INSERT"               spcr)
  dStr (strcat dStr entLay       spcr)
  dStr (strcat dStr entName    spcr)
  dStr (strcat dStr entX spcr entY spcr entZ spcr)
  dStr (strcat dStr entScaX      spcr)
  dStr (strcat dStr entScaY      spcr)
  dStr (strcat dStr entScaZ      spcr)
  dStr (strcat dStr entRot        spcr)
  dStr (strcat dStr entNormStr "\n")
)

Each call to (strcat) requires each string argument to
be copied to the result, which means that each result
is then passed back to (strcat) and must be copied
again, each and every time it is passed to (strcat).

If optimization is what you're after, then replace all of
the calls to (strcat) with a single call that takes as many
arguments as you need to produce the result.

See the attached file for some general tips on optimizing
string-related operations.


Title: Re: Ignoring certain blocks on output
Post by: CAB on March 29, 2013, 07:53:38 AM
Very informative, Thanks Tony
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on March 29, 2013, 10:38:11 AM
...
See the attached file for some general tips on optimizing
string-related operations.
Very interesting, thanks.
But I found a little problem in using read in:
Code: [Select]
(defun string->list (s delim)
   (read
      (vl-list->string
         (append
           '(40 34)        ;; add '("' to start
            (apply 'append
               (subst
                 '(34 34)
                  (vl-string->list delim)
                  (mapcar 'list (vl-string->list s))
               )
            )
           '(34 41)       ;; add '")" to end
         )
      )
   )
)
(string->list "\"Abc\",\"123\"" ",")           => ("" ABC "" "" 123 "")
(ALE_String2List "\"Abc\",\"123\"" ",")   => ("\"Abc\"" "\"123\"")    ; see below

About speed, also I have modified your code to:
(setq string->list-slow ALE_String2List)
Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:
  (string->list-slow): 0.034
  (string->list-fast): 0.5613

Code: [Select]
; Version 1.00 - November 2001
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;
(defun ALE_String2List (InpStr CarDlm / SttPos EndPos TmpLst)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 29, 2013, 07:17:29 PM
Hi Marco.

Thanks for pointing that out.  I should've mentioned that the string->list kludge that uses (read) doesn't always work, and in fact, there are a few ways to break it.  I added that to the original content a long time ago, and never really tested it thoroughly.

I suppose if one is really stuck for lack of a better solution (e.g., non-LISP based), then this hacked-up version might address that specific problem, but not others:

Code: [Select]

(defun string->list (s delim)
   (read
      (vl-list->string
         (append
           '(40 34)        ;; add '("' to start
            (apply 'append
               (subst
                 '(34 34)
                  (vl-string->list delim)
                  (subst
                    '(92 34)
                    '(34)
                     (mapcar 'list (vl-string->list s))
                  )
               )
            )
           '(34 41)       ;; add '")" to end
         )
      )
   )
)


Command: (string->list "\"Abc\",\"123\"" ",")
("\"Abc\"" "\"123\"")


Again, this was only minimally-tested with your example, and I don't know if it works in every case
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 29, 2013, 11:19:55 PM

About speed, also I have modified your code to:
(setq string->list-slow ALE_String2List)
Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:
  (string->list-slow): 0.034
  (string->list-fast): 0.5613

Yes, that's very much better for cases where a single character
is used as the delimiter.

The code I posted was based on a simplified version of code
that splits a string at any one of several different delimiting
characters, and also removes empty strings between two or
more adjacent delimiters:

Code: [Select]

    (string-split "\t\tabc,123\n      xyz,456" "\n,\t ")
    => ("abc" "123" "xyz" "456")


It will also do hierarchical splits, as in:

Code: [Select]

  (string-split "x=10,y=25,z=0" '("," "="))
  => (("x" "10") ("y" "25") ("z" "0"))


Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 30, 2013, 04:53:18 AM
Code: [Select]
; Version 1.00 - November 2001
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;
(defun ALE_String2List (InpStr CarDlm / SttPos EndPos TmpLst)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)

Marco - After seeing your incredibly-fast solution, I went into my old LISP libraries to see why the one using the (read) kludge that I showed was relatively-slow.

Here is why my orange (the function which string->list was
based on) is slower than your apple  :laugh:

Code: [Select]

Command: (setq str "552.32,\"Smith, John\",42,350")
"552.32,\"Smith, John\",42,350"

Command: (ale_string2list str ",")
("552.32" "\"Smith" " John\"" "42" "350")

Command: (string-parse str ",")
("552.32" "\"Smith, John\"" "42" "350")


(string-parse) is the function which the string->list example function from that
document was based on. It was designed from the outset to parse CDF-formatted
data, where commas that appear between two double-quotes are interpreted as
literal text content, rather than as delimiters
. The string->list function was really
just for the purpose of comparing the two approaches, one using many calls to
(strcat) and the other using (read), and also suffers from the same problem shown
above.

Here is a watered-down version of string-parse (the actual working
version does additional things related to whitespace handling which
I've omitted because it is somewhat specific to the application I was
using it with):

Code: [Select]

(defun string-parse ( s delimiters / dquote ddquote flag )
   (cond
      (  (not delimiters) s)
      (  (vl-consp delimiters)
         (mapcar
            (function
               (lambda (str)
                  (string-parse str (cdr delimiters))
               )
            )
            (string-parse s (car delimiters))
         )
      )
      (t (setq dquote '(92 34))
         (setq ddquote '(34 34))
         (read
            (vl-list->string
               (append
                 '(40 34)       
                  (apply 'append
                     (mapcar
                        (function
                           (lambda (c)
                              (cond
                                 ;; escape double-quote and toggle flag

                                 (  (eq c 34) 
                                    (setq flag (not flag))
                                    dquote
                                 )

                                 ;; if flag is set, ignore delimiters:

                                 (flag (list c))

                                 ;; replace delimiter with 2 double-quotes

                                 (  (vl-string-position c delimiters) ddquote)

                                 (t (list c))
                              )
                           )
                        )
                        (vl-string->list s)
                     )
                  )
                 '(34 41)       
               )
            )
         )
      )
   )
)


Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on March 30, 2013, 05:14:45 AM
<clip>
Again, this was only minimally-tested with your example, and I don't know if it works in every case
Thank Tony for your complete and accurate answer.
I have tested other conditions and it seems work good:
(string->list "\"Abc\",\"Abc\"" ",")                 => ("\"Abc\"" "\"Abc\"")
(string->list ".99,.99" ",")                             => (".99" ".99")
(string->list "1.0,1.0" ",")                                => ("1.0" "1.0")
(string->list "1,1" ",")                                   => ("1" "1")
(string->list "Xyz,Xyz" ",")                             => ("Xyz" "Xyz")
(string->list ",," ",")                                        => ("" "" "")
(string->list "(1 2 \"Abc\"),(1 2 \"Abc\")" ",") => ("(1 2 \"Abc\")" "(1 2 \"Abc\")")
(string->list "(1 . 2),(1 . 2)" ",")                => ("(1 . 2)" "(1 . 2)")
(string->list "(1/2\"Abc),(1/2\"Abc)" ",")       => ("(1/2\"Abc)" "(1/2\"Abc)")
(string->list ".,." ",")                                        => ("." ".")
(string->list "(,(" ",")                                     => ("(" "(")
(string->list "),),(,)" ",")                                 => (")" ")" "(" ")")

Ciao.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on March 30, 2013, 07:14:54 AM
<clip>
Tony,

this topic is always very interesting and full of new needs,
thank you for your teaching!

I answer to two your interventions using the old style:

>>>   (string-split "x=10,y=25,z=0" '("," "="))
>>>    => (("x" "10") ("y" "25") ("z" "0"))

very interesting!

>>>   (string-parse) is the function which the string->list
>>>   example function from that document was based on.
>>>   It was designed from the outset to parse CDF-formatted
>>>   data, where commas that appear between two double-quotes
>>>   are interpreted as literal text content, rather than
>>>   as delimiters.

Very correct, now I will try to write a new version for this  ;-)

Below two other functions for delimiter > 1 or more characters
and to remove dupes delimiter.

Grazie mille.

Code: [Select]
; John Uhden, Cadlantic/formerly CADvantage
; String2List
; Originally ALE_STRING2LIST By Marc'Antonio Alessi
; Date: Thursday, November 08, 2001
;
; Renamed in:
; Function: ALE_String2ListStrDlm
;
; Version 1.00
;
; Description:
;   convert a string into a list
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter > 1 or more characters [STR]
;
; Examples:
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][(][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "(" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][)][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" ")" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][\"][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "\"" "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][,][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "," "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][.][99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" "." "99")
;   (ALE_String2ListStrDlm "\"Abc\"][1.0][1][Xyz][.99" "][")
;   => ("\"Abc\"" "1.0" "1" "Xyz" ".99")
;
; Return Values:
;   [LIST]
;
(defun ALE_String2ListStrDlm (InpStr StrDlm / SttPos TmpPos DlmLng TmpLst)
  (cond
    ( (/= (type InpStr) (type StrDlm) 'STR) )
    ( (= InpStr StrDlm) '("") )
    (T
      (setq
        DlmLng (strlen StrDlm)   SttPos 0
        TmpPos (vl-string-search StrDlm InpStr SttPos)
      )
      (while TmpPos
        (setq
          TmpLst (cons (substr InpStr (1+ SttPos) (- TmpPos SttPos)) TmpLst)
          SttPos (+ TmpPos DlmLng)
          TmpPos (vl-string-search StrDlm InpStr SttPos)
        )
      )
      (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
    )
  )
)

; Marc'Antonio Alessi, Italy - http://xoomer.virgilio.it/alessi
;
; Function: ALE_String_ToList
;
; Version 1.00 - 01/2010
;
; Description:
;   convert a string into a list of strings
;
; Arguments:
;   InpStr = string [STR]
;   CarDlm = delimiter [STR] 1 character
;   TrueFl = if nil remove dupes delimiter
;
; Examples:
;  (ALE_String_ToList "aaa_vvv_hhh__yyy ___lll_" "_" T)
;  ("aaa" "vvv" "hhh" "" "yyy " "" "" "lll" "lll")
;
;  (ALE_String_ToList "aaa_vvv_hhh__yyy ___lll_" "_" nil)
;  ("aaa" "vvv" "hhh" "yyy " "lll")
;
(defun ALE_String_ToList (InpStr CarDlm TrueFl / SttPos EndPos TmpLst TmpStr)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpStr (substr InpStr (1+ SttPos) (- EndPos SttPos))
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
    (and
      (or (/= TmpStr "") TrueFl)
      (setq TmpLst (cons TmpStr TmpLst))
    )
  )
  (if (or (/= (setq TmpStr (substr InpStr (1+ SttPos))) "") TrueFl)
    (reverse (cons TmpStr TmpLst))
    (reverse TmpLst)
  )
)
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 30, 2013, 01:33:36 PM
Marco - Prego.

Code - Text: [Select]
  1.  
  2. Command: (setq str "552.32,\"Smith, John\",42,350")
  3. "552.32,\"Smith, John\",42,350"
  4.  
  5. ;; correct CDF-parsing code must ignore the delimiter
  6. ;; between "Smith" and "John", because it appears between
  7. ;; double-quotes and must therefore be treated as literal
  8. ;; content.  The correct result should have 4 elements:
  9.  
  10. Command: (setq result (ale_string_tolist str "," t))
  11. ("552.32" "\"Smith" " John\"" "42" "350")
  12.  
  13. Command: (length result) 5
  14.  
  15. Command: (setq result (ale_string_tolist str "," nil))
  16. ("552.32" "\"Smith" " John\"" "42" "350")
  17.  
  18. Command: (length result) 5
  19.  
  20. Command: (setq result (ale_String2ListStrDlm str ","))
  21. ("552.32" "\"Smith" " John\"" "42" "350")
  22.  
  23. Command: (length result) 5
  24.  
  25. Command: (setq result (string-parse str ","))
  26. ("552.32" "\"Smith, John\"" "42" "350")
  27.  
  28. Command: (length result) 4
  29.  
  30.  

The actual working version I've not posted also removes extra whitespace characters from the input, which  makes for a more-interesting problem to solve using your approach. That was the underlying reason for my choosing to process the input character-by-character, rather than searching for delimiters and quotes using vl-string-position.

Of course nowadays, we can solve the same problem in managed C# in about 1/4 the time required by any of these LISP-based solutions.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on March 30, 2013, 01:59:18 PM
<clip>The correct result should have 4 elements:<clip>
Tony, see my previous:
>>>   (string-parse) is the function which the string->list
>>>   example function from that document was based on.
>>>   It was designed from the outset to parse CDF-formatted
>>>   data, where commas that appear between two double-quotes
>>>   are interpreted as literal text content, rather than
>>>   as delimiters.

Very correct, now I will try to write a new version for this  ;-)

Maybe tomorrow  :|

Happy Easter.

Marco
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 30, 2013, 02:24:14 PM
<clip>The correct result should have 4 elements:<clip>
Tony, see my previous:
>>>   (string-parse) is the function which the string->list
>>>   example function from that document was based on.
>>>   It was designed from the outset to parse CDF-formatted
>>>   data, where commas that appear between two double-quotes
>>>   are interpreted as literal text content, rather than
>>>   as delimiters.

Very correct, now I will try to write a new version for this  ;-)

Maybe tomorrow  :|

Happy Easter.

Marco

Marco - Happy Easter.

This is somewhat difficult to do using vl-string-position approach, but if we also want to remove extra whitespace, then it comes close to "mission impossible" :laugh:

There are many published algorithms for parsing CDF-format data (most in C++), and pretty-much every one that I've seen must go character-by-character to solve the problem completely.
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on March 30, 2013, 07:54:44 PM
Code - Text: [Select]
  1. Command: (setq result (string-parse str ","))
  2. ("552.32" "\"Smith, John\"" "42" "350")
  3.  
  4. Command: (length result) 4

This looked interesting to code, so here is my quick attempt:
Code: [Select]
(defun cdf->lst ( str / sub )
    (
        (setq sub
            (lambda ( str pos / tmp )
                (cond
                    (   (not (setq pos (vl-string-position 44 str pos)))
                        (list str)
                    )
                    (   (wcmatch (setq tmp (substr str 1 pos)) "\"*[~\"]")
                        (sub str (+ pos 2))
                    )
                    (   (cons tmp (sub (substr str (+ pos 2)) 0)))
                )
            )
        )
        str 0
    )
)
Code: [Select]
_$ (setq str "552.32,\"Smith, John\",42,350")
"552.32,\"Smith, John\",42,350"
_$ (cdf->lst str)
("552.32" "\"Smith, John\"" "42" "350")

Though it certainly won't be too fast by its recursive nature.
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 31, 2013, 03:25:59 AM
Hi Lee.

Yes that works. The only concern I would have with using recursion in a problem case like this one, in terms of speed, is that each recursive call receives a copy of the string argument that's passed by the caller.

Code - Text: [Select]
  1.  
  2. Command: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
  3. "552.32,\"Smith, John\",42,350,a,b,c,d"
  4.  
  5. Command: (trace sub)
  6. SUB
  7.  
  8. Command: (cdf->lst str)
  9. Entering (SUB "\"Smith, John\",42,350,a,b,c,d" 0)
  10.   Entering (SUB "\"Smith, John\",42,350,a,b,c,d" 8)
  11.     Entering (SUB "42,350,a,b,c,d" 0)
  12.       Entering (SUB "350,a,b,c,d" 0)
  13.         Entering (SUB "a,b,c,d" 0)
  14.           Entering (SUB "b,c,d" 0)
  15.             Entering (SUB "c,d" 0)
  16.               Entering (SUB "d" 0)
  17.               Result:  ("d")
  18.             Result:  ("c" "d")
  19.           Result:  ("b" "c" "d")
  20.         Result:  ("a" "b" "c" "d")
  21.       Result:  ("350" "a" "b" "c" "d")
  22.     Result:  ("42" "350" "a" "b" "c" "d")
  23.   Result:  ("\"Smith, John\"" "42" "350" "a" "b" "c" "d")
  24. Result:  ("\"Smith, John\"" "42" "350" "a" "b" "c" "d")
  25. ("552.32" "\"Smith, John\"" "42" "350" "a" "b" "c" "d")
  26.  
  27.  

In the above, even though the amount of data between each delimiters is relatively-small, each recursive call receives a copy of everything that remains, which would lead me to suspect that it may not be as fast as a simple iterative loop that operates on the list of ints returned by vl-string->list.

When doing classic recursion on a list, the only thing that gets copied is the cons cell for the CAR of the list, but with strings, each call requires a copy of the string to be made, which may bring us back to the main point I was making with my first post, the reason for avoiding numerous calls to (strcat).
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on March 31, 2013, 07:43:15 AM
Good point Tony.

I guess an iterative solution using vl-string->list could be something like:
Code: [Select]
(defun cdf->lst-i1 ( str / f )
    (read
        (vl-list->string
            (append '(40 34)
                (apply 'append
                    (mapcar
                        (function
                            (lambda ( x )
                                (cond
                                    (   (and (= 44 x) (not f))
                                       '(34 34)
                                    )
                                    (   (= 34 x)
                                        (setq f (not f))
                                       '(92 34)
                                    )
                                    (   (list x)   )
                                )
                            )
                        )
                        (vl-string->list str)
                    )
                )
               '(34 41)
            )
        )
    )
)

Or perhaps:
Code: [Select]
(defun cdf->lst-i2 ( str / r f )
    (setq r '(34 41))
    (foreach x (reverse (vl-string->list str))
        (cond
            (   (and (= 44 x) (not f))
                (setq r (vl-list* 34 34 r))
            )
            (   (= 34 x)
                (setq f (not f)
                      r (vl-list* 92 34 r)
                )
            )
            (   (setq r (cons x r)))
        )
    )
    (read (vl-list->string (vl-list* 40 34 r)))
)
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on March 31, 2013, 07:50:02 PM
I guess an iterative solution using vl-string->list could be something like:
Code: [Select]
(defun cdf->lst-i1 ( str / f )
    (read
        (vl-list->string
            (append '(40 34)
                (apply 'append
                    (mapcar
                        (function
                            (lambda ( x )
                                (cond
                                    (   (and (= 44 x) (not f))
                                       '(34 34)
                                    )
                                    (   (= 34 x)
                                        (setq f (not f))
                                       '(92 34)
                                    )
                                    (   (list x)   )
                                )
                            )
                        )
                        (vl-string->list str)
                    )
                )
               '(34 41)
            )
        )
    )
)

Or perhaps:
Code: [Select]
(defun cdf->lst-i2 ( str / r f )
    (setq r '(34 41))
    (foreach x (reverse (vl-string->list str))
        (cond
            (   (and (= 44 x) (not f))
                (setq r (vl-list* 34 34 r))
            )
            (   (= 34 x)
                (setq f (not f)
                      r (vl-list* 92 34 r)
                )
            )
            (   (setq r (cons x r)))
        )
    )
    (read (vl-list->string (vl-list* 40 34 r)))
)

I was interested in trying to get Marco's approach to work with the problem case that I wrote string-parse to solve, and while I was able to get it to work for quoted delimiters, the other special handling of the input string is still a tough nut to crack, and I'm not really sure that it would be worth the effort.

These days, with most of my work done in .NET and C++, I surely wouldn't attempt to put a LISP-based solution into actual use, but trying to get a working implementation is still a fun exercise, and so (quickly hacked-up and with minimal testing):

Code: [Select]

;; A version of (string-parse) that uses (vl-string-position) to find all
;; delimiters and double-quotes, properly ignoring delimiters contained in
;; literal text content surrounded by double-quotes.

(defun string-parse-revisited (str delim / ascdelim ascquote len indices qpos rslt)
   (setq ascdelim (ascii delim) ascquote 34)
   (if (not (setq indices (string-positions str ascdelim t)))
      (list str)
      (progn
         (if (setq qpos (string-positions str ascquote nil))
            (setq indices
               (apply 'append
                  (mapcar
                     (function
                        (lambda (x)
                           (cond
                              (  (eq (cdr x) 34)
                                 (setq flag (not flag))
                                 nil
                              )
                              (  (not flag)
                                 (list (car x))
                              )
                           )
                        )
                     )
                     (vl-sort
                        (append
                           (mapcar (function (lambda (i) (cons i ascdelim))) indices)
                           (mapcar (function (lambda (i) (cons i ascquote))) qpos)
                        )
                        (function (lambda (a b) (< (car a) (car b))))
                     )
                  )
               )
            )
         )
         (aggregate-binary indices
            (function
               (lambda (start end)
                  (substr str (1+ start) (- end start 1))
               )
            )
         )
      )
   )
)

;; Returns the results of applying the the given
;; function to pairs of adjacent elements in the
;; given list.

(defun aggregate-binary (aggbin:lst aggbin:func / aggbin:rslt)
   (while (cdr aggbin:lst)
      (setq aggbin:rslt
         (cons
            (apply aggbin:func (list (car aggbin:lst) (cadr aggbin:lst)))
            aggbin:rslt
         )
         aggbin:lst (cdr aggbin:lst)
      )
   )
   (reverse aggbin:rslt)
)

;; Returns the indices required by (substr) for extracting
;; the text delimited by adjacent-pairs of delimiters. If
;; the extents argument is non-nil, 0/1+ the length of the
;; string are added to the start/end of the result list.
;; If the input string contains no delimiter characters,
;; the result is nil regardless of whether extents is non-
;; nil or not.

(defun string-positions (str char extents / p c res len )
   (if (not (numberp char))
      (setq c (ascii char))
      (setq c char)
   )
   (setq len (strlen str))
   (setq pos -1)
   (while (setq pos (vl-string-position c str (1+ pos)))
      (setq res (cons (1+ pos) res))
   )
   (if (and res extents (>= len (car res)))
      (setq res (cons (1+ len) res))
   )
   (setq res (reverse res))
   (if (and res extents (> (car res) 0))
      (setq res (cons 0 res))
   )
   res
)


Code - Text: [Select]
  1.  
  2. Command: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
  3. "552.32,\"Smith, John\",42,350,a,b,c,d"
  4.  
  5. Command: (string-parse-revisited str ",")
  6. ("552.32" "\"Smith, John\"" "42" "350" "a" "b" "c" "d")
  7.  
  8.  
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 06, 2013, 01:37:48 PM
Tony and Lee,

sorry for late, now recommend to the moderator to open a new thread
for part of the functions of string-parse.
Here is my original function adapted to work for quoted delimiters:
Code: [Select]
; minimal testing
(defun ALE_String_ToListDQ (InpStr CarDlm / SttPos EndPos TmpLst SttDQt EndDQt)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (if
    (and
      (setq SttDQt (vl-string-position 34 InpStr))
      (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt)))
    )
    (progn
      (while EndPos
        (cond
          ( (and EndDQt (< SttDQt EndPos EndDQt))
            (setq EndPos (vl-string-position CarDlm InpStr (1+ EndPos)))
          )
          ( T
            (setq
              SttDQt (vl-string-position 34 InpStr (1+ EndPos))
              TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
              SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
            )
            (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
          )
        )
      )
      (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
    )
    (progn
      (while EndPos
        (setq
          TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
          SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
        )
      )
      (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
    )
  )
)

Code - Text: [Select]
  1. Comando: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
  2. "552.32,\"Smith, John\",42,350,a,b,c,d"
  3.  
  4. Comando: (ALE_String_ToListDQ str ",")
  5. ("552.32" "\"Smith, John\"" "42" "350" "a" "b" "c" "d")
  6.  

With StringBuildingTest.lsp I get this:
(setq string->list-slow ALE_String_ToListDQ)
(setq string->list-fast string-parse-revisited)

Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:

  (string->list-slow): 0.0262  >>> ALE_String_ToListDQ
  (string->list-fast): 0.1067  >>> string-parse-revisited

%%

(setq string->list-slow ALE_String_ToListDQ)
(setq string->list-fast cdf->lst-i2)

Comando: TEST_STRING_TO_LIST
Generating test data...
Working...
Test data string length: 348893
Result list length: 10000
Average of 6 median iterations:

  (string->list-slow): 0.031  >>> ALE_String_ToListDQ
  (string->list-fast): 0.567  >>> cdf->lst-i2

(defun cdf->lst-i2 ( str foo / r f )...
>>> Modified with 2 arguments
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on April 07, 2013, 11:09:31 AM
Hi Marco.

Very good.

CSV format allows contents of literal strings to also contain double-quotes, by using two consecutive double quotes, as in:

   "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"

Which should produce:

   ("a" "b" "c" "John \"The Baptist\" Smith" "4" "5" "6")

That problem is easily solved when processing each character (store the last-processed character, and if it is also a double-quote then treat it as literal content).

Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 07, 2013, 12:11:40 PM
Hi Marco.

Very good.

CSV format allows contents of literal strings to also contain double-quotes, by using two consecutive double quotes, as in:

   "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"

Which should produce:

   ("a" "b" "c" "John \"The Baptist\" Smith" "4" "5" "6")

That problem is easily solved when processing each character (store the last-processed character, and if it is also a double-quote then treat it as literal content).
Hi Tony,
do not you think that the CSV format normally is:  "a, b, c,John \"The Baptist\" Smith,4,5,6"
not "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" ?

Code: [Select]
Comando: (setq str  "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6")
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"

Comando: (ALE_String_ToListDQ str ",")
("a" " b" " c" "\"John \"\"The Baptist\"\" Smith\"" "4" "5" "6")

Comando: (setq str  "a, b, c,John \"The Baptist\" Smith,4,5,6")
"a, b, c,John \"The Baptist\" Smith,4,5,6"

Comando: (ALE_String_ToListDQ str ",")
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")

Comando: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
"552.32,\"Smith, John\",42,350,a,b,c,d"

Comando: (ALE_String_ToListDQ str ",")
("552.32" "\"Smith, John\"" "42" "350" "a" "b" "c" "d")


Code: [Select]
New shorter version:
; Version 1.10 - 07-04-2013 - minimal testing
(defun ALE_String_ToListDQ (InpStr CarDlm / SttPos EndPos TmpLst SttDQt EndDQt)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
    SttDQt (vl-string-position 34 InpStr)
  )
  (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
  (while EndPos
    (cond
      ( (and EndDQt (< SttDQt EndPos EndDQt))
        (setq EndPos (vl-string-position CarDlm InpStr (1+ EndPos)))
      )
      ( T
        (and SttDQt (setq SttDQt (vl-string-position 34 InpStr (1+ EndPos))))
        (setq
          TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
          SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
        )
        (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
      )
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 07, 2013, 12:19:58 PM
On the topic of CSV parsing, this (http://lee-mac.com/readcsv.html) is what I use (accounting for both quotes & commas present in the cell data, and also allowing for alternative cell delimiter characters) though I make no claims for its efficiency.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 07, 2013, 12:31:00 PM
On the topic of CSV parsing, this (http://lee-mac.com/readcsv.html) is what I use (accounting for both quotes & commas present in the cell data, and also allowing for alternative cell delimiter characters) though I make no claims for its efficiency.
Lee,
I'm sorry but I have some problems with the English language, I did not understand what you mean and where is your example.

"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"       is a correct CSV format?

Thanks for your time.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 07, 2013, 12:41:53 PM
Lee,

I tryed your function but I get error, where I am wrong?

(setq str  "a, b, c,John The Baptist Smith,4,5,6")
(LM:csv->lst str "," 0)
(setq str  "a, b, c,John \"The Baptist\" Smith,4,5,6")
(LM:csv->lst str "," 0)
(setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
(LM:csv->lst str "," 0)
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 07, 2013, 02:38:08 PM
On the topic of CSV parsing, this (http://lee-mac.com/readcsv.html) is what I use (accounting for both quotes & commas present in the cell data, and also allowing for alternative cell delimiter characters) though I make no claims for its efficiency.
I'm sorry but I have some problems with the English language, I did not understand what you mean and where is your example.

"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"       is a correct CSV format?

Sorry Marc, I should have explained further.

The string:
Code: [Select]
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"is indeed a valid CSV format.

My CSV parsing function will then return the result:
Code: [Select]
_$ (LM:csv->lst "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" 44 0)
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")
To demonstrate, try creating a CSV file with the above cell values and open the CSV file using a plain text editor.

Note that my function does not remove whitespace between cell data as I wrote the function with the intention to return the exact CSV content; if whitespace should be removed, the above result may be processed using:
Code: [Select]
_$ (mapcar '(lambda ( x ) (vl-string-trim " \t" x)) (LM:csv->lst "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" 44 0))
("a" "b" "c" "John \"The Baptist\" Smith" "4" "5" "6")

Sorry for the confusion.
Title: Re: Ignoring certain blocks on output
Post by: TheMaster on April 07, 2013, 03:09:06 PM
Hi Marco.

Very good.

CSV format allows contents of literal strings to also contain double-quotes, by using two consecutive double quotes, as in:

   "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"

Which should produce:

   ("a" "b" "c" "John \"The Baptist\" Smith" "4" "5" "6")

That problem is easily solved when processing each character (store the last-processed character, and if it is also a double-quote then treat it as literal content).
Hi Tony,
do not you think that the CSV format normally is:  "a, b, c,John \"The Baptist\" Smith,4,5,6"
not "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" ?

Code: [Select]
Comando: (setq str  "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6")
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"

Comando: (ALE_String_ToListDQ str ",")
("a" " b" " c" "\"John \"\"The Baptist\"\" Smith\"" "4" "5" "6")

Comando: (setq str  "a, b, c,John \"The Baptist\" Smith,4,5,6")
"a, b, c,John \"The Baptist\" Smith,4,5,6"

Comando: (ALE_String_ToListDQ str ",")
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")

Comando: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
"552.32,\"Smith, John\",42,350,a,b,c,d"

Comando: (ALE_String_ToListDQ str ",")
("552.32" "\"Smith, John\"" "42" "350" "a" "b" "c" "d")


Code: [Select]
New shorter version:
; Version 1.10 - 07-04-2013 - minimal testing
(defun ALE_String_ToListDQ (InpStr CarDlm / SttPos EndPos TmpLst SttDQt EndDQt)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
    SttDQt (vl-string-position 34 InpStr)
  )
  (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
  (while EndPos
    (cond
      ( (and EndDQt (< SttDQt EndPos EndDQt))
        (setq EndPos (vl-string-position CarDlm InpStr (1+ EndPos)))
      )
      ( T
        (and SttDQt (setq SttDQt (vl-string-position 34 InpStr (1+ EndPos))))
        (setq
          TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
          SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
        )
        (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
      )
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)

Hi Marco.  In an Excel sheet, enter this, including all the double-quotes:

       "John "the baptist" Smith"

Save to CSV, and look at the output.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 07, 2013, 04:04:21 PM
On the topic of CSV parsing, this (http://lee-mac.com/readcsv.html) is what I use (accounting for both quotes & commas present in the cell data, and also allowing for alternative cell delimiter characters) though I make no claims for its efficiency.
I'm sorry but I have some problems with the English language, I did not understand what you mean and where is your example.

"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"       is a correct CSV format?

Sorry Marc, I should have explained further.

The string:
Code: [Select]
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"is indeed a valid CSV format.

My CSV parsing function will then return the result:
Code: [Select]
_$ (LM:csv->lst "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" 44 0)
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")
To demonstrate, try creating a CSV file with the above cell values and open the CSV file using a plain text editor.

Note that my function does not remove whitespace between cell data as I wrote the function with the intention to return the exact CSV content; if whitespace should be removed, the above result may be processed using:
Code: [Select]
_$ (mapcar '(lambda ( x ) (vl-string-trim " \t" x)) (LM:csv->lst "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6" 44 0))
("a" "b" "c" "John \"The Baptist\" Smith" "4" "5" "6")

Sorry for the confusion.
OK Thanks.
My error was:
;;--------------------=={ CSV to List }==---------------------;;
;;                                                            ;;
;;  Parses a line from a CSV file into a list of cell values. ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2012 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string read from CSV file                           ;;
;;  sep - CSV separator token                                 ;;

>>> sep - CSV separator token   >>> in ascii value!

Ciao.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 07, 2013, 04:11:02 PM
Hi Marco.  In an Excel sheet, enter this, including all the double-quotes:

       "John "the baptist" Smith"

Save to CSV, and look at the output.
Tony,
 "John "the baptist" Smith"    it is very redundant!
Perhaps this is an acceptable result:
("a" " b" " c" "\"John \"\"The Baptist\"\" Smith\"" "4" "5" "6")

I go to sleep, good night.

Title: Re: Ignoring certain blocks on output
Post by: TheMaster on April 08, 2013, 07:21:26 PM
Hi Marco.  In an Excel sheet, enter this, including all the double-quotes:

       "John "the baptist" Smith"

Save to CSV, and look at the output.
Tony,
 "John "the baptist" Smith"    it is very redundant!
Perhaps this is an acceptable result:
("a" " b" " c" "\"John \"\"The Baptist\"\" Smith\"" "4" "5" "6")

I go to sleep, good night.

Hi Marco.

The underlying objective of the code which the list->string function from the document I attached to my OP in this thread is based on, is to correctly-parse CSV-formatted data coming from (amongt other sources) Excel.

To do that correctly requires the character-by-character approach, because of the special handling of data surrounded by double-quotes, including literal double-quotes between an outer pair of double-quotes. Is it redundant? Perhaps, but that is the CSV format, and code must be able to handle CSV- formatted data correctly. If it doesn't handle the data correctly, than how fast it runs is meaningless.

Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 09, 2013, 08:12:52 AM
If it doesn't handle the data correctly, than how fast it runs is meaningless.

Couldn't agree more.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 09, 2013, 10:51:48 AM
Nuovo tentativo (new attempt):
Code: [Select]
; Version 1.11 - 09-04-2013
(defun ALE_String_ToListDQ (InpStr CarDlm / SttPos EndPos TmpLst TmpStr TmpPos SttDQt EndDQt TrueFl)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
    SttDQt (vl-string-position 34 InpStr)
  )
  (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
  (while EndPos
    (and
      EndDQt
      (= "\"" (substr InpStr (1+ EndDQt) 1)) (setq TrueFl T)
      (setq EndDQt (vl-string-position 34 InpStr (+ 2 EndDQt)))
    )
    (cond
      ( (and EndDQt (< SttDQt EndPos EndDQt))
        (setq EndPos (vl-string-position CarDlm InpStr (1+ EndPos)))
      )
      ( T
        (and SttDQt (setq SttDQt (vl-string-position 34 InpStr (1+ EndPos))))
        (setq TmpStr (substr InpStr (1+ SttPos) (- EndPos SttPos)))
        (and
          TrueFl
          (setq TmpPos 0)
          (while (setq TmpPos (vl-string-search  "\"\"" TmpStr TmpPos))
            (setq TmpStr (vl-string-subst "\"" "\"\"" TmpStr TmpPos)
             TmpPos (1+ TmpPos)
            )
          )
          (setq TmpStr (vl-string-trim  "\"" TmpStr) TrueFl nil)
        )
        (setq
          TmpLst (cons TmpStr TmpLst)
          SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
        )
        (and SttDQt (setq EndDQt (vl-string-position 34 InpStr (1+ SttDQt))))
      )
    )
  )
  (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
)
(ALE_String_ToListDQ "a, b, c,\"John \"\"The,Baptist\"\" Smith\",4,5,6" ",")
=> ("a" " b" " c" "John \"The,Baptist\" Smith" "4" "5" "6")
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 09, 2013, 11:04:14 AM
Try this Marc:
Code: [Select]
(setq str "\"Smith,John\",\"\"\"The Baptist\"\"\"")
The result should be:
Code: [Select]
("Smith,John" "\"The Baptist\"")
:-)
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 09, 2013, 11:29:01 AM
Try this Marc:
Code: [Select]
(setq str "\"Smith,John\",\"\"\"The Baptist\"\"\"")
The result should be:
Code: [Select]
("Smith,John" "\"The Baptist\"")
:-)
:-(
"\"Smith,John\",\"\"\"The Baptist\"\"\""
do you think this is a valid value?, can you post an image of the cell? like in:
http://www.theswamp.org/index.php?topic=40660.msg459469#msg459469
Grazie.


Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 09, 2013, 11:47:09 AM
Try this Marc:
Code: [Select]
(setq str "\"Smith,John\",\"\"\"The Baptist\"\"\"")
The result should be:
Code: [Select]
("Smith,John" "\"The Baptist\"")
:-)
:-(
"\"Smith,John\",\"\"\"The Baptist\"\"\""
do you think this is a valid value?, can you post an image of the cell? like in:
http://www.theswamp.org/index.php?topic=40660.msg459469#msg459469
Grazie.

Sure:

(http://www.theswamp.org/lilly_pond/leemac/csvcellshot.png)

Providing the CSV delimiter is a comma, the above will yield a text value of:
Code: [Select]
"\"Smith,John\",\"\"\"The Baptist\"\"\""
Though, the example provided in the thread to which you have linked demonstrates a similar result if you needed proof.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 09, 2013, 12:11:55 PM
>> Providing the CSV delimiter is a comma, the above will yield a text value of: ...

I have modified my italian settings (also decimal sep.): "," ";"    to    "." ","
and now I can see.

Maybe I try a new attempt...

Ciao.
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 09, 2013, 12:15:34 PM
>> Providing the CSV delimiter is a comma, the above will yield a text value of: ...

I have modified my italian settings (also decimal sep.): "," ";"    to    "." ","
and now I can see.

Ah yes, the function also needs to account for the use of different CSV delimiters! :evil:
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 09, 2013, 12:48:24 PM
Ah yes, the function also needs to account for the use of different CSV delimiters! :evil:
May be we need to look the settings in Control Panel:
Excel                        :  Smith,John   "The Baptist"
CSV italian settings  :   Smith,John;"""The Baptist"""
CSV english settings:  "Smith,John","""The Baptist"""

Buona serata.
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 09, 2013, 01:10:41 PM
Ah yes, the function also needs to account for the use of different CSV delimiters! :evil:
May be we need to look the settings in Control Panel:
Excel                        :  Smith,John   "The Baptist"
CSV italian settings  :   Smith,John;"""The Baptist"""
CSV english settings:  "Smith,John","""The Baptist"""

Buona serata.

My Read CSV (http://lee-mac.com/readcsv.html) function does exactly that ;-)
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 10, 2013, 10:36:51 AM
Tony & Lee,

do you think that there are other special cases or the following examples cover all the possible complications?

Code: [Select]
Comando: (setq str "\"abc,123\",\"\"\"ABC\"\"\",\"abc\"\"ABC\"\"123\"")
"\"abc,123\",\"\"\"ABC\"\"\",\"abc\"\"ABC\"\"123\""
Comando: (LM:csv->lst str 44 0)
("abc,123" "\"ABC\"" "abc\"ABC\"123")

Comando: (setq str "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6")
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"
Comando: (LM:csv->lst str 44 0)
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")

Comando: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
"552.32,\"Smith, John\",42,350,a,b,c,d"
Comando: (LM:csv->lst str 44 0)
("552.32" "Smith, John" "42" "350" "a" "b" "c" "d")

Comando: (setq str "\"Smith,John\",\"\"\"The Baptist\"\"\"")
"\"Smith,John\",\"\"\"The Baptist\"\"\""
Comando: (LM:csv->lst str 44 0)
("Smith,John" "\"The Baptist\"")
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 10, 2013, 10:40:05 AM
IMHO > For moderator: as I wrote, maybe is better to move the CSV to List part of this discussion to anothet tr.
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 10, 2013, 12:02:10 PM
2 new attempts (similar engine with vl-string-position):
Code: [Select]
(defun ALE_StringSubstAll (NewStr PatStr InpStr SttPos / NewLen)
  (cond
    ( (= "" PatStr) InpStr )
    ( (setq NewLen (strlen NewStr))
      (while (setq SttPos (vl-string-search PatStr InpStr SttPos))
        (setq
          InpStr (vl-string-subst NewStr PatStr InpStr SttPos)
          SttPos (+ SttPos NewLen)
        )
      )
      InpStr
    )
  )
)
(defun ALE_String_CdfToList (InpStr CarDlm / SttPos EndPos TmpStr OutLst TmpElm)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (cond
      ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos) (- EndPos SttPos))) "\"*\"")
        (setq OutLst
          (cons
            (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0)
            OutLst
          )
        )
      )
      ( (wcmatch TmpElm "\"*") (setq TmpStr (substr TmpElm 2)) )
      ( TmpStr
        (setq OutLst
          (cons
            (strcat TmpStr (chr CarDlm) (substr TmpElm 1 (- (strlen TmpElm) 1)))
            OutLst
          )
          TmpStr nil
        )
      )
      ( T (setq OutLst (cons TmpElm OutLst)) )
    )
    (setq SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos))
  )
  (reverse
    (cons
      (cond
        ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos))) "\"*\"")
          (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0)
        )
        ( (wcmatch TmpElm "\"*")(setq TmpStr (substr TmpElm 2)) )
        ( TmpStr (strcat TmpStr (chr CarDlm) (substr TmpElm 1 (- (strlen TmpElm) 1))) )
        ( T TmpElm )
      )
      OutLst
    )
  )
)
(defun ALE_String_CdfToListFE (InpStr CarDlm / SttPos EndPos TmpLst TmpStr TmpPos OutLst)
  (setq
    CarDlm (ascii CarDlm)   SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
  )
  (while EndPos
    (setq
      TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
      SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
  )
  (foreach ForElm (cons (substr InpStr (1+ SttPos)) TmpLst)
    (cond
      (   (wcmatch ForElm "\"*\"")
          (setq TmpPos 0   ForElm (substr ForElm 2 (- (strlen ForElm) 2)))
          (while (setq TmpPos (vl-string-search  "\"\"" ForElm TmpPos))
            (setq
               ForElm (vl-string-subst "\"" "\"\"" ForElm TmpPos)
               TmpPos (1+ TmpPos)
            )
          )
          (setq OutLst (cons ForElm OutLst))
      )
      (  (wcmatch ForElm "*\"")
         (setq TmpStr (substr ForElm 1 (- (strlen ForElm) 1)))
      )
      ( TmpStr
        (setq OutLst
          (cons
            (strcat (substr ForElm 2) (chr CarDlm) TmpStr)
            OutLst
          )
          TmpStr nil
        )
      )
      ( T (setq OutLst (cons ForElm OutLst)) )
    )
  )
  OutLst
)

Test:
Code: [Select]
Comando: (setq str "\"abc,123\",\"\"\"ABC\"\"\",\"abc\"\"ABC\"\"123\"")
"\"abc,123\",\"\"\"ABC\"\"\",\"abc\"\"ABC\"\"123\""
Comando: (ALE_String_CdfToList str ",")
("abc,123" "\"ABC\"" "abc\"ABC\"123")
Comando: (ALE_String_CdfToListFE str ",")
("abc,123" "\"ABC\"" "abc\"ABC\"123")
Comando: (LM:csv->lst str 44 0)
("abc,123" "\"ABC\"" "abc\"ABC\"123")

Comando: (setq str "a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6")
"a, b, c,\"John \"\"The Baptist\"\" Smith\",4,5,6"
Comando: (ALE_String_CdfToList str ",")
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")
Comando: (ALE_String_CdfToListFE str ",")
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")
Comando: (LM:csv->lst str 44 0)
("a" " b" " c" "John \"The Baptist\" Smith" "4" "5" "6")

Comando: (setq str "552.32,\"Smith, John\",42,350,a,b,c,d")
"552.32,\"Smith, John\",42,350,a,b,c,d"
Comando: (ALE_String_CdfToList str ",")
("552.32" "Smith, John" "42" "350" "a" "b" "c" "d")
Comando: (ALE_String_CdfToListFE str ",")
("552.32" "Smith, John" "42" "350" "a" "b" "c" "d")
Comando: (LM:csv->lst str 44 0)
("552.32" "Smith, John" "42" "350" "a" "b" "c" "d")

Comando: (setq str "\"Smith,John\",\"\"\"The Baptist\"\"\"")
"\"Smith,John\",\"\"\"The Baptist\"\"\""
Comando: (ALE_String_CdfToList str ",")
("Smith,John" "\"The Baptist\"")
Comando: (ALE_String_CdfToListFE str ",")
("Smith,John" "\"The Baptist\"")
Comando: (LM:csv->lst str 44 0)
("Smith,John" "\"The Baptist\"")
/[code]
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 10, 2013, 12:23:28 PM
Lee,

(setq str "\"Smith,John\",\"\"\"The Baptist\"\"\",\"abc\"\"The Baptist\"\"123\",\"acb\"\"\",\"\"\"123\"")
Comando: (ALE_String_CdfToList str ",")
("Smith,John" "\"The Baptist\"" "abc\"The Baptist\"123" "acb\"" "\"123")
Comando: (ALE_String_CdfToListFE str ",")
("Smith,John" "\"The Baptist\"" "abc\"The Baptist\"123" "acb\"" "\"123")
Comando: (LM:csv->lst str 44 0)
("Smith,John" "\"The Baptist\"" "abc\"The Baptist\"123" "acb\"\",\"\"123")
                                                                                                 ^^^^^
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on April 10, 2013, 04:51:09 PM
Thanks Marc, I'll investigate. 8-)
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 11, 2013, 11:10:18 AM
New version for problems with multiple separator: "\"Smith,,,,,John\",123"
Code: [Select]
; Version 1.01 - 11-04-2013
(defun ALE_String_CdfToList (InpStr CarDlm / SttPos EndPos TmpStr OutLst TmpElm)
  (setq CarDlm (ascii CarDlm)   SttPos 0    EndPos (vl-string-position CarDlm InpStr))
  (while EndPos
    (cond
      ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos) (- EndPos SttPos))) "\"*\"")
        (setq OutLst (cons (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0) OutLst))
      )
      ( (wcmatch TmpElm "\"*") (setq TmpStr (substr TmpElm 2)) )
      ( (= TmpElm "") (if TmpStr (setq TmpStr (strcat TmpStr ",")) (setq TmpStr ",")) )
      ( TmpStr
        (setq
          OutLst (cons (strcat TmpStr (chr CarDlm) (substr TmpElm 1 (- (strlen TmpElm) 1))) OutLst)
          TmpStr nil
        )
      )
      ( T (setq OutLst (cons TmpElm OutLst)) )
    )
    (setq SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos))
  )
  (reverse
    (cons
      (cond
        ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos))) "\"*\"")
          (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0)
        )
        ( (wcmatch TmpElm "\"*")(setq TmpStr (substr TmpElm 2)) )
        ( TmpStr (strcat TmpStr (chr CarDlm) (substr TmpElm 1 (- (strlen TmpElm) 1))) )
        ( T TmpElm )
      )
      OutLst
    )
  )
)

Comando: (ALE_String_CdfToList "\"Smith,,,,,John\",123" ",")
("Smith,,,,,John" "123")
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on April 15, 2013, 11:02:47 AM
New version for problems with multiple separator: "\"Smith,,,,,John\",123"
New version for other problems:
Code: [Select]
; Version 1.02 - 15-04-2013
(defun ALE_String_CdfToList (InpStr CarDlm / AscDlm SttPos EndPos TmpStr OutLst TmpElm)
  (setq AscDlm (ascii CarDlm)   SttPos 0    EndPos (vl-string-position AscDlm InpStr))
  (while EndPos
    (cond
      ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos) (- EndPos SttPos))) "\"*\"")
        (setq OutLst (cons (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0) OutLst))
      )
      ( (and (not TmpStr) (wcmatch TmpElm "\"*")) (setq TmpStr (substr TmpElm 2)) )
      ( TmpStr
        (cond
          ( (= TmpElm "\"") (setq OutLst (cons (strcat TmpStr CarDlm) OutLst)  TmpStr nil) )
          ( (wcmatch TmpElm "*\"")
            (setq
              OutLst (cons (strcat TmpStr CarDlm (substr TmpElm 1 (- (strlen TmpElm) 1))) OutLst)
              TmpStr nil
            )
          )
          ( T (setq TmpStr (strcat TmpStr "," TmpElm)) )
        )
      )
      ( T (setq OutLst (cons TmpElm OutLst)) )
    )
    (setq SttPos (1+ EndPos) EndPos (vl-string-position AscDlm InpStr SttPos))
  )
  (reverse
    (cons
      (cond
        ( (wcmatch (setq TmpElm (substr InpStr (1+ SttPos))) "\"*\"")
          (ALE_StringSubstAll "\"" "\"\"" (substr TmpElm 2 (- (strlen TmpElm) 2)) 0)
        )
        ( (and (not TmpStr) (wcmatch TmpElm "\"*")) (substr TmpElm 2) )
        ( TmpStr
          (cond
            ( (= TmpElm "\"") (strcat TmpStr CarDlm) )
            ( (wcmatch TmpElm "*\"") (strcat TmpStr CarDlm (substr TmpElm 1 (- (strlen TmpElm) 1))) )
            ( T (strcat TmpStr "," TmpElm) )
          ) 
        )
        ( T TmpElm )
      )
      OutLst
    )
  )
)
Comando: (ALE_String_CdfToList "\",Smith,,r,,,John,,\",123,\",fd,,ffd,\"" ",")
(",Smith,,r,,,John,," "123" ",fd,,ffd,")
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on May 22, 2013, 11:16:19 AM
Lee,

(setq str "\"Smith,John\",\"\"\"The Baptist\"\"\",\"abc\"\"The Baptist\"\"123\",\"acb\"\"\",\"\"\"123\"")
Comando: (LM:csv->lst str 44 0)
("Smith,John" "\"The Baptist\"" "abc\"The Baptist\"123" "acb\"\",\"\"123")
                                                                                                 ^^^^^
Thanks Marc, I'll investigate. 8-)

I finally got around to looking into this and have now updated my ReadCSV function (http://lee-mac.com/readcsv.html):

Code - Auto/Visual Lisp: [Select]
  1. _$ (setq str "\"Smith,John\",\"\"\"The Baptist\"\"\",\"abc\"\"The Baptist\"\"123\",\"acb\"\"\",\"\"\"123\"")
  2. "\"Smith,John\",\"\"\"The Baptist\"\"\",\"abc\"\"The Baptist\"\"123\",\"acb\"\"\",\"\"\"123\""
  3. _$ (LM:csv->lst str "," 0)
  4. ("Smith,John" "\"The Baptist\"" "abc\"The Baptist\"123" "acb\"" "\"123")

@Marc:
Code - Auto/Visual Lisp: [Select]
  1. _$ (setq str "\",\",\",,\",\"\"\"\",\"\"\"\"\"\",\",\"\"\",\"\"\",\"\"\"")
  2. "\",\",\",,\",\"\"\"\",\"\"\"\"\"\",\",\"\"\",\"\"\",\"\"\""

Result should be:
Code - Auto/Visual Lisp: [Select]
  1. ("," ",," "\"" "\"\"" ",\"" "\",\"")

Code - Auto/Visual Lisp: [Select]
  1. _$ (LM:csv->lst str "," 0)
  2. ("," ",," "\"" "\"\"" ",\"" "\",\"")
  3. _$ (ALE_String_CdfToList str ",")
  4. ("," ",," "\"" "\"\"" "\"" "\"" "\"")

I guess it depends how far you wish to go with it...  :|
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on May 22, 2013, 01:22:24 PM
Result should be:
Code - Auto/Visual Lisp: [Select]
  1. ("," ",," "\"" "\"\"" ",\"" "\",\"")
Code - Auto/Visual Lisp: [Select]
  1. _$ (LM:csv->lst str "," 0)
  2. ("," ",," "\"" "\"\"" ",\"" "\",\"")
  3. _$ (ALE_String_CdfToList str ",")
  4. ("," ",," "\"" "\"\"" "\"" "\"" "\"")
I guess it depends how far you wish to go with it...  :|

Thanks  Lee, I'll investigate. (http://www.theswamp.org/Smileys/aaron/cool.gif)

Ciao
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on June 27, 2013, 12:17:10 PM
I will try again but I think it's out of my reach.
In the meantime I found another problem:

Comando: (LM:csv->lst "\"aaa," "," 0)
; errore: valore dell'argomento errato: string position out of range 6

Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on June 30, 2013, 06:48:15 PM
In the meantime I found another problem:

Comando: (LM:csv->lst "\"aaa," "," 0)
; errore: valore dell'argomento errato: string position out of range 6

Marc,

If possible, could you please attach the CSV file used to generate that string ("\"aaa,")?
With my understanding of the CSV format, that isn't valid CSV content.

Lee
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on July 01, 2013, 03:06:27 AM
My apologies Lee, I do not know if ("\"aaa,") is a valid CSV content, it came out doing some manual testing, delete my report.

Thank you.
Title: Re: Ignoring certain blocks on output
Post by: Lee Mac on July 01, 2013, 07:42:21 AM
My apologies Lee, I do not know if ("\"aaa,") is a valid CSV content, it came out doing some manual testing, delete my report.

No problem at all Marc  :-)

Regarding the validity of the string, if you were to input the string "aaa, in a blank text file and save the file to CSV format, upon opening the file in Excel, the first cell contains aaa,, however, after saving the file, the text file content becomes "aaa," as expected since the quotes should be paired.

Nevertheless, the error returned by my function could be quite easily avoided by changing line 26 to:
Code - Auto/Visual Lisp: [Select]
  1. (   (or (<= (strlen str) pos) (not (setq pos (vl-string-search sep str pos))))
Title: Re: Ignoring certain blocks on output
Post by: Marc'Antonio Alessi on July 01, 2013, 08:41:33 AM
 :kewl:

Thanks Lee, I do not think I'll be back again on this argument because I have reached saturation...
 :'(

Buona giornata.

Marco