开发者

Regex to match anything but more than two spaces

I'm trying to create two a regex to add quotes to some values in a string. Basically the string would be like this:

999            date               Doe, John E.              London            123456789

And I want to surround the name so that if this file is exported to a csv, it won't be separated. This is what I have so far

$line =~ s/([^\s{2,}]*,[^\s{2,}]*)/"$1"/g;

I think it should fin开发者_如何学编程d any comma and anything near it until it finds two or more spaces but it's not working. Thanks for the help.


You asked for anything except 2 or more spaces.

I agree that unpack is the more natural way to do this. But split is a way to use a cookie-cutter in the shape of a pattern. Anything not in that pattern is a return field. So this:

@fields = split /\h{2,}/, $line;
$line = join(" " x 2 => map { "($_)" } @fields);

might be enough.


If this is a fixed-width data (and my guess, it is), better use unpack (or plain old substr,etc..) rather than regular expressions.


[] contain a range of characters that are allowed at that possible, 2-space isn't a character.

Maybe:

$line =~ s/  (.*? .*?)  /  "\1"  /g;

You'll probably need to be more explicit about the format to avoid matches against ' '.

$line =~ s/  (\w+?, [\w ]+?.)  /  "\1"  /g;

To avoid repeating the space in the replacement, look-around assertions could be used, which could also fix the issue of items at the beginning and end of the line:

$line =~ s/(?<=^|  )(\w+?, [\w ]+?.)(?=$|  )/"\1"/g;

Also be careful of your original format - are you sure it isn't just column aligned? (In which case a sufficiently long name or date might not allow 2+ spaces between columns).


Try this:

s/.*  \K(.*),(.*?)  /"$1,$2"  /

Logically, this means: Find a substring between two spaces and a comma, where the two spaces are as far right as possible, and then a substring between that comma and two spaces, where the substring is as short as possible.

Your approach can work too, if you get the syntax for negative lookaheads right.


The sample text you supplied seems to be separated either by tabs or spaces (column aligned?). It is important to know which, or the regexp will not work. It is also important to know whether the pattern is consistent throughout the file.

If it is aligned by columns, the easiest and probably safest way is to simply count off characters. E.g.:

s/(^.{20})(\S*)  /$1"$2"/;

(You will have to adjust the number 20 yourself. I just approximated.)

Note that I am chopping off two spaces at the end of the name field in a reckless manner. This is to not screw up the format for the following values. If however the field is filled to the brim, there might not be two spaces at the end, and the regexp will miss. But then, on the other hand, you would not be able to fit quotes there anyway.

When dealing with these types of files, I do not think it is safe to use generic searches. If you are counting on commas to only appear in the names, sooner or later you will find someone who thought that "Bronx, New York" should be in the city field, and your regexp will be screwed.

A somewhat more strict, but complicated regexp would include the previous fields:

$date='\d{2}-\d{2}-\d{2}'; # this might work for dates such as 11-10-23

s/^(\d+\s+$date\s+)(\S+)  /$1"$2"/;

Same thing here, if the name field is not big enough to fit two quotes, it won't be added. You should check your file and see if that is ever the case. If it is the case, you will need to deal with it somehow.

I sometimes find that putting certain field's regexps in separate variables helps with legibility, such as with $date above.

Good luck!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜