2

[ab] matches any of a or b ,\w matches any word character (alphabets, digits, underscore).

I find that [\w-] can't match \w or - .In order to convert Sec-Control into "Sec-Control".The expression can work

s/\(.\+\)/"\1"/

Why s/\([\w-]\+\)/"\1"/ convert Sec-Control into Sec"-"Control instead of "Sec-Control"?

Why [\w-] can't match \w or - ?

1
  • Is this a peculiarity of Vim's regular expressions? The normal way to write this in, say, Perl's regexes would be [-\w] or [\w\-]. A dash is special in character classes, because it's used for ranges like [a-z], so it will either need to be the first character or escaped with a backslash. Commented Mar 15, 2023 at 15:04

2 Answers 2

3

tldr:

  • Use s/\(\(\w\|-\)\+\)/"\1"/, or s/\(\w\|-\)\+/"&"/ instead.
  • Actually, you might want to use s/\(\(\w\|-\)\+\)/"\1"/g, or s/\(\w\|-\)\+/"&"/g. Just add a g to the end.
  • Use \(\w\|-\) instead of [\w-]

first question on s/\(.\+\)/"\1"/

Ok this command breaks down to s / \(.\+\) / "\1" /, meaning replace \(.\+\) with "\1" for each line.

\(.\+\) matches the whole line if it's nonempty. Basically \( and \) are grouping operators in regular expressions, . matches any character except the newline character \n, and \+ means repeated once or more.

the two " are just two double quotes as verbatim. \1 means the first matched group, in this case it's just the whole line.

You post two different patterns. The other one \([\w-]\+\) means [\w-] repeated one or more times.

More

  • the & in tldr means everything that is matched by the substitute pattern (not just in the group)
  • you might consider adding a g to the end, see :h s_g

second question on [\w-]

Characters inside [ and ] are interpreted verbatim (see :h /[]), so [\w-] means:

one character, that is either \, w or -'

The usual exceptions are

  • if the first character in a pair brackets is ^, it's interpreted as 'not match'
    • e.g. [^ab!] matches any character except a b and !
  • if a - appears between two characters in a pair of brackets, it's interpreted as 'range'
    • e.g. [A-Z] matches any uppercase letter
  • character classes like [:alnum:]

In your case you should be using a disjunction pattern (\w or -), just use

\(\w\|-\)

It breaks down to \( \w \| - \). The \( and \) are grouping operators, \| means either the pattern on its left or its right, \w and - are the two patterns we like to match.

I am assuming you're under the default vim setup i.e. magic. See :h magic otherwise.

4

\w is not supported that way in /[. See :h /\]:

- To include a literal ']', '^', '-' or '\' in the collection, put a
  backslash before it: "[xyz\]]", "[\^xyz]", "[xy\-z]" and "[xyz\\]".
  (Note: POSIX does not support the use of a backslash this way).
  [...]
  For '\' you can also let it be followed by
  any character that's not in "^]-\bdertnoUux".  "[\xyz]" matches '\',
  'x', 'y' and 'z'.  It's better to use "\\" though, future expansions
  may use other characters after '\'.

w is not in the list before which \ is special, so \w just means the characters \ and w inside /[...]. What about the other listed characters bdertnoUux? Further down, we have:

- The following translations are accepted when the 'l' flag is not
  included in 'cpoptions':
    \e  <Esc>
    \t  <Tab>
    \r  <CR>    (NOT end-of-line!)
    \b  <BS>
    \n  line break, see above |/[\n]|
    \d123   decimal number of character
    \o40    octal number of character up to 0o377
    \x20    hexadecimal number of character up to 0xff
    \u20AC  hex. number of multibyte character up to 0xffff
    \U1234  hex. number of multibyte character up to 0xffffffff
  NOTE: The other backslash codes mentioned above do not work inside
  []!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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