editing a single character and problem with ForEach

Just starting out? Need help? Post your questions and find answers here.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

editing a single character and problem with ForEach

Post by nsstudios »

Hi all,

I would appreciate if any of you could help me with a few things:
1. I'm wondering if there's a way of changing/removing a single character from the string, either by doing it with peek/poke or by other means.
In some other languages, I can exploit string=array of characters:
<
string test="test";
test[0]="b";
>
and change test to best.

2. I also have a problem with foreach: it seems like accessing elements of the map manually inside it makes an endless loop, so how are you supposed to do it then?
<
newMap person.s()
person("1")="p1"
person("2")="p2"
current=1
forEach person()
debug mapKey(person())
person(""+current)="p1"
next
>

3. How can I GoTo a label in the global scope from within a procedure?
<
procedure test()
goTo jumpHere
endProcedure
goTo afterJump
global jumpHere:
debug "jumped"
afterJump:
;do something else
>

A reply on one of the topics says to use !jmp l_jumpHere, but that doesn't seem to work.

Any help would be greatly appreciated.
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: editing a single character and problem with ForEach

Post by spikey »

nsstudios wrote:I'm wondering if there's a way of changing/removing a single character from the string
You can use ReplaceString with the #PB_String_InPlace mode to change strings and also RemoveString which will do the removing thing.

Code: Select all

Define.S sString 
sString = "test"
ReplaceString(sString, "t", "b", #PB_String_InPlace, 1, 1)
but if you specifically want a pokey version:

Code: Select all

Procedure AlterString(*Source, Position.I, New.C)
  
  Protected *Position
  
  *Position = *Source + ((Position - 1) * SizeOf(Character))
  PokeC(*Position, New)
  
EndProcedure

Define.S sString 

sString = "test"
Debug sString

AlterString(@sString, 1, 'b')
Debug sString
nsstudios wrote:I also have a problem with foreach
Use PushMapPosition before an update and PopMapPosition afterwards to preserve the position pointer.

Code: Select all

NewMap person.s()
person("1")="p1"
person("2")="p2"
current=1
ForEach person()
  Debug MapKey(person())
  PushMapPosition(person())
  person(""+current)="p1"
  PopMapPosition(person())
Next
nsstudios wrote:How can I GoTo a label in the global scope from within a procedure?
I'd say don't do this, it's just asking for extra bugs to fix. Either you'll be leaving an unreturned call on the stack which will mess up returns down the line. Or you'll be jumping back into the procedure later on to pick up the sequence at the following point; in which case there's no need muck about with jumps outside of the procedure - just put the code inside the procedure.

If you want to write a section of multipurpose code to work the same in several procedures but in the context of the parent procedure separately put it in a macro and call the macro inside the procedures (once it works properly - the debugger doesn't follow code jumps into macros fully which means you can't step through them).
Last edited by spikey on Sun Dec 08, 2019 3:33 pm, edited 1 time in total.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: editing a single character and problem with ForEach

Post by skywalk »

1.
There are many ways to do this depending on how your define your string variable and if you want to replace many characters at once. This is a simple way using PB string lib.

Code: Select all

Define.s s$ = "test"
Define.i iPos = 3
Define.s s2$ = "b"
Debug ReplaceString(s$, Mid(s$, iPos, 1), s2$, #PB_String_CaseSensitive, iPos, 1)
2.

Code: Select all

NewMap person.s()
person("1")="p1"
person("2")="p2"
current=1
ForEach person()
  Debug MapKey(person()) + " = " + person()
Next
3.
I do not recommend jumping out of Procedures.
Instead, set a global status variable or structure element inside your procedures.
On return from any procedure, check your status variable and take appropriate action.

EDIT: spikey beat me!
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: editing a single character and problem with ForEach

Post by spikey »

skywalk wrote:EDIT: spikey beat me!
Well that makes a change! :D
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: editing a single character and problem with ForEach

Post by Marc56us »

1. Debug ReplaceString("test", "t", "b", 0, 0, 1)
2. You change second key to first key name, so ForEach loop forever
3. Goto: forget it! No one uses that anymore. (last time was in 90' in Gwbasic)

:mrgreen:
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: editing a single character and problem with ForEach

Post by Demivec »

1. I'm wondering if there's a way of changing/removing a single character from the string, either by doing it with peek/poke or by other means.
In some other languages, I can exploit string=array of characters:

Code: Select all

test$ = "test"
Debug test$
PokeS(@test$, "c", 1, #PB_Unicode | #PB_String_NoZero) ;only for replacing
Debug test$
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: editing a single character and problem with ForEach

Post by #NULL »

Or just with PokeC() (that's what spikey did in his function anyway)

Code: Select all

test$ = "test"
Debug test$
pos = 0
PokeC(@test$ + SizeOf(Character) * pos, 'c')
Debug test$
User avatar
Tenaja
Addict
Addict
Posts: 1948
Joined: Tue Nov 09, 2010 10:15 pm

Re: editing a single character and problem with ForEach

Post by Tenaja »

I do not recommend treating your MapKey as if they are string variables. (At least, until you thoroughly understand them.) Instead, treat them as the index they are, and use them to look up the data they reference (the "p1"). If you need to store strings that are modified, then use a string, either in a list or an array.

If you really need to use the key as a variable, then you will want to add and remove keys as needed. Otherwise, your code will do odd things like your endless ForEach loop.
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: editing a single character and problem with ForEach

Post by nsstudios »

Thank you all for speedy, super useful replies.
I ran into the infinite forEach when I had to do something to a specific element if the currently selected element did something, e.g.
<
forEach user()
if user()\away
send(user(current)\id, user()\name+" is away.")
endIf
;do something else
next
>
which I'm not sure the push and pop trick would work for, but good to know I can do that in other cases.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: editing a single character and problem with ForEach

Post by skywalk »

Code: Select all

Use code tags in your posts.

Code: Select all

NewMap person.s()
person("1")="p1"
person("2")="p2"
person("3")="p3"
Debug "--BEFORE CHANGES--"
ForEach person()
  Debug MapKey(person()) + " = " + person()
Next
ResetMap(person())             ; Move pointer to BEFORE 1st element.
While NextMapElement(person()) ; Move pointer to next element.
  r$ = MapKey(person())
  PushMapPosition(person())
  ForEach person()           ; Starts with 1st element.
    If person() = "p1"
      person("2") = "p1 made me do it!"
    Else
      ; do other stuff...
    EndIf
  Next person()
  PopMapPosition(person())
Wend
Debug "--AFTER CHANGES--"
ForEach person()
  Debug MapKey(person()) + " = " + person()
Next
Last edited by skywalk on Sun Dec 08, 2019 6:32 pm, edited 1 time in total.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Tenaja
Addict
Addict
Posts: 1948
Joined: Tue Nov 09, 2010 10:15 pm

Re: editing a single character and problem with ForEach

Post by Tenaja »

Your initial example actually modified the key. This is bad practice. Your latest example does not do this.

Not sure if you've grasped the map variable concept, or if you just had wonky examples. Just in case...

You should be using the map as a variable to store the "away" status--do not use the map key as the variable. The first way you were trying to do it is not good practice. The map key, in this instance, should not be treated as a string variable, but rather, the variable name. The variable itself (i.e. the status) is the assignment (="away"...but I would use a flag instead of a string).

The later example looks better, and should not be endless. Like this one, use a Structure if you want to store the status of "Name". You can make a structure accessed within a map if you want more data than just the status, and you want it referenced by the Name.

Think of the mapkey as a door key; the key opens the door. You use a different key when you want to open a different door. Using this analogy, you do not modify your key just because you want to open a vacation house door rather than a living house door. Instead, you grab a different key. Maps are kind of like arrays, but instead of (0) and (1), you reference by ("Tom") and ("Harry")
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: editing a single character and problem with ForEach

Post by nsstudios »

@Tenaja, My original example may have been off, but my point was to demonstrate that forEach goes into the endless loop if I manually access specific map elements inside it.
Thanks @skywalk for the tip.
I'll try to use code tags in the future.
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: editing a single character and problem with ForEach

Post by Josh »

nsstudios wrote:My original example may have been off, but my point was to demonstrate that forEach goes into the endless loop if I manually access specific map elements inside it.
What else should happen if you always reset the map pointer.
sorry for my bad english
User avatar
kenmo
Addict
Addict
Posts: 1967
Joined: Tue Dec 23, 2003 3:54 am

Re: editing a single character and problem with ForEach

Post by kenmo »

It's a few extra lines, but you can read and edit characters of a string as an array like this:

Code: Select all

test.s = "test"
Debug test

Structure CharacterArray
  c.c[0]
EndStructure

*CA.CharacterArray = @test
*CA\c[0] = 'b'
*CA\c[2] = 'a'
Debug test
nsstudios
Enthusiast
Enthusiast
Posts: 274
Joined: Wed Aug 28, 2019 1:01 pm
Location: Serbia
Contact:

Re: editing a single character and problem with ForEach

Post by nsstudios »

Thanks @kenmo!
I was trying to do something like that, but didn't get it quite right.
Post Reply