I'm starting to learn Go after other languages. Go has a very elegant way of creating constants with numeric values like:
const (
_ = iota // 0 and is skipped
Sunday // 1
Monday // 2
...
)
This is very easy to write, but is it really easy to maintain? For example, if you suddenly insert new value to between present, all subsequent will change their values. And it will be hard to find, only scrupulous diff reading can reveal it. Or errors on other parts. How can I extract these values with names and use in other parts of a program, or in database?
For example for PostgreSQL I can define:
CREATE TYPE color AS ENUM ('', 'Sunday', 'Monday');
Just to illustrate an idea. For example, Python has Enum type:
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
Then you may use it like Color.RED. Next I can take all values:
list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
This allows me to "introspect" to module and create easily-readable enums in databases. For example for PostgreSQL I can define:
CREATE TYPE color AS ENUM ('RED', 'GREEN', 'BLUE');
How can I:
Reflect golang constants names?
Make error-proof constants which cannot drift their values? Only fix them manually?
May be there's an idiomatic way to do it better?
Thanks.
1) You can use stringer to generate the names https://godoc.org/golang.org/x/tools/cmd/stringer
2) Not sure what you mean? Most languages will allow you to drift values, you should always add to the end of the list if you want the number to stay constant, or like in python you could explicitly set each value to a number instead of using iota.
3) Not really, enums just aren't great in golang
Just a suggestion, but something that might help in your case: I find that constants are less likely to be changed/broken later on if it's clear that the values look like bit masks, which you can do in go like so:
const (
Red = 1 << iota
Green
Blue
) // values = 1, 2, 4
And, even though it's not the prettiest of declarations, you can include the mask constants, too
const (
Red, RedMask = 1 << iota, 1<< iota - 1 // Red = 1, RedMask = 0
Green, GreenMask // Green = 2, mask = 1
Blue, BlueMask // 4, 3
RGB, RGBMask // 8, 7
)
This, coupled with a designated type for these constants might be useful:
type ColourConst int
const (
Red, RMask ColourConst = 1 << iota, 1 << iota-1
// ...
_, All
)
// something like this (untested, might not be correct)
func (c ColourConst) validate() error {
mask := int(c) & (-1 * int(c))
if mask != int(c) {
return errors.New("Colour is not a single bit value")
}
if s := c & All; s != c {
return errors.New("Colour is not in range")
}
}
I know that the days of the week are unlikely to be used as bitmasks, but it makes it less likely for people to break the code. At the very least, it communicates that the order of the constants matter, that's what iota does IMO.
Solution.
There're excellent modules Enumer and Enumelinter
Related
Luckily i found this side:
https://www.linuxtut.com/en/150745ae0cc17cb5c866/
(There are many Linetypes difined
Excel Enum XlLineStyle)
(xlContinuous = 1
xlDashDot = 4
xlDashDotDot = 5
xlSlantDashDot = 13
xlDash = -4115
xldot = -4118
xlDouble = -4119
xlLineStyleNone = -4142)
i run with try and except +/- 100.000 times set lines because i thought anywhere should be this
[index] number for put this line in my picture too but they warsnt.. why not?
how can i set this line?
why are there some line indexe's in a such huge negative ranche and not just 1, 2, 3...?
how can i discover things like the "number" for doing things like that?
why is this even possible, to send apps data's in particular positions, i want to step a little deeper in that, where can i learn more about this?
(1) You can't find the medium dashed in the linestyle enum because there is none. The line that is drawn as border is a combination of lineStyle and Weight. The lineStyle is xlDash, the weight is xlThin for value 03 in your table and xlMedium for value 08.
(2) To figure out how to set something like this in VBA, use the Macro recorder, it will reveal that lineStyle, Weight (and color) are set when setting a border.
(3) There are a lot of pages describing all the constants, eg have a look to the one #FaneDuru linked to in the comments. They can also be found at Microsoft itself: https://learn.microsoft.com/en-us/office/vba/api/excel.xllinestyle and https://learn.microsoft.com/en-us/office/vba/api/excel.xlborderweight. It seems that someone translated them to Python constants on the linuxTut page.
(4) Don't ask why the enums are not continuous values. I assume especially the constants with negative numbers serve more that one purpose. Just never use the values directly, always use the defined constants.
(5) You can assume that numeric values that have no defined constant can work, but the results are kind of unpredictable. It's unlikely that there are values without constant that result in something "new" (eg a different border style).
As you can see in the following table, not all combination give different borders. Setting the weight to xlHairline will ignore the lineStyle. Setting it to xlThick will also ignore the lineStyle, except for xlDouble. Ob the other hand, xlDouble will be ignored when the weight is not xlThick.
Sub border()
With ThisWorkbook.Sheets(1)
With .Range("A1:J18")
.Clear
.Interior.Color = vbWhite
End With
Dim lStyles(), lWeights(), lStyleNames(), lWeightNames
lStyles() = Array(xlContinuous, xlDash, xlDashDot, xlDashDotDot, xlDot, xlDouble, xlLineStyleNone, xlSlantDashDot)
lStyleNames() = Array("xlContinuous", "xlDash", "xlDashDot", "xlDashDotDot", "xlDot", "xlDouble", "xlLineStyleNone", "xlSlantDashDot")
lWeights = Array(xlHairline, xlThin, xlMedium, xlThick)
lWeightNames = Array("xlHairline", "xlThin", "xlMedium", "xlThick")
Dim x As Long, y As Long
For x = LBound(lStyles) To UBound(lStyles)
Dim row As Long
row = x * 2 + 3
.Cells(row, 1) = lStyleNames(x) & vbLf & "(" & lStyles(x) & ")"
For y = LBound(lWeights) To UBound(lWeights)
Dim col As Long
col = y * 2 + 3
If x = 1 Then .Cells(1, col) = lWeightNames(y) & vbLf & "(" & lWeights(y) & ")"
With .Cells(row, col).Borders
.LineStyle = lStyles(x)
.Weight = lWeights(y)
End With
Next
Next
End With
End Sub
So we can generate a unique id with str(uuid.uuid4()), which is 36 characters long.
Is there another method to generate a unique ID which is shorter in terms of characters?
EDIT:
If ID is usable as primary key then even better
Granularity should be better than 1ms
This code could be distributed, so we can't assume time independence.
If this is for use as a primary key field in db, consider just using auto-incrementing integer instead.
str(uuid.uuid4()) is 36 chars but it has four useless dashes (-) in it, and it's limited to 0-9 a-f.
Better uuid4 in 32 chars:
>>> uuid.uuid4().hex
'b327fc1b6a2343e48af311343fc3f5a8'
Or just b64 encode and slice some urandom bytes (up to you to guarantee uniqueness):
>>> base64.b64encode(os.urandom(32))[:8]
b'iR4hZqs9'
TLDR
Most of the times it's better to work with numbers internally and encode them to short IDs externally. So here's a function for Python3, PowerShell & VBA that will convert an int32 to an alphanumeric ID. Use it like this:
int32_to_id(225204568)
'F2AXP8'
For distributed code use ULIDs: https://github.com/mdipierro/ulid
They are much longer but unique across different machines.
How short are the IDs?
It will encode about half a billion IDs in 6 characters so it's as compact as possible while still using only non-ambiguous digits and letters.
How can I get even shorter IDs?
If you want even more compact IDs/codes/Serial Numbers, you can easily expand the character set by just changing the chars="..." definition. For example if you allow all lower and upper case letters you can have 56 billion IDs within the same 6 characters. Adding a few symbols (like ~!##$%^&*()_+-=) gives you 208 billion IDs.
So why didn't you go for the shortest possible IDs?
The character set I'm using in my code has an advantage: It generates IDs that are easy to copy-paste (no symbols so double clicking selects the whole ID), easy to read without mistakes (no look-alike characters like 2 and Z) and rather easy to communicate verbally (only upper case letters). Sticking to numeric digits only is your best option for verbal communication but they are not compact.
I'm convinced: show me the code
Python 3
def int32_to_id(n):
if n==0: return "0"
chars="0123456789ACEFHJKLMNPRTUVWXY"
length=len(chars)
result=""
remain=n
while remain>0:
pos = remain % length
remain = remain // length
result = chars[pos] + result
return result
PowerShell
function int32_to_id($n){
$chars="0123456789ACEFHJKLMNPRTUVWXY"
$length=$chars.length
$result=""; $remain=[int]$n
do {
$pos = $remain % $length
$remain = [int][Math]::Floor($remain / $length)
$result = $chars[$pos] + $result
} while ($remain -gt 0)
$result
}
VBA
Function int32_to_id(n)
Dim chars$, length, result$, remain, pos
If n = 0 Then int32_to_id = "0": Exit Function
chars$ = "0123456789ACEFHJKLMNPRTUVWXY"
length = Len(chars$)
result$ = ""
remain = n
Do While (remain > 0)
pos = remain Mod length
remain = Int(remain / length)
result$ = Mid(chars$, pos + 1, 1) + result$
Loop
int32_to_id = result
End Function
Function id_to_int32(id$)
Dim chars$, length, result, remain, pos, value, power
chars$ = "0123456789ACEFHJKLMNPRTUVWXY"
length = Len(chars$)
result = 0
power = 1
For pos = Len(id$) To 1 Step -1
result = result + (InStr(chars$, Mid(id$, pos, 1)) - 1) * power
power = power * length
Next
id_to_int32 = result
End Function
Public Sub test_id_to_int32()
Dim i
For i = 0 To 28 ^ 3
If id_to_int32(int32_to_id(i)) <> i Then Debug.Print "Error, i=", i, "int32_to_id(i)", int32_to_id(i), "id_to_int32('" & int32_to_id(i) & "')", id_to_int32(int32_to_id(i))
Next
Debug.Print "Done testing"
End Sub
Yes. Just use the current UTC millis. This number never repeats.
const uniqueID = new Date().getTime();
EDIT
If you have the rather seldom requirement to produce more than one ID within the same millisecond, this method is of no use as this number‘s granularity is 1ms.
Shortish version
I am using this regex:
(^|[yY]\s{0,}\=|\+|\-)\s{0,}([0-9]{0,}\.?[0-9]{0,})\s{0,}(\*{0,1}[xX]{0,1})\s{0,}(\^{0,1})(-?)([0-9]{0,}\.?[0-9]{0,})(\s{0,}|$)?
To try and extract all the element coefficient and order numbers from equations like this:
y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1
I want the regex to ignore the erroneous 4x^ which is missing its power number (doesn't currently do this) and allow me to get to this final result:
((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -3.5), (1.1, 0.0))
Where first coordinate is coefficient and second is order for each element. Currently the regex above 'nearly' works if I take groups 1&2 and 5&6 to give me the coefficient and order respectively.
It just falls over on the erroneous 4x^ plus feels extremely inelegant, but I am somewhat noob at regex and am not sure what improvements to make.
How can I improve this regex, and also fix so that 4x^ is considered 'wrong' but 4x2 and 4x^2 are both fine?
tl;dr version
I am trying parse polynomial equations entered by users in order to validate and then decompose the equation into a series of elements. The equations will be presented as strings.
Here is an example of how the users are asked to format their string:
y = 2.0x^2.5 - 3.1x + 5.2
Where x is the independent variable (not a times symbol) and y is the dependent variable.
In reality the users commonly make any of the following mistakes:
Forgetting to include y =
Adding a * to coefficients such as y = 2.0*x
Using integers instead of floats, e.g. y = 5x
Missing the ^ when setting the order e.g. y = x3
Adding or removing whitespace anywhere
However, for all of these I'd say it's still easily understandable what the user is trying to write. By that I mean it is obvious what the coefficient and order are meant to be for each element.
So what I want to do is write some regex that correctly splits the entered string into separate elements and can get me A (the coefficient) and B (the order) of each element where an element in general is of the form Ax^B and A and B can each be any real number.
I devised the following example:
y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1
Which I believe covers all of the potential issues I outlined above, in addition to one other straight up mistake 4x^+2x^2 is missing the order on the element 4x^.
For this example I'd like to get to: ((1.0, 1.0), (3.3, -50.0), (15.0, 25.5), (2.0, 2.0), (3.0, -3.5), (1.1, 0.0)) where 4x^ has been ignored.
I am somewhat new to regex but I have made an effort using regex101.com to create the following:
(^|[yY]\s{0,}\=|\+|\-)\s{0,}([0-9]{0,}\.?[0-9]{0,})\s{0,}(\*{0,1}[xX]{0,1})\s{0,}(\^{0,1})(-?)([0-9]{0,}\.?[0-9]{0,})(\s{0,}|$)?
This appears to nearly work, with the following issues:
Does not catch missing order as per example 4x^ given above - I am not sure how to make the optionality of the order number 'conditional' on the presence of ^ whilst also working when ^ is not present but the order number is such as y = 4x2
Feels extremely in-concise / inelegant, but being inexperienced I am struggling to see where improvements can be made
Also please note I am happily ignoring the issue of repeated elements with the same order not being summed, e.g. I am happy to ignore y = x^2 + x^2 not appearing as y = 2x^2.
Thank you for any help.
p.s. Program to be written in Go, but I am also somewhat noob at Go so I am first prototyping in Python. Not sure if this will make any difference to the regex (I really am that new to regex).
The following regex will mostly do:
(?P<c1>[+-]? *\d+(?:\.\d+)?)? *\*? *[xX] *(?:\^ *(?P<e1>-? *\d+(?:\.\d+)?)|(?P<e2>-? *\d+(?:\.\d+)?)?)|(?P<c2>[+-]? *\d+(?:\.\d+)?)
I say mostly because this solution takes the "4x^" case as having order 1, given the requirements are already pretty lenient and otherwise trying to ignore such term makes the RE much much more complicated or even impossible because it creates an ambiguity which can not be parsed with a RE.
Please note that absent coeficients/exponents will not be captured as '1.0' as you represent in your example result, that will have to be done after applying the regex and taking all empty capture groups as '1' (or '0' for the exponent depending on the captured groups).
Here you have the regex in regex101.com for checking/trying how it works.
And here a working program in golang which tests a couple of cases:
package main
import (
"fmt"
"regexp"
"strconv"
"strings"
)
const e = `(?P<c1>[+-]? *\d+(?:\.\d+)?)? *\*? *[xX] *(?:\^ *(?P<e1>-? *\d+(?:\.\d+)?)|(?P<e2>-? *\d+(?:\.\d+)?)?)|(?P<c2>[+-]? *\d+(?:\.\d+)?)`
var cases = []string{
"y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1",
"3.3X^-50",
}
func parse(d float64, ss ...string) float64 {
for _, s := range ss {
if s != "" {
c, _ := strconv.ParseFloat(strings.Replace(s, " ", "", -1), 64)
return c
}
}
return d
}
func main() {
re := regexp.MustCompile(e)
for i, c := range cases {
fmt.Printf("testing case %v: %q\n", i, c)
ms := re.FindAllStringSubmatch(c, -1)
if ms == nil {
fmt.Println("no match")
continue
}
for i, m := range ms {
fmt.Printf(" match %v: %q\n", i, m[0])
c := parse(1.0, m[1], m[4])
de := 1.0
if m[4] != "" {
de = 0.0
}
e := parse(de, m[2], m[3])
fmt.Printf(" c: %v\n", c)
fmt.Printf(" e: %v\n", e)
}
}
}
Which outputs:
testing case 0: "y=x+3.3X^-50+ 15x25.5 - 4x^+2x^2 +3*x-2.5+1.1"
match 0: "x"
c: 1
e: 1
match 1: "+3.3X^-50"
c: 3.3
e: -50
match 2: "+ 15x25.5"
c: 15
e: 25.5
match 3: "- 4x"
c: -4
e: 1
match 4: "+2x^2"
c: 2
e: 2
match 5: "+3*x-2.5"
c: 3
e: -2.5
match 6: "+1.1"
c: 1.1
e: 0
testing case 1: "3.3X^-50"
match 0: "3.3X^-50"
c: 3.3
e: -50
Here you have the program on golang playground to try.
I have this set of constants declarations
self.POUTPUT = 1
self.PPWM = 2
self.PINPUT = 4
self.PUNUSED = 8
self.PSONAR = 16
self.PULTRA = 32
self.PSERVOD = 64
self.PSTEPPER = 128
self.PCOUNT = 256
self.PINPUTDOWN = 512
self.PINPUTNONE = 1024
What is the pythonic way of checking whether a value matches any of the input states (4,512 and 1024) please?
Extra info: I'd normally just use bit pattern checking in simpler languages but I wondered if there was a better way in Python :)
Basically it is that each pin can have one of the I/O states above but if a pin is any of of the input values then one action occurs
e.g if pin == 4 or 512 or 1024 -> do something
if SOME_DATA & self.PINPUTNONE: # do somethign
is how people usually do it
to check alot
ANY = self.POUTPUT | self.PPWM | self.PINPUT | self.PUNUSED | self.PSONAR ...
if some_data & ANY: #do something
Testing for set membership (which is what you seem to be doing) is best done using a set.
self.input_states = {self.PINPUT, self.PINPUTDOWN, self.PINPUTNONE}
# later
if value in self.input_states:
do_something()
Of course you could handle this in a variety of essentially-identical ways, but one way or another you have to encode some knowledge as to which of these magic numbers are "input states".
Now if, as has been suggested, what you actually want is to do some bit-masking or tests based on whether a particular bit is set, then you want to take a look at the Python bitwise operators. In particular, to see if a value is equal to one of the ones you've got there, you'd use the bitwise and, which is denoted by & in Python. Joran's answer covers this use well, but the basic idea is:
if value & self.PINPUT: # Value has a 1 in the PINPUT bit (bit 3)
do_something()
Or if all of those input values trigger the same action:
if any(value & p for p in (self.PINPUT, self.PINPUTDOWN, self.PINPUTNONE)):
do_something()
I'm not sure what to call what I'm looking for; so if I failed to find this question else where, I apologize. In short, I am writing python code that will interface directly with the Linux kernel. Its easy to get the required values from include header files and write them in to my source:
IFA_UNSPEC = 0
IFA_ADDRESS = 1
IFA_LOCAL = 2
IFA_LABEL = 3
IFA_BROADCAST = 4
IFA_ANYCAST = 5
IFA_CACHEINFO = 6
IFA_MULTICAST = 7
Its easy to use these values when constructing structs to send to the kernel. However, they are of almost no help to resolve the values in the responses from the kernel.
If I put the values in to dict I would have to scan all the values in the dict to look up keys for each item in each struct from the kernel I presume. There must be a simpler, more efficient way.
How would you do it? (feel free to retitle the question if its way off)
If you want to use two dicts, you can try this to create the inverted dict:
b = {v: k for k, v in a.iteritems()}
Your solution leaves a lot of work do the repeated person creating the file. That is a source for error (you actually have to write each name three times). If you have a file where you need to update those from time to time (like, when new kernel releases come out), you are destined to include an error sooner or later. Actually, that was just a long way of saying, your solution violates DRY.
I would change your solution to something like this:
IFA_UNSPEC = 0
IFA_ADDRESS = 1
IFA_LOCAL = 2
IFA_LABEL = 3
IFA_BROADCAST = 4
IFA_ANYCAST = 5
IFA_CACHEINFO = 6
IFA_MULTICAST = 7
__IFA_MAX = 8
values = {globals()[x]:x for x in dir() if x.startswith('IFA_') or x.startswith('__IFA_')}
This was the values dict is generated automatically. You might want to (or have to) change the condition in the if statement there, according to whatever else is in that file. Maybe something like the following. That version would take away the need to list prefixes in the if statement, but it would fail if you had other stuff in the file.
values = {globals()[x]:x for x in dir() if not x.endswith('__')}
You could of course do something more sophisticated there, e.g. check for accidentally repeated values.
What I ended up doing is leaving the constant values in the module and creating a dict. The module is ip_addr.py (the values are from linux/if_addr.h) so when constructing structs to send to the kernel I can use if_addr.IFA_LABEL and resolves responses with if_addr.values[2]. I'm hoping this is the most straight forward so when I have to look at this again in a year+ its easy to understand :p
IFA_UNSPEC = 0
IFA_ADDRESS = 1
IFA_LOCAL = 2
IFA_LABEL = 3
IFA_BROADCAST = 4
IFA_ANYCAST = 5
IFA_CACHEINFO = 6
IFA_MULTICAST = 7
__IFA_MAX = 8
values = {
IFA_UNSPEC : 'IFA_UNSPEC',
IFA_ADDRESS : 'IFA_ADDRESS',
IFA_LOCAL : 'IFA_LOCAL',
IFA_LABEL : 'IFA_LABEL',
IFA_BROADCAST : 'IFA_BROADCAST',
IFA_ANYCAST : 'IFA_ANYCAST',
IFA_CACHEINFO : 'IFA_CACHEINFO',
IFA_MULTICAST : 'IFA_MULTICAST',
__IFA_MAX : '__IFA_MAX'
}