It is currently August 10th, 2020, 3:52 pm

[EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Report bugs with the Rainmeter application and suggest features.
User avatar
Yincognito
Posts: 2223
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

[EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Post by Yincognito »

This is probably not a bug, but just in case this isn't the expected behavior, I posted this here and not in the Rainmeter Skins section of the forum. Sorry if I was wrong with this, but anyway, let's get to the point.

Sample code:

Code: Select all

[Variables]
String=abracadabra

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
BackgroundMode=2
SolidColor=47,47,47,255

---Measures---

; [MeasureTest]
; Measure=String
; String=a
; RegExpSubstitute=1
; Substitute="(?si)^.*$":"\0a"
; DynamicVariables=1

; [MeasureTest]
; Measure=String
; String=a
; RegExpSubstitute=1
; Substitute="(?si)^(.*)$":"\0a"
; DynamicVariables=1

; [MeasureTest]
; Measure=String
; String=a
; RegExpSubstitute=1
; Substitute="(?si)^(.*)$":"\1a"
; DynamicVariables=1

; [MeasureTest]
; Measure=String
; String=
; RegExpSubstitute=1
; Substitute="(?si)^.*$":"[MeasureTest]a"
; DynamicVariables=1

; [MeasureTest]
; Measure=String
; String=
; RegExpSubstitute=1
; Substitute="$":"a"
; DynamicVariables=1

[MeasureTest]
Measure=String
String=[MeasureTest]a
DynamicVariables=1

---Meters---

[MeterTest]
Meter=STRING
X=0
Y=0
FontFace=Consolas
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
FontSize=16
AntiAlias=1
MeasureName=MeasureTest
Text="Test = %1"
DynamicVariables=1
Expected result: all measures keep adding a-s to their past value (e.g. "a" on 1st update, "aa" on the 2nd, "aaa" on the 3rd and so on)
Actual result: only the uncommented measure does this, the commented ones do not, although the basic steps and principle are (or should be) the same

Now the code above is overly simplified to better see and understand things, so one may rightfully ask why I don't do it as in the last working measure and be done with it. The answer is simple: I can't, since the String option doesn't allow an "inline substitution" and obviously, compared to this sample, my code is more complex than that, which means I have to use RegExp substitutions and simply doing it from the String option is not going to accomplish what I want (which is to regex substitute based on the previous value of the measure).

So, is this the expected behavior and why? And if it is, what can I do to achieve what I want? Any workaround to this?

EDIT: On a second thought, knowing how these things work in WebParser measures where we substitute things and they don't do this over and over on every update, it looks like it is indeed the way it should work, but then, the question remains: how can I achieve the opposite?

EDIT2: Forget I asked, adding this to the skin seems to achieve what I want:

Code: Select all

[Variables]
LastValue=
...
...
...
[MeasureTest]
Measure=String
String=
RegExpSubstitute=1
Substitute="(?si)^.*$":"#LastValue#a"
OnUpdateAction=[!SetVariable LastValue "[MeasureTest]"]
DynamicVariables=1
...
but for some reason there is a problem doing this properly in my actual code, so maybe the issue lies elsewhere... :???:
Last edited by Yincognito on July 27th, 2020, 7:37 pm, edited 1 time in total.
User avatar
Brian
Developer
Posts: 2044
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Post by Brian »

jsmorley may want to chime in on this one since he is more proficient in regex than I am, but I believe this is expected behavior.

While similar, RegExpSubstitute and RegExp (from Webparser) are different. For Webparser, RegExp determines what is stored via StringIndex. This sets the "value" (or string value) to whatever is returned from the RegExp array. On the other hand, Substitute is executed on each call for any measures value. Yes, this means Substitute can happen "multiple" times during the update cycle for each measure depending on many times it is referenced in other measures/meters/dialogs. Substitute does not modify the measure's value at all, instead it modifies the returned value from the measure. Substitute is almost like a post process on demand action. Every time you ask for a measure's string value, it evaluates the Substitute option.

I hope that makes sense.

To your specific examples:
  • Example #1: The pattern just represents the entire string. There are no captures (no parenthesis were used), so the entire string is replaced with "\0a".
  • Example #2: The pattern represents the entire string, but also captures it. \0 represents the entire captured string, so it returns "aa".
  • Example #3: Similar to #2, but it gets the "first" captured index, which is the same as the entire capture (\0), so it returns "aa".
  • Example #4: Similar to #1, only there is no string value to [MeasureTest] (because String="" or an empty string). So the measure returns an empty string and appends an "a".
  • Example #5: Similar to #4. The "end of line" is replaced with a "a".
Yincognito wrote: July 22nd, 2020, 3:49 pm but for some reason there is a problem doing this properly in my actual code, so maybe the issue lies elsewhere... :???:
Maybe you could post your specific problem so the regex nerds can help? :D

-Brian

PS - Since Substitute on a measure can be ran multiple times during the update cycle, it can become inefficient depending on the number of replacements (you can create infinite loops if you aren't careful), and the number times that measure's string value is referenced in other objects (like other measures, meters and even the About dialog).
User avatar
Yincognito
Posts: 2223
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Post by Yincognito »

Brian wrote: July 23rd, 2020, 5:34 am jsmorley may want to chime in on this one since he is more proficient in regex than I am, but I believe this is expected behavior.

While similar, RegExpSubstitute and RegExp (from Webparser) are different. For Webparser, RegExp determines what is stored via StringIndex. This sets the "value" (or string value) to whatever is returned from the RegExp array. On the other hand, Substitute is executed on each call for any measures value. Yes, this means Substitute can happen "multiple" times during the update cycle for each measure depending on many times it is referenced in other measures/meters/dialogs. Substitute does not modify the measure's value at all, instead it modifies the returned value from the measure. Substitute is almost like a post process on demand action. Every time you ask for a measure's string value, it evaluates the Substitute option.

I hope that makes sense.

To your specific examples:
  • Example #1: The pattern just represents the entire string. There are no captures (no parenthesis were used), so the entire string is replaced with "\0a".
  • Example #2: The pattern represents the entire string, but also captures it. \0 represents the entire captured string, so it returns "aa".
  • Example #3: Similar to #2, but it gets the "first" captured index, which is the same as the entire capture (\0), so it returns "aa".
  • Example #4: Similar to #1, only there is no string value to [MeasureTest] (because String="" or an empty string). So the measure returns an empty string and appends an "a".
  • Example #5: Similar to #4. The "end of line" is replaced with a "a".

Maybe you could post your specific problem so the regex nerds can help? :D

-Brian

PS - Since Substitute on a measure can be ran multiple times during the update cycle, it can become inefficient depending on the number of replacements (you can create infinite loops if you aren't careful), and the number times that measure's string value is referenced in other objects (like other measures, meters and even the About dialog).
Many thanks for answering in detail, Brian. I would post the code I'm working on, as by my standards it's still short and simple enough to be understood, but even so, it uses some techniques (self updating measure loops, string-based text length counters, substitutes build on the fly on self updates, nested variables, !SetVariable-s that need multiple quotes, etc.) that I'm not sure they will be understood properly, not to mention finding regex nerds - other than myself, that is - appears to be a difficult task here on the forum, as far as I could see, LOL.

The fact that substitute does not modify the measure's value at all kind of bothers me, as I feel this has a saying in things not working out as planned during the development of my code. Since posting, I managed to somehow achieve what I wanted, but I do experience lots of Rainmeter hangs due to that annoying "can't have empty regex results", which by the way, isn't limited to "pure" (captures), it happens for other capture-less strings as well. It is annoying for me as one doesn't have that kind of issues when testing his regexes online or in another program, as they work fine and don't hang due to the "emptiness" - so you can have otherwise perfectly valid regex patterns and substitutions that for such reasons will cause those CPU spikes and hangs in Rainmeter. :???:
User avatar
Yincognito
Posts: 2223
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Post by Yincognito »

Brian wrote: July 23rd, 2020, 5:34 amMaybe you could post your specific problem so the regex nerds can help? :D

-Brian
Brian, just wanted to let you know that I solved the issue(s) in my skin, by taking a slightly different approach to the matter, based on dividing my process into separate steps so I can better see where the problems were.

The whole thing went well (and better than I expected) for the most part, bar some minor hickups due to the need of updating my variables (which I ended up turning them into measures so they could automatically update themselves when needed) and some string replacement issues in WebParser generated outputs (for some reason, some "lost" carriage-return and new-line characters appeared during my string replacement process, and using substitutes like "\R":"" didn't seem to do the job properly while equivalent substitutes like "\r?\n":"" did - I'm not sure why, although I suspect the \R variable length to be the culprit).

Bottom line, now my dynamic menu works very well. It uses an editable (and automatically parsed and updated on mouse hover) TXT file like:

Code: Select all

; This file stores the menu shown in the <Launcher> skin. Line indentation level (defined using either spaces or tabs) describes the menu item level,
; while more than one space or tab separate a non submenu item name from its associated command or URL. Each menu item must start on a separate line.

a
	b
		c
			d
				e		D:\Software\Games\Backgammon Professional\BackGammon.exe
				f		D:\Software\Games\Monopoly by Parker Brothers\MonopolyPB.exe
		g
	h
i
	j
k
	l
		m
		n
			o
				p		C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
	q
		r				C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe
	s
		t
		u
			v			cmd.exe
			w			regedit.exe
			x			calc.exe
		y
z
to create a navigable menu (through mouse scroll, left click to open, right click to go back one level) in my skin.

Many thanks for answering. :thumbup:
User avatar
Brian
Developer
Posts: 2044
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [EXPECTED BEHAVIOR?] Past Measure Value Based Substitute

Post by Brian »

Yincognito wrote: July 27th, 2020, 7:36 pm Many thanks for answering. :thumbup:
Glad you got it worked out!

-Brian