Picking out characters from a string

I'm trying to display individual words from a string.
CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
OBJ
  pst : "Parallax Serial Terminal"
var

long value, x 
Pub Main
  pst.Start(115_200)     
  waitcnt(clkfreq * 2 + cnt)    
  pst.Clear
  pst.Str(String("press any key"))
  value := pst.CharIn
  pst.Chars(pst#NL,1)
   x:=1
 repeat while x < 16
   
   pst.Char(@three[x])
   x++  
   pst.Char(@three[x])
   x++  
   pst.Char(@three[x])
   x++ 
    pst.Chars(pst#NL,1) 
pst.Chars(pst#NL,1) 
pst.Str(String("done"))
repeat
Dat
'Three letter words
Three byte "theandforarebutnotyouallanycanherwasoneouroutday",0

Comments

  • Here's one way that should work:
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    OBJ
      pst : "Parallax Serial Terminal"
    var
    
    long value, x 
    Pub Main
      pst.Start(115_200)     
      waitcnt(clkfreq * 2 + cnt)    
      pst.Clear
      pst.Str(String("press any key"))
      value := pst.CharIn
      pst.Chars(pst#NL,1)
       x:=0
     repeat while three[x] <> 0
       
       pst.Char(three[x])
       x++  
       pst.Char(three[x])
       x++  
       pst.Char(three[x])
       x++ 
        pst.Chars(pst#NL,1) 
    pst.Chars(pst#NL,1) 
    pst.Str(String("done"))
    repeat
    Dat
    'Three letter words
    Three byte "theandforarebutnotyouallanycanherwasoneouroutday",0
    

    Changes are:
    * Reference the variable 'Three' directly, instead of its address
    * The index 'x' is initialized with 0 (that's the first element of your variable 'Three' - it started with 1 before, which would be the 'h' in the word 'the')
    * The repeat block now loops as long as the value of three isn't 0/NUL (which was used but not tested for in your original example)

    Cheers,
    Jesse
    --
    WIP Spin drivers for various devices: LSM9DS1 (SPI) | US2066 (I2C) | MLX90621 (I2C) | SHT3x (I2C) | SSD1306 (I2C; P1-SPIN, P2-SPIN2) | TCS3x7x (I2C) | MAX31856 (SPI) | BMP280 (I2C) | TMC2130 (SPI) | nRF24L01+ (SPI) | MLX90614 (I2C) | MAX9744 (I2C) | DS28CM00 (I2C) | TSL2591 (I2C) | CC1101 (SPI) | SX1231 (SPI) | LM75 (I2C) | DS18B20 (OW)
    Use with spin-standard-library (fork)
  • Thanks, I give it a try.
  • JonnyMacJonnyMac Posts: 6,212
    edited 2019-05-29 - 22:32:05
    You could write a little method like this:
    pub sub_string(p_dest, p_src, ofs, len)
    
    '' Copy sub-string from p_src to p_dest
    '' -- ofs is offset of len-lenthed sub-string
    
      ofs *= len                                                    ' convert word offset to 1st char position
      bytemove(p_dest, p_src+ofs, len)                              ' copy len characters
      byte[p_dest+3] := 0                                           ' 0-terminate destination string
    
      return p_dest
    

    I tested with this snippet and it works fine. Note that I use my own version of FDS, not PST.
        repeat idx from 0 to 15
          term.dec(idx)
          term.tx(term#TAB)
          term.str(sub_string(@buffer, @Words3, idx, 3))
          term.tx(13)
    
    Jon McPhalen
    Hollywood, CA
    It's Jon or JonnyMac -- please do not call me Jonny.
  • Thanks Jon.
  • JonnyMacJonnyMac Posts: 6,212
    edited 2019-05-30 - 14:19:38
    I just looked back at the code and found a small error -- if the length of the desired sub-string is other than 3 the returned string will be incorrect. Here's the correction:
    pub sub_string(p_dest, p_src, ofs, len)
    
    '' Copy sub-string from p_src to p_dest
    '' -- ofs is offset of len-lenthed sub-string
    
      ofs *= len                                                    ' convert word offset to 1st char position
      bytemove(p_dest, p_src+ofs, len)                              ' copy len characters
      byte[p_dest+len] := 0                                         ' 0-terminate destination string (FIXED)
    
      return p_dest
    

    BTW, when you see repeated code in your listing you can use condense it with... repeat. For example, from your original listing you could do this:
      repeat 3
        pst.Char(@three[x++])
    
    Jon McPhalen
    Hollywood, CA
    It's Jon or JonnyMac -- please do not call me Jonny.
  • Kye wrote a string handler with lots of functions. It’s well documented. Take a look at that - you could either use it or copy the relevant code.
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • PublisonPublison Posts: 10,851
    edited 2019-05-30 - 21:55:49
    Cluso99 wrote: »
    Kye wrote a string handler with lots of functions. It’s well documented. Take a look at that - you could either use it or copy the relevant code.

    Is this the one?

    http://obex.parallax.com/object/579
    Infernal Machine
  • Thanks for all the help.
    You guys are the best!
  • This project has proceeded nicely. Now I'm reducing redundant subroutines. This next problem is not a show stopper, it just caught me by surprise, and I hope someone will chime in as to why this happened. I used the WORDMOVE command and the strings don't line up, I'm off by one.
    repeat
       value := pst.CharIn 
       if value == 49 '#1  three letter words
         LetterCount:=3
         wordmove(@TestWords,@three, 198) 'Copy three to TestWords    
         ManyWords:=66      ' How many words
         quit
       if value == 50 '#2  four letter words
         LetterCount:=4
         wordmove(@TestWords,@four, 280) 'Copy four to TestWords  
          ManyWords:=70
         quit
    
    In another subroutine I extract random words from TestWords. If I extract directly from three or four the words line up correctly.
    I fixed it by subtracting 1 from the extraction index. I just want to know why I needed to do this.

    here is the word extraction subroutine
     x:= random * LetterCount
     w:=0
     x:=X-1
      repeat while x < (LetterCount * random + LetterCount)-1   
         TheWord[w]:=TestWords[x]     
         x++
         w++
    
  • WORDMOVE moves 16-bit "words". I think you may be looking for BYTEMOVE
  • LaserSteveLaserSteve Posts: 21
    edited 2019-06-02 - 20:06:32
    Ok, I'll look into it.
    Thanks.

    You were right, thanks.
  • JonnyMacJonnyMac Posts: 6,212
    edited 2019-06-02 - 21:42:22
    If your goal is to copy the entire string, let me suggest you do it like this:
      bytemove(@TestWords, @three, strsize(@three)+1)
    
    Two things: 1) Use bytemove, not wordmove, and 2) Use strsize() so that you don't have to count the length of the string -- this will let you update the string without having to go back in and fix the code. The reason for the +1 is that it will copy the terminating 0 from the source to the destination.
    Jon McPhalen
    Hollywood, CA
    It's Jon or JonnyMac -- please do not call me Jonny.
  • Publison wrote: »
    Cluso99 wrote: »
    Kye wrote a string handler with lots of functions. It’s well documented. Take a look at that - you could either use it or copy the relevant code.

    Is this the one?

    http://obex.parallax.com/object/579

    Yes, that's it.
    Kye has a very nice way of commenting his code, especially tuned for beginners.
    To me, the names of the routines and variables are quite long, but they do exactly what the name says.
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • Thanks for all the help.
Sign In or Register to comment.