It is currently April 20th, 2024, 2:06 am

Digits separator

Get help with creating, editing & fixing problems with skins
mak_kawa
Posts: 908
Joined: December 30th, 2015, 9:47 am

Digits separator

Post by mak_kawa »

I want to show digits string with "3 digits separator", for example, "12345678" to "12,345,678".

It is probably easy with RegExp substitution only when the length of the digits is known and fixed. That is, in the cae of above digits, Substitute="^(\d{1,3})(\d{3})(\d{3})$":"\1,\2,\3" does work.

But when the length of the digits is unknown and variable?? What substitute expression I should use commonly for such digits as "12" "12345" "123456789"??
Lookahead assertion? Or something? In any case, it is far beyond of my novice RegExp skill. Any help is appreciated.

Or, as always, am I missing something easy?...:-)
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Digits separator

Post by jsmorley »

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[Variables]
Separator=","
Decimal="."

[MeasureNumber]
Measure=Calc
Formula=10000000.99
RegExpSubstitute=1
Substitute="^(\d+)$":"\1A","([\.,])":"A","\d{1,3}(?=(\d{3})+A)":"\0B","A$":"","B":"#Separator#","A":"#Decimal#"

[MeterNumber]
Meter=String
FontSize=11
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
DynamicVariables=1
Text=Formatted: [MeasureNumber]#CRLF#Unformatted: [MeasureNumber:2]

1.png


https://forum.rainmeter.net/viewtopic.php?f=5&t=16551#p92235
You do not have the required permissions to view the files attached to this post.
mak_kawa
Posts: 908
Joined: December 30th, 2015, 9:47 am

Re: Digits separator

Post by mak_kawa »

Hi jsmorley

Thank you for...great and brilliant substitution. It does work perfectly. Awesome!!

But sadly in fact, I almost can't understand this substitution expression. ("NanigaNandaka" in Japanese) :-) It is desperately necessary for me to learn regular expression much more...
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Digits separator

Post by jsmorley »

mak_kawa wrote: November 27th, 2019, 1:56 pm Hi jsmorley

Thank you for...great and brilliant substitution. It does work perfectly. Awesome!!

But sadly in fact, I almost can't understand this substitution expression. ("NanigaNandaka" in Japanese) :-) It is desperately necessary for me to learn regular expression much more...
Fear not, I don't understand it either... ;-)
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Digits separator

Post by jsmorley »

jsmorley wrote: November 27th, 2019, 1:57 pm Fear not, I don't understand it either... ;-)
It actually isn't perfect, as it will have trouble with negative numbers. I think this is really pushing the boundaries of what I would use Substitute for. Hang on a second, and I will demonstrate a Lua function that I prefer to do this.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Digits separator

Post by jsmorley »

I would use something like this:

Skin:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

[Variables]

[Lua]
Measure=Script
ScriptFile=FormatNumber.lua
SepChar=,
DecChar=.
Disabled=1

[MeasureNumber]
Measure=String
String=12345678.1

[MeterBigNumber]
Meter=String
FontSize=13
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=Unformatted : [MeasureNumber]#CRLF#Formatted : [&Lua:FormatNumber('[&MeasureNumber]')]
DynamicVariables=1
FormatNumber.lua:

Code: Select all

function FormatNumber(inNum)
  
	sepChar = SELF:GetOption('SepChar', ',')
	decChar = SELF:GetOption('DecChar', '.')
	negNum = nil
  
	outNum = inNum
	if tonumber(outNum) < 0 then
		negNum = 1
		outNum = tostring(math.abs(outNum))
	end
	
	replaceCount = 0
  
	outNum = outNum:gsub('^(.-)%D(.-)$', '%1'..decChar..'%2')
  
	while true do
		outNum, replaceCount = outNum:gsub('^(-?%d+)(%d%d%d)', '%1'..sepChar..'%2')
		if (replaceCount == 0) then
			break
		end
	end
  
	if negNum then
		return '-'..outNum
	else
		return outNum
	end

end
FormatNumber_2.0.rmskin

1.png


This will handle a number of any size and any number of decimal places, and both positive and negative numbers. It will optionally allow the decimal and separator characters to be defined. Another advantage is that it can be used anywhere you want to display a number, without needing that complicated Substitute on each and every measure returning a number value. The Lua is certainly more involved than the Substitute, but only needs to be created once, and used anywhere.

I will note that C++ has some trouble with very large floating point numbers (numbers with decimal places), in that the decimal portion of the number value will have a small rounding error. This means that a number like 12345678.1 will internally return a value like 12345678.099999996 or something. That is why we want to pass the number value to the Lua script as a 'string' and not a number, then use Lua to convert this to a number as needed to evaluate if it is positive or not, then back to a string to tear it apart. It's also why we use [MeasureName] instead of [MeasureName:] to display the unformatted number in the meter.


Search keys: comma separated formatted numbers
You do not have the required permissions to view the files attached to this post.
mak_kawa
Posts: 908
Joined: December 30th, 2015, 9:47 am

Re: Digits separator

Post by mak_kawa »

Hi jsmorley

This smart Lua script works perfectly. Thanks.

Anyway, the RegExp string is a kind of magic spell causing me some headache. :-)
User avatar
Yamajac
Posts: 134
Joined: June 30th, 2014, 8:44 am

Re: Digits separator

Post by Yamajac »

Code: Select all

[tester]
Measure = String
String = 12389234857983271584971234
RegExpSubstitute = 1
Substitute = "(\d)(?=(\d{3})+$)" : "\1,"
Got this from stackoverflow. This works with negative numbers, short numbers, long numbers. It does not work with numbers that have decimals though.

If your numbers have decimals, then you'd use this regex instead:

Code: Select all

Substitute = "(\d)(?=(\d{3})+\.)" : "\1,"
If you need it to handle both decimals and non decimals then that's also doable just lemme know, I didn't bother wasting my time making one cause I figured you'd know whether the number will have decimals or not.


The regex is fairly simple, but I'll give you a basic walkthrough of what's happening anyway.


First we capture a digit. Then we use a positive lookahead to see if groups of 3 digits continually repeat (at least once) until they naturally reach the end of the string (or a decimal place if you're using that one). If the positive lookahead returns true, we capture the digit in question and replace it with itself followed by a comma.

Make sense?


To make it handle both decimal places and not having decimal places would be a fair bit more complicated but it could still be done just lemme know.

I know you have a lua solution already but I just don't think lua's worth it for such a simple task, personally.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Digits separator

Post by jsmorley »

To each his own certainly. Personally, I'm not afraid of Lua, and find it to be very powerful and very easy to use. In my view, the advantage to the Lua approach here is that it can be used on as many numbers as you like / need in the skin, without having to replicate a fairly complicated RegExpSubstitute on each measure returning a number you might want to display.

With a calculated number, I resist that you likely will "know" if the number is going to end up with a fractional amount or not...

But if we all liked the same things, there would be a hell of a traffic jam.
User avatar
Yamajac
Posts: 134
Joined: June 30th, 2014, 8:44 am

Re: Digits separator

Post by Yamajac »

jsmorley wrote: November 27th, 2019, 11:21 pm To each his own certainly. Personally, I'm not afraid of Lua, and find it to be very powerful and very easy to use. In my view, the advantage to the Lua approach here is that it can be used on as many numbers as you like / need in the skin, without having to replicate a fairly complicated RegExpSubstitute on each measure returning a number you might want to display.

But if we all liked the same things, there would be a hell of a traffic jam.
That's why I want MeasureStyles! :D