Fog Creek Software
Discussion Board




Tricky character counting alogorthim

I'm at the tail end of big accounting system integration.  Lots of data flying back and forth.  It's going well.  All of a sudden, this little,simple,easy request shows up on the rework list. 

"PO Comment field allows you to type more than four lines of text.  When I print, only four lines show.  Make it so the PO Comment field only allows four lines."

I think, "No problem."  Well, that was two days ago.  I've spent a good four or five hours and my brain is mush.  If this turns out to be something simple, I will probably just kill myself :)  But I'm convinced it's just a complicated problem. 

Here are the parameters:
(1) There are 50 characters per printed line.
(2) The PO Comment box allows you type free form including carriage returns.  The only limit on what you can type is that when you have typed 120 characters without a carriage return,you are forced to type a hard return.

So what I'm looking for is a formula to run in the OnChange event that will calculate how close I am to the 4 line/200 character limit. 

As I said, it seems pretty simple.  But I have torn my hair out trying to come up with a math formula that makes this work. 

Examples of what has to be "caught"

xxxxxxx...........xxxxxxxxx (120)<CR>
xxxxxx(50)

Only 170 characters, but with two automatic wraps and a forced CR, you have three lines, plus 50=40 lines

<CR>
<CR>
<CR>
xxxxxxxxxxxxxx(50)

Only 50 characters, but I wasted three lines with the 1st 3 CRs

So there it is.  Think of it as a brain teaser if you want.  I'll give you credit in the source code and to everyone else on my team and the client if you post an answer that works. 


How

Frustrated by the obvious(?)
Thursday, March 18, 2004

Cheap solution: make the field 50x4. Put a note next to it saying "if you can't see your message in the box, it won't print".

Otherwise, while I've not done that sort of stuff in quite a while, can't you just examine the string itself? Search for newlines? I'm sorry if I missed something obvious, but I don't see what makes this a hard problem. Assuming you can access the individual characters, at least.

Mike Swieton
Thursday, March 18, 2004

How about this...

If a line is >= 50 characters remove all "forced" CR's from the text.

The number of lines then are
(int) (total characters in lines >= 50 chars/50) + 1.

Add to that number all the lines which are less than 50 characters and you have the total lines.

Code Monkey
Thursday, March 18, 2004

Yah - just scan the text and count the number of CR and lines > 50

Bad Pseudocode:

Numlines = 0
TempLine = ""

For I = 1 to Len(POComments)
    If POComments(I) = CR then
        NumLines = Numlines +1
        TempLine = ""
    Else
        TempLine = Templine + POComments(I)
        If Len(TempLine) = 50 then
            NumLines = Numlines +1
            TempLine = ""
        End
    End
Next

If NumLines > 4 then
  Msg "Hey you - too many lines"
End

This has to stop
Thursday, March 18, 2004

I like the cheap solution.  I'll check to see if we can resize it as was suggested. 

In case that doesn't work,

>>(int) (total characters in lines >= 50 chars/50) + 1

You lost me on this, can you reword?

Frustrated by the obvious(?)
Thursday, March 18, 2004

This has to stop,
Yeah I think that might work.  I guess I was looking for a "cool" formula that wouldn't make me parse the string.  No reason for that really, other than it would be "nicer" or "purer".  This is more brute force, but certainly good enough. 

Frustrated by the obvious(?)
Thursday, March 18, 2004

Split out each line (just by scanning for newline, if you can't directly access it per-line)

For each newline, numLines++
if (length(line) > 100) numLines += 2
else if (length(line) > 50) numLines++

is there some issue with this?  You might have to deal with a corner case of having an unneccessary newline at the end of the last line, but that shouldn't be too hard to figure out

MikeMcNertney
Thursday, March 18, 2004

>>(int) (total characters in lines >= 50 chars/50) + 1

Count all the non CR characters in your textbox, and divide by 50. (50 being the max per line). Round that number to the next higher integer.

132/50=2.64 round that to 3.

This will get you the number of lines needed to fit the text for printing, with the 50 chars per line maximum.

Patrik
Thursday, March 18, 2004

Not disputing any of the above.  But...

All these solutions, and the original request, assume a known, fixed-width font.  Make sure that the font can be easily changed without upsetting the printing.  It will change:-)

David

David Freeman
Thursday, March 18, 2004

Patrick, I don't think that gives you a useful measure.  With 132 characters you could have 4 lines of legal text (say 40, 40, 40, 12), or you could have something like 1, 1, 1, 129... which would be more than 4 lines total because the last line would be split in 3

MikeMcNertney
Thursday, March 18, 2004

Mike,

True. I stand corrected. Didn't think about that scenario.

Patrik
Thursday, March 18, 2004

Re: Fixed Width Font

Yes, the reports are fixed width font based. 

Frustrated by the obvious(?)
Thursday, March 18, 2004

Is this a Windows Edit control?  If so, you can modify the text in the Change notification (or even better, the Update notification) in order to enforce the limits.  If the line count is greater than four, chop the lines off until there are less than four.  If the char count is greater than 120, chop the lines down until they're shorter than 120 chars.  If this isn't Windows, perhaps there's a similiar solution on your platform? 

SomeBody
Thursday, March 18, 2004

As has essentially already been said, the trivial 'algorithm' works with a fixed width font.  In that case, you count a line if you encounter N characters, or a newline (whichever comes first).

If you want it to work with variable width fonts then the algorithm is only slightly more difficult, but if you don't want to bother with the little geometry problem you can send your edit control the EM_GETLINECOUNT message.

K
Thursday, March 18, 2004

Each logical line occupies one physical line, plus one physical line for each complete 50 characters. (I'm guessing that 50 characters with a CR at the end means you get a blank line. I'll say later how to fix that.)

Therefore, for a line with n characters you have 1 + floor(n/50) lines. So the total number of physical lines is the sum of this expression over all your logical lines.

However, if a 50-character line occupies only 1 physical line (so that you can't tell the difference between 50*'x'+50*'y' and 50*'x'+newline+50*'y') then an n-character logical line occupies max(1, ceiling(n/50)) physical lines, so sum that over all your logical lines.

The second of these is equivalent to Mike McNerty's solution above except that it's shorter (if you have max and ceiling functions available) or longer (if you don't) and doesn't rely on the "all logical lines are <= 120 characters long" thing.

Gareth McCaughan
Friday, March 19, 2004

Why force the users to type a newline after an arbitrary number of characters? It's obvious that it doesn't make printing any easier, so what's the reasoning behind the "120 characters -> force a new line" rule?

Martha
Friday, March 19, 2004

Cool, thanks for all the responses.  The application, Great Plains, is the one using non standard controls and imposing 120 character hard limits.  I'm just trying to work around it. 

Frustrated by the obvious(?)
Friday, March 19, 2004

Can you just create four 50 char boxes???

Line 1:
Line 2:
Line 3:
Line 4:

Kind of cheesy but dead simple and no code...

This has to stop
Friday, March 19, 2004

*  Recent Topics

*  Fog Creek Home