Using StrParse? Be careful!


If you use VisualNeo Win’s StrParse, you have to be careful because of two issues.

  1. StrParse gives not always correct results and
  2. StrParse is rather slow and can cause your program to freeze.

Let’s start with the first issue.

Figure 1


In the texteditor Notepad++, I entered the number 1, pressed the Enter key, entered the number 2 and pressed the Enter key again. The cursor is on line 3 as the blue rectangle and the line gutter number 3 suggests: see Figure 1.

The two lines are separated by the delimiter CRLF, which is the same as the backslash escapes \r\n and as [#13][#10] in VisualNeo Win. The empty third line has no End of Line symbol.

If the variable [mc-text] contains the entered data then

strparse "[mc-text]" "[#13][#10]" "[line]" "[number-of-lines]"

should generate the variable [number-of-lines] with the value 3. But this is not true: [number-of-lines] has the value 2. So, the empty last line is not counted by VisualNeo Win.

The newLISP equivalent generates the correct number 3.

hpwnewlispcall "(length (parse {[mc-text]} {\r\n} 0))" "[number-of-lines]"

The code (parse {[mc-text]} {\r\n} 0) results in the list (“1” “2” “”) which contains 3 elements. The length of this list is of course 3, corresponding to the 3 lines in Figure 1.

The second issue (‘StrParse is rather slow and can cause your program to freeze’) can be demonstrated in an application with a text entry field. The application not only determines the number of text lines but also returns the line number where the cursor was positioned. Basically, you need the next VisualNeo Win code for these tasks where mctext is the text entry object and [mc-text] the variable that contains the text.

.buggy, result has to incremented by 1
strparse "[mc-text]" "[#13][#10]" "[line]" "[number-of-lines]"
getobjectinfo "mctext" "cursorposition" "[cursor-position]"
substr "[mc-text]" "1" "[cursor-position]" "[extracted-substring]"
.buggy, result has to incremented by 1
strparse "[extracted-substring]" "[#13][#10]" "[lines]" "[cursor-is-on-line]"

Some explanation. In Figure 1, the cursor position is 5, which is the result of the getobjectinfo function:

getobjectinfo "mctext" "cursorposition" "[cursor-position]"

The substring [extracted-substring] contains the characters from position 1 to the cursor position 5: 1[#13][#10]2[#13][#10] The number of [#13][#10] is 2, so the variable [cursor-is-on-line] should be 3.

Apart from the bug, the VisualNeo Win code works fine only if the application has to process small texts. However, in case of large texts, the application will freeze.

Speeding up your application can easily be done by applying newLISP. 150.000 text lines (and even more) are no problem for newLISP and are processed within a fraction of a second! The relevant newLISP code is straightforward.

.to make the newLISP code more readable, two variables [t] and [/t], containing text tags;
.notice also that these tags [#91]text[#93] and [#91]/text[#93] around the text variable are necessary.
setvar "[t]" "[#91]text[#93]"
setvar "[/t]" "[#91]/text[#93]"
hpwnewlispcall "(length (parse [t][mc-text][/t] {\r\n} 0))" "[number-of-lines]"
getobjectinfo "mctext" "cursorposition" "[cursor-position]"
substr "[mc-text]" "1" "[cursor-position]" "[extracted-substring]"
hpwnewlispcall "(length (parse [t][extracted-substring][/t] {\r\n} 0))" "[cursor-is-on-line]"

(You may wonder, why I still use the VisualNeo function substr. Well, this function is fast enough and seems not be beaten by a newLISP equivalent – at least not convincingly).

To implement this code in an application, use it in a Timer object. I made a sample PUB for you to test and experiment: download here. Notice that you have to install Hans-Peter Wickern’s excellent newLISP plugin. I hope it helps.

Thanks for reading!

Reinier Maliepaard