7

New to regex and I need to pattern match on some dates to change the format.

I'm going from mm/dd/yy to yyyy-mm-dd where there are no entries prior to 2000.

What I'm unfamiliar with is how to group things to use their respective references of \1, \2, etc.

Would I first want to match on mm/dd/yy with something like ( \d{2} ) ( \/\d{2} ) ( \/\d{2} ) or is it as easy as \d\d/\d\d/\d\d ?

Assuming my first grouping is partially the right idea, I'm looking to do something like:

:%s/old/new/g
:%s/ ( \d{2} ) ( \/\d{2} ) ( \/\d{2} ) / ( 20+\3) - (\3) - (\1) /g

EDIT: Sorry, the replace is going to a yyyy-mm-dd format with hyphens, not the slash.

4

4 回答 4

11

I was going to comment on another answer but it got complicated.

Mind the magic setting. If you want unescaped parens to do grouping, you need to include \v somewhere in your pattern. (See :help magic).

You can avoid escaping the slashes if you use something other than slashes in the :s command.

You are close. :) You don't want all of those spaces though as they'll require spaces in the same places to match.

My solution, where I use \v so I don't need to escape the parens and exclamation points so I can use slashes in my pattern without escaping them:

:%s!\v(\d{2})/(\d{2})/(\d{2})!20\3-\2-\1!g

This will match "inside" items that start or end with three or more digits though, too. If you can give begin/end criteria then that'd possibly be helpful. Assuming that simple "word boundary" conditions work, you can use <>:

:%s!\v<(\d{2})/(\d{2})/(\d{2})>!20\3-\2-\1!g

To critique yours specifically (for learning!):

:%s/ ( \d{2} ) ( \/\d{2} ) ( \/\d{2} ) / ( 20+\3) - (\3) - (\1) /g
  • Get rid of the spaces since presumably you don't want them!
  • Your grouping needs either \( \) or \v to work
  • You also need \{2} unless you use \v
  • You are putting the slashes in groups two and three which means they'll show up in the replacement too
  • You don't want the parentheses in the output!
  • You're substituting text directly; you don't want the + after the 20 in the output
于 2012-11-02T19:19:47.700 回答
1

Try this:

:%s/\(\d\{2}\)\/\(\d\{2}\)\/\(\d\{2}\)/20\3-\2-\1/g

The bits you're interested in are: \(...\) - capture; \d - a digit; \{N} - N occurrences; and \/ - a literal forward slash.

So that's capturing two digits, skipping a slash, capturing two more, skipping another slash, and capturing two more, then replacing it with "20" + the third couplet + "-" + the second couplet + "-" + the first couplet. That should turn "dd/mm/yy" into "20yy-mm-dd".

于 2012-11-02T18:54:23.757 回答
1

ok, try this one:

 :0,$s#\(\d\{1,2\}\)/\(\d\{1,2\}\)/\(\d\{1,2\}\)#20\3-\2-\1#g

I've removed a lot of the spaces, both in the matching section and the replacement section, and most of parens, because the format you were asking for didn't have it.

Some things of note:

  • With vi you can change the '/' to any other character, which helps when you're trying to match a string with slashes in it.. I usually use '#' but it doesn't have to be.
  • You've got to escape the parens, and the curly braces
  • I use the :0,$ instead of %s, but I think it has the same meaning -- apply the following command to every row between row 0 and the end.
于 2012-11-02T19:18:46.863 回答
-1

For the match: (\d{2})\/(\d{2})\/(\d{2})

For the replace: 20\3\/\1\/\2

于 2012-11-02T18:54:01.263 回答