It is currently April 19th, 2024, 1:55 pm

thousands separator

Get help with creating, editing & fixing problems with skins
User avatar
Indy
Posts: 40
Joined: August 8th, 2013, 10:40 pm

thousands separator

Post by Indy »

Hello,

i have a question again.

I have a number, example 123456789 or 123456789,00

How i can display it whit thousands separators, example 123.456.789 or 123.456.789,00

Have Rainmeter a funktion for this included?
If not, what way can do this?


greeting Indy
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: thousands separator

Post by jsmorley »

Indy wrote:Hello,

i have a question again.

I have a number, example 123456789 or 123456789,00

How i can display it whit thousands separators, example 123.456.789 or 123.456.789,00

Have Rainmeter a funktion for this included?
If not, what way can do this?


greeting Indy
There is no built-in function for this in Rainmeter. The only way I can think of to approach it and get both the separators, and in the "locale" format you suggest, is to use a Lua script.

FormatNumber.ini

Code: Select all

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

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

[MeasureFormatNumber]
Measure=Script
ScriptFile=FormatNumber.lua
UpdateDivider=-1

[MeasureDriveCTotal]
Measure=FreeDiskSpace
Drive=C:
Total=1
IgnoreRemovable=0
UpdateDivider=5
OnUpdateAction=[!CommandMeasure MeasureFormatNumber "FormatNumber('DriveCTotal', '[MeasureDriveCTotal]', '#Separator#', '#Decimal#')"]
DynamicVariables=1

[MeterDriveCTotal]
Meter=String
MeasureName=MeasureDriveCTotal
FontSize=13
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=Unformatted - %1#CRLF#Formatted - #DriveCTotal#
DynamicVariables=1
FormatNumber.lua

Code: Select all

function FormatNumber(varName, inNum, sepChar, decChar)
  
  local outNum = inNum
  local 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
  
  SKIN:Bang('!SetVariable', varName, outNum)
  
end
This skin requires the latest Rainmeter 3.0 beta from http://rainmeter.net.
FormatNumber_1.0.rmskin
01.jpg
Simply set the character you want as the separator in the [Variable] Separator="SomeChar", and the character to use to delimit decimal places in Decimal="SomeChar".

The !CommandMeasure bang to Lua will take as input to the function the variable to set, the input value as a string or a [SectionVariable], the separator as a string, and the decimal place delimiter as a string. This is in the format:

[!CommandMeasure ScriptMeasureName "FormatNumber('VariableToSet', 'InputValue', 'Separator', 'DecimalDelimiter')"]

All parameters are required.

When the measure with the OnUpdateAction fires the Lua script with !CommandMeasure, the number will be formatted, and the variable will dynamically be set in the skin. You can then use that variable dynamically in any output meter you desire.

The skin and example above uses the FreeDiskSpace measure as a working example. However, it doesn't demonstrate the setting of the decimal place delimiter. The following test skin does:

Code: Select all

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

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

[MeasureFormatNumber]
Measure=Script
ScriptFile=FormatNumber.lua
UpdateDivider=-1

[MeasureBigNumber]
Measure=Time
Format=123456789.1234
UpdateDivider=5
OnUpdateAction=[!CommandMeasure MeasureFormatNumber "FormatNumber('BigNumber', '[MeasureBigNumber]', '#Separator#', '#Decimal#')"]
DynamicVariables=1

[MeterBigNumber]
Meter=String
MeasureName=MeasureBigNumber
FontSize=13
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=Unformatted - %1#CRLF#Formatted - #BigNumber#
DynamicVariables=1
02.jpg
Note: The Lua script measure is general purpose in nature, and can be created once and used as many times in your skin as you need. Just make sure the variable to set and the input value are different each time you call it.

If you haven't already run away screaming, I'm glad to answer any questions about how and why this works. It looks more complicated than it really is.
You do not have the required permissions to view the files attached to this post.
User avatar
Indy
Posts: 40
Joined: August 8th, 2013, 10:40 pm

Re: thousands separator

Post by Indy »

Hello,

thank you very much for your help.
I tried to implement it in my Project.

What i do?

The unformatted number come from

Code: Select all

[MeasureSP3]
Measure=Plugin
Plugin=Plugins\WebParser.dll
Url=[MeasureCharacterInfo3]
StringIndex=2
MinValue=0
MaxValue=441344000
DynamicVariables=1
as a number whit 9 digits (example 123456789)


firstly add

Code: Select all

Separator="."
Decimal=","
to my Variables


secondly add

Code: Select all

[MeasureFormatNumber]
Measure=Script
ScriptFile=FormatNumber.lua
UpdateDivider=-1
thirdly add

Code: Select all

[MeasureSkillPoints]
Measure=Time
UpdateDivider=5
OnUpdateAction=[!CommandMeasure MeasureFormatNumber "FormatNumber('SkillPoints', '[MeasureSP3]', '#Separator#', '#Decimal#')"]
DynamicVariables=1
And the Output

Code: Select all

[MeterSP4]
Meter=STRING
MeasureName=MeasureSkillPoints
MeterStyle= styleBodyText
X = 5
Y = 155
Text=Skill Points: Unformatted - %1#CRLF#Formatted - #SkillPoints#
DynamicVariables=1
The output in the Skin is now

Skill Points: Unformatted - 00:15:18 (i think is the Windows Time)
Formatted - 123.456.789 (the right 9 digits number now formatted)


Now i have questions to this.

The Measure=Time is not need for this?

If i change Measure=Time to Measure=anything, i become an error:
Measure=anything is not Valid in[MeasureSkillPoints]


How i become this Output?

Skill Points: Unformatted - 123456789 (the right 9 digits number from input, unformatted)
Formatted - 123.456.789 (the right 9 digits number from input, formatted)

It work fine for format my number, but i dont understand Measure=Time thing.
Sorry for some questions, but I do not see my error.


greeting Indy
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: thousands separator

Post by jsmorley »

The Time measure was just an example to show how to format a number with decimal places in it. I just demonstrated with a Time measure as you can put any string in the Format option, so it is a good measure type for easy testing of stuff like this.

In your case, you can

Code: Select all

[MeasureSP3]
Measure=Plugin
Plugin=Plugins\WebParser.dll
Url=[MeasureCharacterInfo3]
StringIndex=2
OnFinishAction=[!ShowMeter MeterSP3]

[MeasureSP3Number]
Measure=Calc
Formula=[MeasureSP3]
MinValue=0
MaxValue=441344000
OnChangeAction=[!CommandMeasure MeasureFormatNumber "FormatNumber('SkillPoints', '[MeasureSP3Number]', '#Separator#', '#Decimal#')"]
DynamicVariables=1

[MeterSP3]
Meter=String
MeasureNameMeasureSP3Number
MeterStyle=styleBodyText
X=5
Y=155
Text=Skill Points: Unformatted - %1#CRLF#Formatted - #SkillPoints#
Hidden=1
DynamicVariables=1
Note that I put this in a Calc measure that uses [MeasureSP3] as the input for the Formula, since you seem to have some other need for a MinValue / MaxValue based on the number (this is right if you later want to use it in a Bar or Line or Rotator meter for example, which require a "percentage" based on the range of minimum and maximum).

However, you can't use MinValue or MaxValue on a WebParser measure, as WebParser only returns "strings", (even if it looks like a number) and not "real numbers". Using a Calc measure with the current value of the WebParser measure as the Formula will convert the string into a "real number", that you can do calculations on (like setting a MinValue and MaxValue).

If on the other hand, you don't actually need to set MinValue / MaxValue, (and don't want to use IFActions on the value, or perform some calculation on the value, or anything else that requires a real number) then there is no reason why you can't put the OnChangeAction (see below for why I made it OnChangeAction instead of OnUpdateAction) right on the WebParser measure, as the Lua function is just treating the number as a string in any case.

----------------
Just one other hint that is specific to doing this with WebParser.

The reason I used OnUpdateAction to execute the !CommandMeasure was to be able to control how often the script was actually run by setting UpdateDivider on the measure (the FreeDiskSpace measure in my example). I don't want to check the drive and run the script every Update (which would be once a second with Update=1000 in [Rainmeter]) as that is just excessive for that kind of value.

Now with WebParser, you control how often the site is accessed and the HTML read using a different option. You use UpdateRate, which defaults to 600, or every 10 minutes when Update=1000. Generally speaking, hitting a site every 10 minutes is plenty often.

However the WebParser measure itself will still "update" based on the Update value in [Rainmeter], even though by default the UpdateRate is telling only to hit the site every 10 minutes. If we use OnUpdateAction to run the !CommandMeasure bang in the calc measure, we are running the script once a second, when the value of the measure is certain to change at BEST once every 10 minutes.

That is just hideously inefficient. It won't hurt anything really, but offends me.

Still, we want to keep the actual update of the value from the site in "sync" with the running of the Lua script, so we don't want to just add an UpdateDivider=600 to the Calc measure or something, as that won't really tie the two (the WebParser and the Calc) together, just get them "close" as far as timing.

So, instead I used OnChangeAction in the Calc measure to run the !CommandMeasure bang. That way, the Lua script is only run when the value of the Calc measure is actually changed, which will only be when the WebParser measure goes out and gets a value from the web site that is different than what it was 10 minutes ago.

I set the initial state of the meter [MeterSP3] to Hidden=1, so it doesn't display invalid values before the WebParser measure has a chance to get the information from the web site. I use FinishAction=[!ShowMeter MeterSP3] on the WebParser measure to "unhide" the meter when the measure has finished getting and parsing the site.

Hope that makes sense. It's not a big deal, but it is the "right" way to do it.
User avatar
moshi
Posts: 1740
Joined: November 13th, 2012, 9:53 pm

Re: thousands separator

Post by moshi »

Code: Select all

RegExpSubstitute=1
Substitute="\d{1,3}(?=(\d{3})+(?!\d))":"\0."
:)
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: thousands separator

Post by jsmorley »

moshi wrote:

Code: Select all

RegExpSubstitute=1
Substitute="\d{1,3}(?=(\d{3})+(?!\d))":"\0."
Yeah, I considered something like that, but it doesn't quite do all he wants. It will set the separator to "." and format that part of the number, but won't change the decimal place delimiter to ",". Now all of this might well be dependent on how he has his "locale" set up in Windows, and might be irrelevant, but I wanted something with maximum flexibility.

Also, if the decimal places are more than three in length, like 123456789.1234 then it will format the decimal positions with the separator as well, "1.234.567.890.1.234". Not good.

I also like that the original string value of the WebParser measure stays unchanged, so it can be used (via the Calc measure with MinValue / MaxValue as in my example) as input to a Bar or Rotator meter later if desired.

Still, you might be able to get there with Regular Expression, but what would be the fun in that? ;-)
User avatar
moshi
Posts: 1740
Joined: November 13th, 2012, 9:53 pm

Re: thousands separator

Post by moshi »

i'm drunk, but this should do it:

Code: Select all

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

[Number]
Measure=Time
Format=10000000.1234567
RegExpSubstitute=1
Substitute="^(\d+)$":"\1A","([\.,])":"A","\d{1,3}(?=(\d{3})+A)":"\0B","A$":"","B":"#Separator#","A":"#Decimal#"

[Meter]
Meter=String
DynamicVariables=1
Text=Formatted: [Number]#CRLF#Unformatted: [Number:]
SolidColor=ffffff
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: thousands separator

Post by jsmorley »

moshi wrote:i'm drunk, but this should do it:

Code: Select all

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

[Number]
Measure=Time
Format=10000000.1234567
RegExpSubstitute=1
Substitute="^(\d+)$":"\1A","([\.,])":"A","\d{1,3}(?=(\d{3})+A)":"\0B","A$":"","B":"#Separator#","A":"#Decimal#"

[Meter]
Meter=String
DynamicVariables=1
Text=Formatted: [Number]#CRLF#Unformatted: [Number:]
SolidColor=ffffff
Maybe, I'm too lazy to even attempt to figure that out.

;-)
User avatar
Indy
Posts: 40
Joined: August 8th, 2013, 10:40 pm

Re: thousands separator

Post by Indy »

Hello,

thx for all the help, now it working fine.
skill.png
Only two more errors to fix i think, and the Project is completed :D
error.png
All Ideas ar welcome :oops:



greeting Indy
You do not have the required permissions to view the files attached to this post.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: thousands separator

Post by jsmorley »

I'd have to see the skin code and the .lua code you are using. I didn't have any GetStringValue() in the code I posted, so that one surprises me. The error from WebParser is a parsing error, but since you are getting the results you want, it might just be a problem with a second WebParser measure trying to use the result from an earlier one when it isn't "done" yet. So you get an initial error, but then on the next update it is corrected.