6

I am trying to convert a String '1' to a Number (int) 1 in a vimL script. I have used the built-in command str2nr() so far, however I was not able to write this in an elegant and effective way.

Ideally I would like to catch invalid strings before attempting to convert them to an integer.

For example: 'abc1' will return 0 when run through the str2nr() command.

I probably need the right regex pattern to catch anything such as: 'a', 'a1b' '7xy' as an illegal value and anything like: '1' or '7' as a legal value, thus filtering out all non-integer values.

I tried something in the lines of:

let l:value = 'abcX1'
let l:debug = l:value =~ '\[0-9]^\[A-Z]\^[a-z]\' ? "YES" : "NO"
echom l:debug

This is expected to return a NO, while this:

let l:value = '7'
let l:debug = l:value =~ '\[0-9]^\[A-Z]\^[a-z]\' ? "YES" : "NO"
echom l:debug

is expected to return a YES.

However, as I said, I am not good with regular expressions and probably building the wrong pattern up in those examples above as they are not working.

Thanks.

  • 3
    If your definition of an invalid string is any string containing a non-digit character, you could use the atom \D like this: let debug = value =~ '\D' ? "NO" : "YES" (Also :help /character-classes might help you) – saginaw Jan 3 '16 at 18:11
  • 2
    Thank you, I think this works as well: let l:debug = empty(a:value =~ '[^0-9]') ? "YES" : "NO" – mbilyanov Jan 3 '16 at 18:47
  • I'm not sure but if you made some tests and it works, then it's all good. If you want more help, maybe add some context from your script, aside from just the 3 lines. If you're interested in writing a regex in general, here are 2 useful links: vimregex.com and regex.learncodethehardway.org/book – saginaw Jan 3 '16 at 19:03
  • 2
    How about converting the result back to string, and comparing with the original? :D – VanLaser Jan 4 '16 at 11:31
  • 1
    I think '[^0-9]' is the correct answer to this -- it will match any string with any characters besides those. You should write that as an answer as well, @symbolix. – Sakari Cajanus Jan 5 '16 at 9:04
3

You can represent the set of non-digit characters with the atom \D or with the expression [^0-9].

So, if your definition of an invalid string is any string containing a non-digit character, you could probably detect it like this:
let debug = value =~ '\D' ? "NO" : "YES"
or like this:
let debug = value =~ '[^0-9]' ? "NO" : "YES"

You can describe a set of characters with a pair of brackets [], and then put inside all the characters you want. You could imagine they're separated by the logical operator OR.

[012]  = 0 or 1 or 2
[0-9]  = 0 or 1 or 2 or ... 9
[^0-9] = anything except 0 or 1 or ... 9

A caret sign (^) positioned inside the pair of brackets just after the opening one allows you to invert the set of characters. It could be read as: anything except what follows.

The regex engine of Vim provides another kind of notation to describe some sets of characters which are then called atoms. For example:

  • \d for digit, same as [0-9]
  • \s for whitespace, a space or a tab
  • \w for word character, same as [0-9A-Za-z_]

Usually you can "invert" an atom by using an uppercase character (there are some exceptions though):

  • \D for non-digit, same as [^0-9]
  • \S for non-whitespace, anything except a space or a tab
  • \W for non-word character, same as [^0-9A-Za-z_]

If you want to know more about the various sets of characters or atoms you can use to build your regexes, see:

:help /character-classes

| improve this answer | |
  • 1
    Thanks a lot! This wraps up the solution in a great detail. – mbilyanov Jan 27 '16 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.