Author Topic: How to stop chopping words in long strings  (Read 3562 times)

0 Members and 1 Guest are viewing this topic.

Offline lawsonm1

  • Newbie
  • Posts: 64
    • View Profile
How to stop chopping words in long strings
« on: December 28, 2019, 01:30:02 pm »
Does anyone know how I can stop having words chopped up when displaying long stings? If I have a string that is longer than what will display on a single line, some words get split up when I try to PRINT them to the screen. Thanks, Mike

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: How to stop chopping words in long strings
« Reply #1 on: December 28, 2019, 02:42:25 pm »
You need a basic word wrapping routine for output:

Code: QB64: [Select]
  1. 'SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. LOCATE 1, 21 'to test a line with an offset
  4. test$ = "This is a very long sentence which runs on and on and one and even contains tipos and errors and goofs and mistakes and all sorts of junk, but it is good for testing if we have word breaks working properly for us!"
  5. WordWrap test$, -1
  6. PRINT 'to test a line from the starting point
  7. WordWrap test$, -1
  8. PRINT "=============="
  9. WordWrap test$, 0 'And this shows that we can wordwrap text without automatically moving to a new line
  10. WordWrap test$, -1 'As this line picks up right where the last one left off.
  11.  
  12.  
  13.  
  14. SUB WordWrap (text AS STRING, newline)
  15.     DIM BreakPoint AS STRING
  16.     BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints.  If you want something else, change them.
  17.  
  18.     w = _WIDTH
  19.     pw = _PRINTWIDTH(text)
  20.     x = POS(0): y = CSRLIN
  21.     IF _PIXELSIZE <> 0 THEN x = x * _FONTWIDTH
  22.     firstlinewidth = w - x + 1
  23.     IF pw <= firstlinewidth THEN
  24.         PRINT text;
  25.         IF newline THEN PRINT
  26.     ELSE
  27.         'first find the natural length of the line
  28.         FOR i = 1 TO LEN(text)
  29.             p = _PRINTWIDTH(LEFT$(text, i))
  30.             IF p > firstlinewidth THEN EXIT FOR
  31.         NEXT
  32.         lineend = i - 1
  33.         t$ = RTRIM$(LEFT$(text, lineend)) 'at most, our line can't be any longer than what fits the screen.
  34.         FOR i = lineend TO 1 STEP -1
  35.             IF INSTR(BreakPoint, MID$(text, i, 1)) THEN lineend = i: EXIT FOR
  36.         NEXT
  37.         PRINT LEFT$(text, lineend)
  38.         WordWrap LTRIM$(MID$(text, lineend + 1)), newline
  39.     END IF
  40.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline lawsonm1

  • Newbie
  • Posts: 64
    • View Profile
Re: How to stop chopping words in long strings
« Reply #2 on: December 28, 2019, 03:34:46 pm »
Thanks Steve. It works just wonderful. I have used GWBASIC in the past, but that doesn't work anymore on Windows 10. So I'm still getting used to QB64, and trying to clean up the cobwebs from using BASIC years ago. I'm using this as part of a educational program I'm writting for my two kids to help them in school. Thanks again, Mike

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: How to stop chopping words in long strings
« Reply #3 on: December 28, 2019, 08:15:27 pm »
Here are a couple more wrappings:

For just printing:
Code: QB64: [Select]
  1. _TITLE "wrap$ test" 'b+ 2019-12-28  a simple way
  2.  
  3. 'now test in graphics screen
  4. 'SCREEN _NEWIMAGE(640, 600, 32) 'now test in graphics screen
  5.  
  6. PRINT "Here is our test string:"
  7. test$ = "12345678901234567890123456789012345678901234567890123456789012345678901234567890     Here is a super long string to test with the wrap$ Function that splits a string at first space found before the maxLen limit to keep the strings at or under the maxLen length."
  8. PRINT test$
  9. PRINT "press any for printWrap demo... "
  10.  
  11. PRINT "Here is printWrap at row = 12, col = 1, wrap length is 80:"
  12. printWrap test$, 80, 12, 1
  13. LOCATE 25, 20: PRINT "press any for another demo... ";
  14.  
  15. PRINT "Here is printWrap at row = 9, col = 20, wrap length is 40:"
  16. printWrap test$, 40, 9, 20
  17. LOCATE 25, 20: PRINT "press any for another demo... ";
  18.  
  19. PRINT "Here is printWrap at row = 5, col = 30, wrap length is 20:"
  20. printWrap test$, 20, 5, 30
  21. LOCATE 24, 20: PRINT "end of demos... ";
  22.  
  23.  
  24. 'This function returns the first segment of string less than or equal to maxLen AND
  25. 'the remainder of the string (if any) is returned in tail$ to be used by wrap$ again
  26. FUNCTION wrap$ (s$, maxLen, tail$)
  27.     IF LEN(s$) > maxLen THEN
  28.         p = maxLen + 1
  29.         WHILE MID$(s$, p, 1) <> " " AND p > 1
  30.             p = p - 1
  31.         WEND
  32.         IF p = 1 THEN
  33.             wrap$ = MID$(s$, 1, maxLen): tail$ = MID$(s$, maxLen + 1)
  34.         ELSE
  35.             wrap$ = MID$(s$, 1, p - 1): tail$ = MID$(s$, p + 1)
  36.         END IF
  37.     ELSE
  38.         wrap$ = s$: tail$ = ""
  39.     END IF
  40.  
  41. 'this sub uses the wrap$ function to print out a string with row and column offsets
  42. SUB printWrap (s$, maxLen, rowOffset, colOffset)
  43.     ss$ = s$ 'work with copy
  44.     DO
  45.         LOCATE rowOffset + i, colOffset: PRINT wrap$(ss$, maxLen, st$)
  46.         ss$ = st$
  47.         i = i + 1
  48.     LOOP UNTIL LEN(ss$) = 0
  49.  

For storing and appending fixed lengths in a array and using when and where needed:
Code: QB64: [Select]
  1. _TITLE "wrapAppend test" 'b+ 2019-12-28  a less simple way
  2.  
  3. test$ = "1234567890123456789012345678901234567890     Here is a rather long string to test with the wrap$ SUB that splits a string at first space found before the maxLen limit to keep the strings at or under the maxLen length and appends these segments to an Dynamic Array which is handy to track number of rows."
  4. test2$ = "     And here is a 2nd very long line to see how well it appends to the first long line in the dynamic array holding all the segments at maxLen or less."
  5. PRINT "Here is our first test string:"
  6. PRINT test$
  7. PRINT "Here is 2nd string for our test of appending fixed length string to an array:"
  8. PRINT test2$
  9. PRINT: PRINT "press any for first demo... "
  10.  
  11. REDIM testArr$(1 TO 1) '<<< dynamic array
  12. wrapAppend test$, 40, testArr$()
  13. wrapAppend "     Hey! add this short line too.", 40, testArr$()
  14. wrapAppend test2$, 40, testArr$()
  15. PRINT "Here are the 2 strings split at max lengths of 40 and stored in an array:"
  16. FOR i = LBOUND(testArr$) TO UBOUND(testArr$)
  17.     PRINT "Row"; i, testArr$(i)
  18. PRINT "Press any to see a centered display..."
  19.  
  20. ub = UBOUND(testArr$)
  21. sRow = (_HEIGHT - ub) \ 2
  22. sCol = 20
  23. FOR i = LBOUND(testArr$) TO ub
  24.     LOCATE sRow + i, sCol: PRINT testArr$(i);
  25.  
  26. 'this sub splits a string at first spaces less than maxlen + 1
  27. SUB wrapAppend (s$, maxLen AS INTEGER, dynamicArr$()) 'appends strings from s$ to arr$()at lengths of maxLen and under
  28.     ss$ = s$ 'copy s$ because going to change it
  29.     ub = UBOUND(dynamicArr$)
  30.     lb = LBOUND(dynamicArr$)
  31.     WHILE LEN(ss$) > maxLen
  32.         p = maxLen + 1
  33.         WHILE MID$(ss$, p, 1) <> " " AND p > 1
  34.             p = p - 1
  35.         WEND
  36.         IF ub = lb AND LEN(dynamicArr$(lb)) = 0 THEN ELSE ub = ub + 1: REDIM _PRESERVE dynamicArr$(lb TO ub)
  37.         IF p = 1 THEN
  38.             dynamicArr$(ub) = MID$(ss$, 1, maxLen)
  39.             ss$ = MID$(ss$, maxLen + 1)
  40.         ELSE
  41.             dynamicArr$(ub) = MID$(ss$, 1, p - 1)
  42.             ss$ = MID$(ss$, p + 1)
  43.         END IF
  44.     WEND
  45.     IF LEN(ss$) THEN
  46.         IF ub = lb AND LEN(dynamicArr$(lb)) = 0 THEN ELSE ub = ub + 1: REDIM _PRESERVE dynamicArr$(lb TO ub)
  47.         dynamicArr$(ub) = ss$
  48.     END IF
  49.  
  50.  
  51.  

« Last Edit: December 28, 2019, 08:23:48 pm by bplus »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: How to stop chopping words in long strings
« Reply #4 on: December 29, 2019, 01:50:44 am »
Let's not forget about our new exciting keyword _INSTRREV...

Code: QB64: [Select]
  1. WIDTH 80, 43
  2. a$ = "The quick brown fox ran through the dense forrest."
  3. lmargin = 1
  4. rmargin = 50
  5. IF RIGHT$(a$, 1) <> " " THEN a$ = a$ + " "
  6. DO UNTIL rmargin = 0
  7.     LOCATE 1, lmargin - 1 + rmargin + 1
  8.     FOR i = 1 TO 42
  9.         LOCATE , rmargin + 1
  10.         PRINT "|"
  11.     NEXT
  12.     seed = 1
  13.     LOCATE 1, lmargin
  14.     DO UNTIL INSTR(seed, a$, " ") = 0
  15.         z$ = MID$(a$, seed, rmargin - lmargin + 2)
  16.         IF lmargin = rmargin THEN z$ = MID$(z$, 1, LEN(z$) - 1)
  17.         IF RIGHT$(z$, 1) = " " THEN
  18.             x = LEN(z$)
  19.         ELSE
  20.             x = _INSTRREV(z$, " ")
  21.         END IF
  22.         IF x = 0 THEN x = rmargin - lmargin + 1
  23.         PRINT RTRIM$(MID$(a$, seed, x))
  24.         IF rmargin = lmargin AND x = 0 THEN SYSTEM
  25.         seed = seed + x
  26.     LOOP
  27.     DO
  28.         _LIMIT 30
  29.         b$ = INKEY$
  30.         IF LEN(b$) THEN
  31.             SELECT CASE b$ ' Use left / right arrow keys to decrease / increase page width.
  32.                 CASE CHR$(27)
  33.                     SYSTEM
  34.                 CASE CHR$(0) + "M"
  35.                     IF rmargin < 80 - 1 THEN rmargin = rmargin + 1: EXIT DO
  36.                 CASE CHR$(0) + "K"
  37.                     IF rmargin > lmargin THEN rmargin = rmargin - 1: EXIT DO
  38.             END SELECT
  39.         END IF
  40.     LOOP
  41.     CLS


... These are the things I think about at work.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline lawsonm1

  • Newbie
  • Posts: 64
    • View Profile
Re: How to stop chopping words in long strings
« Reply #5 on: December 29, 2019, 12:03:12 pm »
Steve, I have noticed that if there are single quotes in the text string, then they get displayed as some other character, as in from a completely different font. I'm sure I am missing something... Thanks, Mike

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: How to stop chopping words in long strings
« Reply #6 on: December 29, 2019, 12:22:11 pm »
Steve, I have noticed that if there are single quotes in the text string, then they get displayed as some other character, as in from a completely different font. I'm sure I am missing something... Thanks, Mike

We don't do anything to the character values with the little routine I posted, except just choose a suitable breakpoint and stop printing the text at that point, before moving to the next line to start again.

Testing with the following code, I don't generate any odd characters with the program, that I can see:

Code: [Select]
SCREEN _NEWIMAGE(640, 480, 32)

LOCATE 1, 21 'to test a line with an offset
test$ = "This is a '''' " + CHR$(34) + " ```` very long sentence which runs on and on and one and even contains tipos and errors and goofs and mistakes and all sorts of junk, but it is good for testing if we have word breaks working properly for us!"
WordWrap test$, -1
PRINT 'to test a line from the starting point
WordWrap test$, -1
PRINT
PRINT "=============="
PRINT
WordWrap test$, 0 'And this shows that we can wordwrap text without automatically moving to a new line
WordWrap test$, -1 'As this line picks up right where the last one left off.



SUB WordWrap (text AS STRING, newline)
    DIM BreakPoint AS STRING
    BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints.  If you want something else, change them.

    w = _WIDTH
    pw = _PRINTWIDTH(text)
    x = POS(0): y = CSRLIN
    IF _PIXELSIZE <> 0 THEN x = x * _FONTWIDTH
    firstlinewidth = w - x + 1
    IF pw <= firstlinewidth THEN
        PRINT text;
        IF newline THEN PRINT
    ELSE
        'first find the natural length of the line
        FOR i = 1 TO LEN(text)
            p = _PRINTWIDTH(LEFT$(text, i))
            IF p > firstlinewidth THEN EXIT FOR
        NEXT
        lineend = i - 1
        t$ = RTRIM$(LEFT$(text, lineend)) 'at most, our line can't be any longer than what fits the screen.
        FOR i = lineend TO 1 STEP -1
            IF INSTR(BreakPoint, MID$(text, i, 1)) THEN lineend = i: EXIT FOR
        NEXT
        PRINT LEFT$(text, lineend)
        WordWrap LTRIM$(MID$(text, lineend + 1)), newline
    END IF
END SUB

Can you provide an example of the code which is displaying character substitutions?  I'll be happy to help with debugging it for you, if I can.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline lawsonm1

  • Newbie
  • Posts: 64
    • View Profile
Re: How to stop chopping words in long strings
« Reply #7 on: December 29, 2019, 10:09:01 pm »
Thanks. I did a little bit of testing some things, but I'm thinking it may be more related to the application I use for creating the text file I load that gets parsed. The computer I run QB64 on is a Windows10 machine and I generated the text file using LibreOffice 6.1. But I was editing the file on my laptop, which is Windows 8.1 and running Excel 2010. The text file is a comma separated .csv file. I'll fiddle some more tomorrow to see if I can get the error to come back. I'll let you know one way or another. Thanks again, Mike

Offline lawsonm1

  • Newbie
  • Posts: 64
    • View Profile
Re: How to stop chopping words in long strings
« Reply #8 on: December 30, 2019, 09:41:47 pm »
Steve, I did some more testing, and so far it appears that the file is changed when I use LibreOffice Calc. It works fine when I use Microsoft Excel to create and modify the .csv file. Thanks again for your help, Mike