[Question]
  [
# Objective
Write a program or function that checks if a variable name is valid and output 1 or `True` if it is valid, 0.5 if it is valid but starts with an underscore (\_), and 0 or `False` if it is not valid.
# Rules
* A variable name in most languages is valid if it begins with an underscore or letter (a-z, A-Z, \_) and the rest of the characters are either underscores, letters, or numbers. (a-z, A-Z, 0-9, \_)
* Output 1 or `True` if the variable name is valid and 0 or `False` if not valid.
* However, it is not good practice to start a variable with an underscore, so return 0.5 if it starts with an underscore and the name is valid.
# Test Cases
## Input
`abcdefghijklmnop`
## Output
`1`
## Input
`_test_`
## Output
`0.5` (starts with an underscore)
## Input
`123abc`
## Output
`0` (starts with a number)
## Input
`A_b1C_23`
## Output
`1`
## Input
`_!`
## Output
`0` (not 0.5 because it's not valid)
## Input
`magical pony1`
## Output
`0` (no spaces)
[Standard loopholes](http://meta.codegolf.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) apply.
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so shortest code wins.
**Bonus:** -10% if your program/function outputs `0` for an empty string(`""`).
  
[Answer]
## JavaScript (ES6), 37 - 10% = 33.3 bytes
Saved 4 bytes thanks to @edc65
Saved 5.6 bytes thanks to @Mateon
```
s=>!/^\d|\W|^$/.test(s)/-~(s[0]=='_')
```
[Answer]
# [05AB1E](http://github.com/Adriandmen/05AB1E), ~~25~~ ~~24~~ ~~20~~ 19 bytes
Code:
```
¬D'_Qsa·+¹žj-""Q*2/
```
Explanation:
```
¬                     # Push input and also push the first character.
 D                    # Duplicate the first character.
  '_Q                 # Check if it is equal to an underscore character.
     sa               # Swap and check the duplicate if it's an alphabetic character.
       ·              # Double the value.
        +             # Add both values up
         ¹            # Take the first input.
          žj-         # žj is short for [a-zA-Z0-9_]. This will be substracted from the
                        initial string. 
             ""Q      # Check if the string is empty.
                *     # Multiply this with the first value.
                 2/   # Halve it, resulting into 0.0, 0.5, or 1.0.
```
In short, the formula for the string `s` in pseudocode is:
```
((s[0] == '_' + s.isalpha() × 2) × (s.remove([a-zA-Z0-9_]) == "")) / 2
```
[Try it online!](http://05ab1e.tryitonline.net/#code=wqxEJ19Rc2HCtyvCucW-ai0iIlEqMi8&input=bWFnaWNhbCBwb255MQ)
Uses **CP-1252** encoding.
[Answer]
## PHP (50 - 10% = 45)
Thanks to Schism for the -2 :)
```
preg_match('/^[a-z_]\w*$/i',$s)?$s[0]=='_'?.5:1:0;
```
Not to compete with the golflang answers, but I thought I'd try it anyways.
```
preg_match('/^[a-z_]\w*$/i', $s) # Matches every a-zA-Z0-9_ string that doesnt start with a number
?   $s[0] == '_'                   # Then, if it starts with an _
    ?   .5                         # give 0.5 points
    :   1                          # If it doesn't, give 1
:   0;                             # If it didn't match the regex, give 0
```
Something to note is that in PHP, without the `/u` modifier, `\w` only selects ASCII letters. In some other languages/Regex flavours, this pattern won't work.
**Edit**: I see a lot of people using \w and \d in their answers, when they use a language that includes non-ASCII letters and digits too. That is NOT the puzzle. They are wrong. (Can't downvote/comment yet, sorry to need to tell it this way.)
[Answer]
# Retina, ~~30 - 10% = 27~~ ~~28 - 10% = 25.2~~ 29 - 10% = 26.1 bytes
Both versions qualify for bonus, as they handle empty input correctly (outputs `0`)
I had to fix a bug caused by one of .NET regex features, which considers some (read as many) Unicode characters as "word" characters. Fortunately, this cost me only a single byte in both versions. It only came down to adding a modifier to make the regex matching behavior compliant to ECMAScript standards. More about that [here](https://msdn.microsoft.com/en-us/library/20bw873z%28v=vs.110%29.aspx#Anchor_5).
### New ~~28~~ 29-byte version, made by @MartinBüttner. Thanks!
```
^_
$_¶_
Mme`^(?!\d)\w+$
2
0.5
```
### Explanation
First, we check if the input starts with an underscore. If it does, the input is duplicated, with a newline in between. For example: `_test_` -> `_test_\n_test_`, where `\n` is the newline. Then we try to match anything, that doesn't start with a number, but is followed by any number of "word" characters (`a-z`, `A-Z`, digits, and underscore) *on each line*. Note that if input started with an underscore and was replaced to two lines, this will match both lines. Then we check if we had 2 matches, and replace them with `0.5`. Empty or invalid line will always yield 0 matches, and valid variable names always yield 1 match.
---
### My own ~~30~~ 31-byte version
```
Ae`^\d|\W
^_.*
0.5
^\D.*
1
^$
0
```
### Explanation
First of all, we check if input starts with a digit or contains a non-word character (anything other than `a-z`, `A-Z`, digits and underscore). If it does, it's discarded, because it's invalid. Then we check if it starts with an underscore. If it does, it's replaced with `0.5`. Then we check if it starts with a non-digit character (at this point the first character is either `0`, `a-z`, or `A-Z`. Only `a-z` and `A-Z` are non-digits, obviously). If it does, it's replaced with a `1`. Then we check for empty string and replace it with `0`.
[Try it online!](http://retina.tryitonline.net/#code=Xl8KJF_Ctl8KTW1lYF4oPyFcZClcdyskCjIKMC41&input=X3Rlc3Rf)  
[Try it online! Old version](http://retina.tryitonline.net/#code=QWVgXlxkfFxXCl5fLioKMC41Cl5cRC4qCjEKXiQKMA&input=X3Rlc3Rf)
[Answer]
# Python 3, 36 bytes
```
lambda s:s.isidentifier()/-~(s[:1]=='_')
```
The code is **40 bytes** long and qualifies for the **-10% bonus**.
Note that this will only work correctly for code pages that don't have non-ASCII letters/digits.
[Answer]
# [MATL](https://esolangs.org/wiki/MATL), 27 bytes
```
1)95=2/8M3Y2m+G7M95h4Y2hmA*
```
This works in [current version(15.0.0)](https://github.com/lmendo/MATL/releases/tag/15.0.0) of the language.
Input is a string with single quotes.
[**Try it online!**](http://matl.tryitonline.net/#code=MSk5NT0yLzhNM1kybStHN005NWg0WTJobUEq&input=J190ZXN0Xyc)
### Explanation
```
1)      % take input implicitly. Get its first element
95=     % true if it equals 95 (underscore)
2/      % divide by 2: gives 0.5 if underscore, 0 if not
8M      % push first element of input again
3Y2     % predefined literal: string with all letters
m       % true if it's a letter
+       % add. Gives 1 if letter, 0.5 if underscore
G       % push input again
7M      % push string with all letters again
95h     % concatenate underscore
4Y2h    % predefined literal: string with all digits. Concatenate
mA      % true if all input chars belong to that concatenated string
*       % multiply. Display implicitly
```
[Answer]
## [Pyke](https://github.com/muddyfish/PYKE), 21 bytes
### (noncompeting, added string subtraction, various string constants)
```
Qh~u{Q~J\_+-|!Qh\_qh/
```
Explanation:
```
Qh~u{                 - Check first char isn't a digit
     Q~J\_+-          - Is the input alphanumeric + "_"
            |!        - Combine
              Qh\_q   - Is the first char an "_"
                   h/ - Combine
```
[Answer]
## Pyth, 27 bytes
```
c!|-rz0++G\_JjkUT}hzJhqhz\_
```
[Test Suite](http://pyth.herokuapp.com/?code=c!|-rz0%2B%2BG%5C_JjkUT%7DhzJhqhz%5C_&input=abcdefghijklmnop%0A123abc%0A_test_&test_suite=1&test_suite_input=abcdefghijklmnop%0AABcdefghijklmnop%0A123abc%0A_test_&debug=0)
[Answer]
# [Gogh](https://github.com/zachgates7/Gogh), 29 bytes
```
÷"[^\W\d]\w*"g¦"_.*"g+÷2=0.5¿
```
Run using:
```
$ ./gogh no '÷"[^\W\d]\w*"g¦"_.*"g+÷2=0.5¿' "_test"
```
---
### Explanation
```
                   “ Implicit input                               ”
÷                  “ Duplicate the TOS                            ”
"[^\W\d]\w*"g      “ Fully match the STOS against the TOS (regex) ”
¦                  “ Swap the STOS and TOS                        ”
"_.*"g             “ Fully match the STOS against the TOS (regex) ”
+                  “ Add the TOS to the STOS                      ”
÷                  “ Duplicate the TOS                            ”
2=                 “ Determine if the TOS is equal to 2           ”
0.5¿               “ Leave the correct output on the stack        ”
                   “ Implicit output                              ”
```
[Answer]
# Perl, 21 bytes
```
$_=!/\W|^\d//2**/^_/
```
The score includes **+1 byte** for the `-p` switch. Try it on [Ideone](http://ideone.com/7JreBb).
[Answer]
# Pyth, 19 bytes
```
c!:z"\W|^\d"0h!xz\_
```
Try it with the [Pyth Compiler](http://pyth.herokuapp.com/?code=c%21%3Az%22%5CW%7C%5E%5Cd%220h%21xz%5C_&input=abcdefghijklmnop%0A123abc%0A_test_&test_suite=1&test_suite_input=abcdefghijklmnop%0A_test_%0A123abc%0AA_b1C_23%0A_%21%0Amagical+pony1&debug=0).
Note that this will only work correctly for code pages that don't have non-ASCII letters/digits.
### How it works
```
c!:z"\W|^\d"0h!xz\_  (implicit) Save the input in z.
  :z        0        Test if z matches the following regex:
    "\W|^\d"           A non-word character or a digit at the beginning.
                     This returns True iff z is an invalid name.
 !                   Apply logical NOT to yield True iff z is a valid name.
               xz\_  Find the first index of the underscore in z.
                     This yields 0 iff z begins with an underscore.
             h!      Apply logical NOT and increment.
                     This yields 2 if z begins with an underscore, 1 otherwise.
c                    Divide the two results.
```
[Answer]
# [Factor](http://factorcode.org/), 84 \* 0.9 = 76.5
```
USE: regexp
[ R/ [_a-zA-Z]\w*/ R/ _.*/ [ matches? 1 0 ? ] bi-curry@ bi 0 = 1 2 ? / ]
```
Runs on the listener (repl), defines a quotation (anonymous function) that takes a string and outputs { 0 | 1/2 | 1 }.
Defining it as a word it's 97 chars:
```
USE: regexp
: v ( s -- n ) R/ [_a-zA-Z]\w*/ R/ _.*/ [ matches? 1 0 ? ] bi-curry@ bi 0 = 1 2 ? / ;
```
### How does it work:
`R/ [_a-zA-Z]\w*/ R/ _.*/` defines two regular expressions. `bi-curry@` partially applies the quotation `[ matches? 1 0 ? ]` to each regex, leaving two curried quotations on the stack. `bi` applies each quotation to the argument string.
Each of those (curried quotations) leave either a 1 or a 0, depending if they matched. The first matches on the well formed names, the second on names starting with underscore.
`0 = 1 2 ? /` The last value is replaced with a 1 if it was 0, or with a 2 if it was 1. Then the first (1 or 0, valid or not) is divided by the second (2 or 1, starts with underscore or not).
This is loooong! Any pointers to shrinking a bit more appreciated...
And I hate regexps!
### PS.
```
{ 0 } [ "" v ] unit-test
{ 0 } [ "" v ] unit-test
{ 0 } [ "1" v ] unit-test
{ 0 } [ "1var" v ] unit-test
{ 0 } [ "var$" v ] unit-test
{ 0 } [ "foo var" v ] unit-test
{ 1 } [ "v" v ] unit-test
{ 1 } [ "var" v ] unit-test
{ 1 } [ "var_i_able" v ] unit-test
{ 1 } [ "v4r14bl3" v ] unit-test
{ 1/2 } [ "_" v ] unit-test
{ 1/2 } [ "_v" v ] unit-test
{ 1/2 } [ "_var" v ] unit-test
{ 1/2 } [ "_var_i_able" v ] unit-test
{ 1/2 } [ "_v4r14bl3" v ] unit-test
```
all test pass ;)
[Answer]
# [Dyalog APL](http://goo.gl/9KrKoM), 19 bytes - 10% = 17.1
```
{(0≤⎕NC⍵)÷1+'_'=⊃⍵}
```
`{`…`⍵`…`}` anonymous function where the right argument is represented by `⍵`  
`⊃⍵` first character (gives space if empty)  
`'_'=` 1 if equal to 'underbar, 0 otherwise  
`1+` evaluates to 2 if initial underbar, 1 otherwise  
`⎕NC⍵` [name class](http://help.dyalog.com/14.1/Content/Language/System%20Functions/nc.htm); -1 if invalid name, 0 if undefined (but valid name), 2-9 if defined (and thus valid)
[Answer]
# Mathematica, 93 bytes
```
If[#~StringMatchQ~RegularExpression@"[A-Za-z_][0-9A-Za-z_]*",If[#~StringTake~1=="_",.5,1],0]&
```
I'm honestly not sure if this *can* be golfed further.
[Answer]
# Perl, 34 + 1 = 35 bytes
```
$_=/^([^\W\d])\w*$//(($1 eq"_")+1)
```
Uses the `-p` flag.
## Explanation
```
$_=/^([^\W\d])\w*$//(($1 eq"_")+1)
   /^([^\W\d])\w*$/                 matches any string that starts with an underscore or a letter of the alphabet followed by 0 or more alphanumeric + underscore characters. The first character is stored in a capture group
                   /                divide result by
                    (($1 eq"_")+1)  (capture == "_") + 1. This is 1 if the first character was not an underscore and 2 if it was.
$_=                                 assign to $_ and implicitly print
```
[Answer]
# Python, 84 -10% = 76 bytes
```
lambda x:[0,[[.5,1][x[0]>'z'],0][x[0]<'A']][x.replace('_','a').isalnum()]if x else 0
```
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal), 22 bytes
```
hkdc¬:[kr\_+?F¬?h\_=ß½
```
[Try it Online!](https://lyxal.pythonanywhere.com?flags=&code=hkdc%C2%AC%3A%5Bkr%5C_%2B%3FF%C2%AC%3Fh%5C_%3D%C3%9F%C2%BD&inputs=_test_&header=&footer=)
A mess.
[Answer]
# [Japt](https://github.com/ETHproductions/japt), 23 [bytes](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
Guess which genius once upon a time suggested removing `_` from Japt's `\w` character class thereby costing himself 3 bytes here! ETH *was* going to add a new class with `_` included but then he disappeared.
```
¥f"[%l_][%w_]+")/ÒUè"^_
```
[Try it](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=pWYiWyVsX11bJXdfXSsiKS/SVegiXl8&input=ImFiY2RlZmdoaWprbG1ub3Ai) or [run all test cases](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=pWYiWyVsX11bJXdfXSsiKS/SVegiXl8&input=WwoiYWJjZGVmZ2hpamtsbW5vcCIKIl90ZXN0XyIKIjEyM2FiYyIKIkFfYjFDXzIzIgoiXyEiCiJtYWdpY2FsIHBvbnkxIgpdLW1S)
[Answer]
# JavaScript ES7, 37 bytes
```
x=>!x.match(/\W|^\d/)/2**/^_/.test(x)
```
[Try it online](http://vihan.org/p/esfiddle/?code=f%3Dx%3D%3E!x.match(%2F%5CW%7C%5E%5Cd%2F)%2F2**%2F%5E_%2F.test(x)%3B%0A%5B%0A%20%20%20%20%5B%22abcdefghijklmnop%22%2C%201%5D%2C%0A%20%20%20%20%5B%22_test_%22%2C%20.5%5D%2C%0A%20%20%20%20%5B%22123abc%22%2C%200%5D%2C%0A%20%20%20%20%5B%22A_b1C_23%22%2C%201%5D%2C%0A%20%20%20%20%5B%22_!%22%2C%200%5D%2C%0A%20%20%20%20%5B%22magical%20pony1%22%2C%200%5D%0A%5D.map(x%3D%3E%60%27%24%7Bx%5B0%5D%7D%27%20%3D%20%24%7Bf(x%5B0%5D)%7D%2C%20expected%20%24%7Bx%5B1%5D%7D%60).join(%60%0A%60))
How it works:
```
x=>                                   // Fat arrow function
   !x.match(/\W|^\d/)                 // Gives false if contains non word or starting 
                                      //   with a digit. Booleans in numeric context will 
                                      //   be 0 or 1
                      2**             // 2 to the power of...
                         /^_/.test(x) // gives true if starting with '_'. 
                                      //   true -> 1 -> 2**1 -> 2
                                      //   false -> 0 -> 2**0 -> 1
                     /                // Devide the lValue boolean with the numeric rValue:
                                      // lValue = 0 or 1
                                      // rValue = 2 or 1
```
Port of @Dennis's Perl answer
[Answer]
# Ruby, 44 bytes
```
->(s){s=~/^(_|\d)?\w*$/?$1?$1==?_?0.5:0:1:0}
```
[Answer]
# Ruby, 57 - 10% = 51.3 bytes
```
->(s){case s
when'',/^\d/,/\W/
0
when/^_/
0.5
else
1
end}
```
A pretty naïve approach
[Answer]
# Lua, 82 - 10% = 73.8
```
v=function(s)return(s:match("^[_%a]+[_%w]*$")and 1or 0)*(s:match("_")and.5or 1)end
```
Test Cases:
```
print(v("a") == 1) -- true
print(v("1") == 0) -- true
print(v("_") == 0.5) -- true
print(v("") == 0) -- true
print(v("1a") == 0) -- true
print(v("a1") == 1) -- true
print(v("_1") == 0.5) -- true
print(v("_a") == 0.5) -- true
print(v("1_") == 0) -- true
print(v("a_") == 0.5) -- true
```
[Answer]
# Lua, 68 \* .9 = 61.2 bytes
```
s=arg[1]print(s:find("^[%a_][%w_]*$")and(s:find("^_")and.5or 1)or 0)
```
Takes arguments on the command line
[Answer]
# [Julia 1.3](http://julialang.org/), ~~46~~ 44 -10% = ~~41.4~~ 39.6 bytes
```
!s=[1 .5]count.(r"^[a-z]\w*$"i=>r"^_\w*$",s)
```
[Try it online!](https://tio.run/##RY6/TsMwEMZ3P4WbMiSoTUgrlqBUFMSCEAMdGEqJzo7ruDhOFF/6h4k35JGCE7VisP2777v7fLtWK4iP3ZhCnoucKkOfe4nG4ZyMaYFY2ySKpMKiZSGvymiwX8DIaNdTxHTFor1rD2@i16f3VVjmYyMOU61YA81pum0NR1UZSx7AChfRGvRrQBSNSZI3IcVxQi02ysgkWTJHwHE11He02otGQ51uQVsRpFoYiYXPK60FR18AL0pAXlzyLkH/g@c3CIJuZNN1TMPbzbBC6Dfe5xqm35uPw/WVp9KFq7OBJzboUFi0NKVr4nnEA8ZzsZWF2n3p0lS1k7K@I3MQz@bOdrDMWPyYzea9OXJXCVJx0LSuzCnuRXd@fzyyIeQ@pLXbE7Xxzx8t6GigoPsD "Julia 1.0 – Try It Online")
### explanation
* `r"^[a-z]\w*$"i` is the regex for a variable not starting with a `_` (the `i` means case-insensitive)
* `r"^_\w*$"` for a variable starting with a `_`
* `count.()` counts the number of time each regex appears in s, result is in a vector (similar to a 2×1 matrix)
* `[1 .5]` is a 1×2 matrix, when multiplied by the previous result, gives the expected result (0.5 when starting with `_`, 1 otherwise)
]