63

I am completely new to regex and I would greatly appreciate any help.

The task is simple. I have a CSV file with records that read like this:

12345,67890,12345,67890
12345,67890,12345,67890
12345,67890,12345,67890
12345,67890,12345,67890
12345,67890,12345,67890

I would like to replace the first comma with a space and leave the rest of the commas intact, for every line. Is there a regex expression that will only match the first comma?

I tried this: ^.....,. This matches the comma, however, it also matches the entire length of the string preceding the comma, so if I try to replace this with a space all of the numbers are deleted as well.

2
  • what tool are you using? (sed, perl, awk, something else?)
    – Mat
    Apr 5, 2011 at 6:07
  • 2
    Textpad (Windows) Apr 5, 2011 at 6:14

7 Answers 7

85

The matching pattern could be:

^([^,]+),

That means

^        starts with
[^,]     anything but a comma
+        repeated one or more times (use * (means zero or more) if the first field can be empty)
([^,]+)  remember that part
,        followed by a comma

In e.g. perl, the whole match and replace would look like:

s/^([^,]+),/\1 /

The replacement part just takes the whole thing that matched and replaces it with the first block you remembered and appends a space. The coma is "dropped" because it's not in the first capturing group.

2
  • 1
    Awesome! Thank you Mat, it worked great. It actually did not work in Textpad (I think their regex is limited), so I ended up downloading PowerGrep, and used the search and replace with the expression you provided and it worked great. Thanks also for the nice explanation, it helps understand what's going on. Apr 5, 2011 at 7:15
  • But the expression matches everything until first comma. Not the first comma only (of each line). Is there any way to do so? @Mat
    – blueDexter
    Apr 13, 2023 at 6:42
9
s/,/ /

This, by default (i.e. without the g option), replaces only the first match.

2
  • 1
    Is this actually Textpad search&replace syntax?
    – Daniel Beck
    Aug 1, 2012 at 21:54
  • 2
    This is a syntax of sed, perl and some other tools. Dec 2, 2013 at 20:57
3

This should match only the first number and the comma: ^(\d{5}),. If you'd like to gobble up everything else in the line, change the regex to this: ^(\d{5}),(.*)$

2
  • This also did the trick. I actually ended up using Mat's solution but I tested yours too and it works. Thanks for the help! Apr 5, 2011 at 7:18
  • Why \d{5} & not [^,]*? That would @ least be more generic.
    – JustinCB
    Jun 26, 2018 at 13:28
3

More elegant solution is to use lazy matching:

s/^(.+?),/\1 /

that will group characters by moving from start of the string (^) towards the end by one character (.+?) on each step untill it finds first comma sign. All this group along with the first comma occurence will be replaces by group (\1) and space character.

2
  • Note that this won't match a line that doesn't contain a comma (a single value on a line). Matching any * might be better than one + so s/^(.*?),/\1 / Sep 5, 2016 at 18:35
  • You could also do s/^([^,]*),/\1 /, which would match the start, anything not a comma, then a comma. Also, don't you know that s// doesn't change anything it doesn't match?
    – JustinCB
    Jun 26, 2018 at 13:27
2

To match only the first occurrence of any regex expression remove all flags. Each regex expression comes with the following possible flags and typically defaults to using the global flag which will match more than one occurrence:

  • /g = With this flag the search looks for all matches, without it – only the first match is returned
  • /i = case insensitive
  • /m = multi line mode
  • /s = all . to match newline character \n
  • /u = unicode
  • /y = sticky mode (search in specific location)
1

TextPad always had the ability to use posix notation, but you have to change the settings in a different dialog box. To use TextPad's default settings for regular expressions, you have to "escape" the opening and closing parentheses:

Replace space after 5-digit zip code, at the beginning of each line

^\([0-9]+\)[ ]

With tab

\1\t

As above, the ^ means start of line

\( is an "escaped parenthesis" and it marks the beginning of the first search expression, i.e., the five digits

[0-9]+ means one or more digits (not just 5-digit zip codes)

\) is another "escaped parenthesis" to mark the end of the first search expression

[ ] is just a space character (you could leave out the brackets, but then no one would be able to see it on this web page :-)

In the replacement expression

\1 is the first search expression, the part between parentheses above (one or more digits)

\t is a tab character

So the search and replace command looks for one or more digits, followed by a space. Then it replaces all that with the same group of digits followed by a tab.

I don't think there is any way simply to find "a space that comes after 5 digits" so you can just replace the space without touching the digits. You have to find the 5 digits (the first string) followed by the space (the second string). Then, although it seems redundant or cumbersome, REPLACE the original string of 5 digits with ITSELF, followed by the tab (the second string).

Everyone who knows this forgets that newbies have no idea about this. That's why I'm spelling it out for you, my friend.

Ed Poor Math Tutor and retired Computer Programmer New York City

0

Positive Lookbehind worked for me:

(?<=^[0-9]+),

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .