Counting the Number of Lines in a Text Field
You may have a requirement to count the number of lines in a field that is coming from a database. One of our SCN members had this requirement recently.
Unfortunately there is no property in an object that grabs the object height…although that could come in very handy for this situation and others. And text objects have line breaks at the end of the last word that will fit in a line. This inconsistency makes the solution a bit more complicated than grabbing the length of the field and basing the number of lines partially on that length. After attempts at using the text object length and estimating lines without much success, the solution seems to involve tracking when a line breaks or in particular when a line is going to break.
The solution still involves knowing the maximum number of characters in a line and the use of a fixed width font such as Lucida Console. Please have a look at the attached report by unzipping the file and changing the file extension from .txt to .rpt.
Steps to use this technique on your report:
1) change the text object (the one that you need to count the number of lines) to use a fixed width font…apologies to those that don’t care for fixed width fonts but this is a requirement
2) now count the number of characters across you’d like the text object to be
3) create a new formula with the syntax below
stringvar t:= {Product_Type.Description};
numbervar ll:= 36; // set this to the desired width of the output, or line length, in characters > a fixed width font is recommended
// the code below does not need to be modified
stringvar o:= ”; // the formula output
stringvar en:= ‘ @@%%^^ ‘; // identifier used to replace “Enter” values in var t
t:= replace(t,chr(13)+chr(10), en) + ‘ ‘;
numbervar lt:= length(t);
numbervar i:= 1; // where the next word starts
numbervar nt; // where the next token or space starts
numbervar ntrt:= 0; // token running total
numbervar lc:= 1; // line counter
numbervar il:= 0; // character counter which is reset after each line
while i < lt do
(
nt:= instr(t[i to lt], ‘ ‘);
ntrt:= ntrt + nt;
stringvar nw:= t[i to ntrt]; // next whole word
numbervar lnw:= length(nw); // length of next whole word
if trim(nw) <> trim(en)
then
(
if ll – il + 1 >= lnw then o:= o + nw else
if ll – il + 1 < lnw then (il:= 0; lc:= lc + 1; o:= o + chr(10) + nw;)
)
else
(il:= 0; lc:= lc + 1; o:= o + chr(10))
;
if trim(nw) <> trim(en) then il:= il + lnw;
i:= i + nt;
);
o; // use this line (and comment out next line) to display the formula output which mimics your text
//lc; // use the line to display the number of lines output by the formula above
4) change the first stringvar to use your text field
5) change the first numbervar to use the number of characters per line that you wish to use
6) save the formula and make a duplicate of the formula
7) the first formula leave it as is and put on the report…this will count and display the number of lines of output of your field
8) the second formula, uncomment the second last line, and comment out the last line…this will then have stringvar “o” as the output which is the original text object, but with the line breaks inserted at the appropriate places
9) ensure that the second formula has been stretched wide enough to accommodate the desired width and that it has been formatted to Can Grow
I hope that you find this tecnhique helpful. If you are looking for any other solutions or workarounds for Crystal Reports, please see my blog here in particular the content section.
Wouldn't it be a lot easier just to split the whole string into an array, then count the number of items in the array - I make that about 3 lines of code!
Still wouldn't solve the problem of having carriage returns, but neither does your solution.
the problem with using an array is that you're limited to 1000 values. and using an array doesn't eliminate the need to check the length of the next word and count the number of characters you're at already...which was the requirement of this exercise and which also represents the majority of the code. please do post an array based solution though.
i do see what you mean if there's a hybrid of plain text and then some special ascii characters in the db...e.g. if there's regular text and then at the end of a paragraph there's a chr(13)+chr(10) in the field representing "Enter" in a db field. the solution above and the attachment have been modified to take this into account.