Break long string onto shorter lines

General FreeBASIC programming questions.
Post Reply
ITomi
Posts: 154
Joined: Jul 31, 2015 11:23
Location: Hungary

Break long string onto shorter lines

Post by ITomi »

Hello!
I have a problem when I try break a long string at spaces to fit the screen: I got an "Aborting due to runtime error 6 (out of bounds array access) at line 13" error message.
This is my code:

Code: Select all

#include "fbgfx.bi"
Using FB

dim as string letter,a_line,a_string
dim as ubyte numoflines,endoftheprogram=0
dim lines(any) as string
dim as ushort placeintheline=1,prevspace=1,numofletters=0,startintheline=1
a_string="This is a long string onto the screen and maybe it will be break correctly with this piece of code."
for c as ushort=1 to len(a_string)
    numofletters+=1 : placeintheline+=1
    letter=mid(a_string,c,1)
    if (numofletters*8>=80 and letter=" ") or c=len(a_string) then 
        lines(numoflines)=mid(a_string,startintheline,prevspace-startintheline) : numoflines+=1
        if c<len(a_string) then
            numofletters=0 : c=prevspace+1 : startintheline=c : placeintheline=c
        end if
    elseif letter=" " and numofletters*8<80 then prevspace=placeintheline
    end if
next c

do
    for l as ubyte=0 to numoflines-1
        print lines(l)
    next l
    if multikey(sc_enter) then endoftheprogram=1
loop until endoftheprogram=1
What is the problem with that array? And, I'm not sure that my program is correct. Is this the best and simpliest way to dismember a string to fit the screen with its substrings? I would like cut the string at the last spaces what fits onto the screen.
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: Break long string onto shorter lines

Post by srvaldez »

you use dim lines(any) as string but you never redimed the array
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Break long string onto shorter lines

Post by MrSwiss »

Your code currently seems to cater for 'standard size' console only (25 x 80).
Using Width to get the 'real' console size as may be set (in WIN at least) would make the code more universal.
For re-usability I'd use a procedure to split the string (rather than doing it in main code).
Xusinboy Bekchanov
Posts: 789
Joined: Jul 26, 2018 18:28

Re: Break long string onto shorter lines

Post by Xusinboy Bekchanov »

That's right:

Code: Select all

#include "fbgfx.bi"
Using FB

Dim As String letter,a_line,a_string
Dim As UByte numoflines,endoftheprogram=0
Dim lines(Any) As String
Dim As UShort placeintheline=1,prevspace=1,numofletters=0,startintheline=1
a_string="This is a long string onto the screen and maybe it will be break correctly with this piece of code."
For c As UShort=1 To Len(a_string)
    numofletters+=1 : placeintheline+=1
    letter=Mid(a_string,c,1)
    If (numofletters*8>=80 And letter=" ") Or c=Len(a_string) Then
    	ReDim lines(numoflines)
        lines(numoflines)=Mid(a_string,startintheline,prevspace-startintheline) : numoflines+=1
        If c<Len(a_string) Then
            numofletters=0 : c=prevspace+1 : startintheline=c : placeintheline=c
        End If
    ElseIf letter=" " And numofletters*8<80 Then prevspace=placeintheline
    End If
Next c

Do
    For l As UByte=0 To numoflines-1
        Print lines(l)
    Next l
    If MultiKey(sc_enter) Then endoftheprogram=1
Loop Until endoftheprogram=1
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Break long string onto shorter lines

Post by fxm »

My beta version:

Code: Select all

Declare Sub formatting (sarray() as string, Byval sline As String, Byval w As Integer = 80)

dim as string a_string
dim lines(any) as string

a_string="This is a long string onto the screen and maybe it will be break correctly with this piece of code."

formatting(lines(),a_string, Loword(width))

Print a_string
Print
Print "formatted into " & ubound(lines) + 1 & " line(s):"
for i as integer = 0 to ubound(lines)
    print lines(i)
next i

sleep

Sub formatting (sarray() as string, Byval sline As String, Byval w As Integer = 80)
    While Len(sline) > w
        Dim As Integer n
        n = Instrrev(sline, " ", w)
        If n = 0 Then Exit While
        Redim Preserve sarray(ubound(sarray) + 1)
        sarray(ubound(sarray)) = Left(sline, n - 1)
        sline = Mid(sline, n + 1)
    Wend
    If Len(sline) > 0 Then
        Redim Preserve sarray(ubound(sarray) + 1)
        sarray(Ubound(sarray))= sline
    End If
End Sub
[edit]
add a test on none space found
Last edited by fxm on Oct 08, 2020 14:37, edited 2 times in total.
Xusinboy Bekchanov
Posts: 789
Joined: Jul 26, 2018 18:28

Re: Break long string onto shorter lines

Post by Xusinboy Bekchanov »

I was wrong about Preserve
paul doe
Moderator
Posts: 1733
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Break long string onto shorter lines

Post by paul doe »

Xusinboy Bekchanov wrote:I was wrong about Preserve
Also, beware about using ubytes as indexes, as this triggers a well-known bug:

Code: Select all

for i as ubyte = 0 to 255
  ? "Hello: " & i
next
Causes an infinite loop.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Break long string onto shorter lines

Post by dodicat »

My try:

Code: Select all


Function wrap(s As String) As String
    Dim As String res,t
    Dim As Long ct,spcct
    For n As Long=0 To Len(s)-1
        ct+=1
        If s[n]=32 Then spcct=0 Else spcct+=1
        res+=Chr(s[n])
        skip:
        If ct>=Loword(Width)  Then
            ct=0
            If spcct >= Loword(Width) Then spcct=0: Goto skip 
            Var p =Instrrev(res," ")
            Var l1=Len(res)
            t=Mid(res,1,p)
            If spcct<>0 Then  res=t+Chr(10)
            Var l2=Len(res)
            n=n-(l1-l2)-1*Sgn(spcct)
        End If
    Next
    Return res
End Function


Do
    Cls
    Width 50+Rnd*90
    Dim As String a_string="This is a long string onto the screen and maybe it will break correctly with this piece of code but "
    a_string+="I have to add some length, my Win 10 console might be very wide ("+Str(Loword(Width))+" chartacters just now.)"
    a_string+=" This is another extension (Big word full of A's) "+String(400+Rnd*100,"A")
    a_string+=" Bla Bla Bla Bla Bla Bla Bla Press a key ...  (or <esc> to end)"  
    
    Print wrap(a_string)
    
    
    Sleep
    Loop until inkey=chr(27)  
ITomi
Posts: 154
Joined: Jul 31, 2015 11:23
Location: Hungary

Re: Break long string onto shorter lines

Post by ITomi »

Oh, it's true, I forgot the ReDim, as Srvaldez and Xusinboy Bekchanov mentioned... Now I put this command into my program and it is work, except that the program shows only a small part of the whole string.
But I tried programs of Fxm and Dodicat and both of these works correctly. I would like do my code similar way, but if I will fail with it, I will use those if possible.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Break long string onto shorter lines

Post by dodicat »

Custom ubyte for looping, but it is more trouble than it is worth.

Code: Select all

Type YouByte
    Dim As Ubyte u
    as boolean flag
    Declare Operator For(As YouByte)
    Declare Operator Next(As YouByte,As YouByte) As Integer
    Declare Operator Step(As YouByte)
End Type

Operator YouByte.For(Stepper As YouByte)
End Operator

Operator YouByte.Next (ender As YouByte,stepper As YouByte) As Integer
If u=0 and flag=true Then flag=false:Return 0
flag=true
Return u<=ender.u
End Operator

Operator YouByte.Step(stepper As YouByte)
u+=stepper.u
End Operator

For x As YouByte = Type<YouByte>(0) To Type<YouByte>(255) Step Type<YouByte>(1) 
    Print x.u;" ";
Next x

print
print

For x As YouByte = Type<YouByte>(0) To Type<YouByte>(255) Step Type<YouByte>(1) 
    Print x.u;" ";
Next x

Sleep 
Using the two largest (I think) words to test the breaker.

Code: Select all

Function wrap(s As String) As String
    Dim As String res,t
    Dim As Long ct,spcct
    For n As Long=0 To Len(s)-1
        ct+=1
        If s[n]=32 Then spcct=0 Else spcct+=1
        res+=Chr(s[n])
        skip:
        If ct>=Loword(Width)  Then
            ct=0
            If spcct >= Loword(Width) Then spcct=0: Goto skip
            Var p =Instrrev(res," ")
            Var l1=Len(res)
            t=Mid(res,1,p)
            If spcct<>0 Then  res=t+Chr(10)
            Var l2=Len(res)
            n=n-(l1-l2)-1*Sgn(spcct)
        End If
    Next
    Return res
End Function

width 120
dim as string s=string(1084,0)
for n as long=0 to 1084
    read s[n]
next n
print wrap(s)
sleep

data _
076,097,115,116,032,121,101,097,114,032,073,032,116,111,111,107,032,097,032,104,_
111,108,105,100,097,121,032,105,110,032,078,101,119,032,090,101,097,108,097,110,_
100,044,032,073,032,119,101,110,116,032,116,111,032,097,032,100,101,108,105,103,_
104,116,102,117,108,032,108,105,116,116,108,101,032,115,112,111,116,032,099,097,_
108,108,101,100,032,084,097,117,109,097,116,097,119,104,097,107,097,116,097,110,_
103,105,104,097,110,103,097,107,111,097,117,097,117,111,116,097,109,097,116,101,_
097,116,117,114,105,112,117,107,097,107,097,112,105,107,105,109,097,117,110,103,_
097,104,111,114,111,110,117,107,117,112,111,107,097,105,119,104,101,110,117,097,_
107,105,116,097,110,097,116,097,104,117,044,032,105,116,032,119,097,115,032,118,_
101,114,121,032,110,105,099,101,046,032,072,111,119,101,118,101,114,032,073,032,_
117,115,117,097,108,108,121,032,112,114,101,102,101,114,032,116,111,032,104,111,_
108,105,100,097,121,032,110,101,097,114,101,114,032,104,111,109,101,044,032,101,_
115,112,101,099,105,097,108,108,121,032,105,110,032,116,104,101,032,087,105,110,_
116,101,114,032,109,111,110,116,104,115,046,032,076,108,097,110,102,097,105,114,_
112,119,108,108,103,119,121,110,103,121,108,108,103,111,103,101,114,121,099,104,_
119,121,114,110,100,114,111,098,119,108,108,108,108,097,110,116,121,115,105,108,_
105,111,103,111,103,111,103,111,099,104,032,105,110,032,065,110,103,108,101,115,_
097,121,032,105,115,032,118,101,114,121,032,110,105,099,101,032,111,102,102,032,_
115,101,097,115,111,110,046,032,073,032,108,105,107,101,032,101,115,112,101,099,_
105,097,108,108,121,032,116,111,032,098,117,121,032,097,032,112,108,097,116,102,_
111,114,109,032,116,105,099,107,101,116,032,097,110,100,032,115,105,116,032,111,_
110,032,097,032,098,101,110,099,104,032,097,110,100,032,119,097,116,099,104,032,_
116,104,101,032,116,114,097,105,110,115,032,099,111,109,101,032,097,110,100,032,_
103,111,032,116,104,114,111,117,103,104,032,116,104,101,032,115,116,097,116,105,_
111,110,046,032,076,097,115,116,032,121,101,097,114,032,073,032,104,111,112,112,_
101,100,032,097,098,111,097,114,100,032,111,110,101,044,032,098,117,116,032,102,_
101,108,108,032,097,115,108,101,101,112,032,097,110,100,032,101,110,100,101,100,_
032,117,112,032,105,110,032,080,101,116,101,114,104,101,097,100,046,032,073,032,_
107,110,101,119,032,101,120,097,099,116,108,121,032,119,104,101,114,101,032,073,_
032,119,097,115,032,119,104,101,110,032,073,032,119,111,107,101,032,117,112,044,_
032,073,032,099,111,117,108,100,032,115,109,101,108,108,032,116,104,101,032,102,_
105,115,104,044,032,097,099,116,117,097,108,108,121,032,116,104,097,116,032,119,_
097,115,032,119,104,097,116,032,119,111,107,101,032,109,101,032,117,112,046,032,_
068,111,110,039,116,032,103,101,116,032,109,101,032,119,114,111,110,103,044,032,_
080,101,116,101,114,104,101,097,100,032,105,115,032,100,101,108,105,103,104,116,_
102,117,108,032,105,110,032,105,116,039,115,032,111,119,110,032,119,097,121,044,_
032,098,117,116,032,073,032,102,111,117,110,100,032,105,116,032,119,097,115,032,_
097,032,098,105,116,032,075,105,110,103,032,066,105,108,108,121,032,102,111,114,_
032,097,032,087,105,110,116,101,114,032,098,114,101,097,107,046,032,065,110,121,_
119,097,121,044,032,116,104,105,115,032,121,101,097,114,032,073,032,102,105,110,_
100,032,109,121,115,101,108,102,032,098,097,099,107,032,105,110,032,076,108,097,_
110,102,097,105,114,112,119,108,108,103,119,121,110,103,121,108,108,103,111,103,_
101,114,121,099,104,119,121,114,110,100,114,111,098,119,108,108,108,108,097,110,_
116,121,115,105,108,105,111,103,111,103,111,103,111,099,104,044,032,098,117,116,_
032,100,117,101,032,116,111,032,116,104,101,032,110,101,119,032,108,111,099,107,_
100,111,119,110,032,073,032,097,109,032,115,116,114,097,110,100,101,100,046,032,_
073,032,099,097,110,110,111,116,032,104,111,112,032,111,110,032,097,032,116,114,_
097,105,110,032,098,101,099,097,117,115,101,032,116,104,101,114,101,032,097,114,_
101,032,112,111,108,105,116,105,099,105,097,110,115,032,112,097,099,105,110,103,_
032,117,112,032,097,110,100,032,100,111,119,110,032,116,104,101,032,112,108,097,_
116,102,111,114,109,046,032,084,104,101,114,101,032,097,114,101,032,115,116,105,_
108,108,032,116,114,097,105,110,115,032,112,097,115,115,105,110,103,032,116,104,_
114,111,117,103,104,044,032,098,117,116,032,110,111,098,111,100,121,032,105,115,_
032,097,108,108,111,119,101,100,032,111,102,102,032,111,114,032,111,110,032,116,_
104,101,109,046,032
 
Post Reply