我正在尝试创建两个正则表达式来为字符串中的某些值添加引号。基本上字符串将是这样的:
999 date Doe, John E. London 123456789
我希望将名称包围起来,以便如果将此文件导出到csv,则不会将其分开。这就是我到目前为止所拥有的
$line =~ s/([^\s{2,}]*,[^\s{2,}]*)/"$1"/g;
我认为它应该找到任何逗号及其附近的任何内容,直到它找到两个或更多空格但它不起作用。谢谢你的帮助。
答案 0 :(得分:8)
您要求除 2个或更多空格外的任何内容。
我同意unpack
是更自然的方式。但split
是一种以图案形状使用千篇一律的方法。该模式中的任何不都是返回字段。所以这个:
@fields = split /\h{2,}/, $line;
$line = join(" " x 2 => map { "($_)" } @fields);
可能已经足够了。
答案 1 :(得分:2)
如果这是一个固定宽度的数据(我的猜测,那就是),最好使用unpack(或普通的旧substr等)而不是正则表达式。
答案 2 :(得分:1)
[]
包含一系列允许的字符,2空格不是字符。
也许:
$line =~ s/ (.*? .*?) / "\1" /g;
您可能需要更明确地确定格式以避免与''匹配。
$line =~ s/ (\w+?, [\w ]+?.) / "\1" /g;
为避免重复替换中的空格,可以使用环视断言,这也可以解决在行的开头和结尾处的项目问题:
$line =~ s/(?<=^| )(\w+?, [\w ]+?.)(?=$| )/"\1"/g;
还要注意原始格式 - 您确定它不仅仅是列对齐吗? (在这种情况下,足够长的名称或日期可能不允许列之间有2个以上的空格。)
答案 3 :(得分:1)
试试这个:
s/.* \K(.*),(.*?) /"$1,$2" /
逻辑上,这意味着:找到两个空格和逗号之间的子字符串,其中两个空格尽可能地靠近,然后是该逗号和两个空格之间的子字符串,其中子字符串尽可能短。< / p>
如果你正确地得到负向前瞻的语法,你的方法也可以工作。
答案 4 :(得分:1)
您提供的示例文本似乎是由制表符或空格分隔(列对齐?)。重要的是要知道哪个或正则表达式不起作用。了解模式在整个文件中是否一致也很重要。
如果按列对齐,最简单且最安全的方法是简单地计算字符数。 E.g:
s/(^.{20})(\S*) /$1"$2"/;
(你必须自己调整数字20。我只是近似了。)
请注意,我正在以鲁莽的方式砍掉名字字段末尾的两个空格。这是为了不搞砸以下值的格式。但是,如果字段填充到边缘,则最后可能没有两个空格,并且正则表达式将会丢失。但是,另一方面,无论如何,你都无法在那里得到引号。
在处理这些类型的文件时,我认为使用通用搜索并不安全。如果你指望逗号只出现在名字中,迟早你会发现有人认为“布朗克斯,纽约”应该在城市领域,并且你的正则表达式会被搞砸。
一个更严格但复杂的正则表达式将包括以前的字段:
$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"/;
同样的事情,如果名称字段不足以容纳两个引号,则不会添加它。您应该检查您的文件,看看是否是这种情况。如果是这种情况,您将需要以某种方式处理它。
我有时会发现将某些字段的正则表达式放在单独的变量中有助于提高易读性,例如上面的$ date。
祝你好运!