Chinaunix

标题: 如何忽略双引号中的分割符 [打印本页]

作者: cnmtchbgs    时间: 2011-01-04 14:31
标题: 如何忽略双引号中的分割符
有这么一个例子
ab:123,bc:"333,444",cd:456
用,作为分割符,分割出来希望得到是
ab:123
bc:"333,444"
cd:456
这样的效果,忽略双引号中间的分隔符。而不是
ab:123
bc:"333
444"
cd:456
请教各位大侠如何实现!
作者: ly5066113    时间: 2011-01-04 14:59
可以用 Text::CSV 吧。
作者: liyangole    时间: 2011-01-04 15:05
我用了很笨的方法。楼上的没有用过那个模块 ,下面是我的代码:
#!/usr/bin/perl -w
$str=qq/ab:123,bc:"333,444",cd:4r6/;
$str=~s/"(\d+?),(\d+?)"/"$12"/;
@a=split/,/,$str;
for $value (@a) {
  $value=~s/("[^"]+?)[^"]+?"/$1,$2/;
  print $value,"\n";
}
作者: cnmtchbgs    时间: 2011-01-04 15:18
楼上的方法也许能行,不过花脸太多,有碍阅读。
经过试验发现使用Text:arseWords这个模块,使用quotewords这个函数可以做到,代码如下:
use Text:arseWords;

$str1='ab:123,bc:"333,444",cd:456';

my @str=quotewords(",", 1, $str1);

其中quotewords函数,参数2中 1 代表不去除"号,如果改为零,代表去除引号。
作者: liyangole    时间: 2011-01-04 15:23
回复 4# cnmtchbgs


    ok,我试试这个模块。
作者: meihuaqi    时间: 2011-01-04 15:28
回复 1# cnmtchbgs
发现我也有点高手的范了{:3_183:}
  1. bsd# perl -e '$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+:(")?.*?(?(1)")(?=,|$)/g){print [        DISCUZ_CODE_0        ],"\n";}'
  2. ab:123
  3. bc:"333,444"
  4. cd:456
复制代码

作者: meihuaqi    时间: 2011-01-04 15:29

为啥 $& 会变成   DISCUZ_CODE_0
作者: liyangole    时间: 2011-01-04 15:35
安装了模块,试了,
作者: cnmtchbgs    时间: 2011-01-04 15:57
回复 6# meihuaqi


    我试过了,你的这串代码,跑不起来,报错如下:
'$)' is not recognized as an internal or external command,
作者: meihuaqi    时间: 2011-01-04 16:01
回复 9# cnmtchbgs
把   DISCUZ_CODE_0  换成$&, 还有就是拷贝的时候注意,没有回车的,那是一行代码
作者: meihuaqi    时间: 2011-01-04 16:01
把 [        DISCUZ_CODE_0        ] 换成 $&
作者: meihuaqi    时间: 2011-01-04 16:02
perl -e '$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+"?.*?(?(1)"(?=,|$)/g){print $&,"\n";}'
作者: meihuaqi    时间: 2011-01-04 16:03
perl -e '$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+:(")?.*?(?(1)")(?=,|$)/g){print $&,"\n";}'
作者: cnmtchbgs    时间: 2011-01-04 16:11
回复 13# meihuaqi


    不知道你调试过没有,我拿你这个最新的代码试验了一下,同样的错误。很奇怪的,难道跟操作系统有关,我在win vista下面测试的
作者: cnmtchbgs    时间: 2011-01-04 16:17
回复 13# meihuaqi


    放到perl脚本文件里面执行,结果是正确的,我研究一下这两者的区别。
作者: meihuaqi    时间: 2011-01-04 16:17
无奈了
把这行代码写到文件中执行
$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+:(")?.*?(?(1)")(?=,|$)/g){print $&,"\n";}
作者: cnmtchbgs    时间: 2011-01-04 16:19
回复 16# meihuaqi


    放在文件中执行是没有问题的,这个就有意思了
作者: liyangole    时间: 2011-01-04 16:24
回复 13# meihuaqi


    请详细介绍一下/\w+"?.*?(?(1)"(?=,|$)/g  谢谢
作者: cnmtchbgs    时间: 2011-01-04 16:38
回复 16# meihuaqi


    同上,我也不明白这句话的具体含义,只知道是非贪婪匹配。
作者: toniz    时间: 2011-01-04 17:49
貌似这个问题回答过很多相似的。。

perldoc -q "delimited string"
Found in /usr/lib/perl5/5.8.8/pod/perlfaq4.pod
       How can I split a [character] delimited string except when inside [character]?

       Several modules can handle this sort of pasing---Text::Balanced, Text::CSV, Text::CSV_XS, and
       Text:arseWords, among others.

       Take the example case of trying to split a string that is comma-separated into its different fields. You
       can't use "split(/,/)" because you shouldn't split if the comma is inside quotes.  For example, take a
       data line like this:

           SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped"

       Due to the restriction of the quotes, this is a fairly complex problem.  Thankfully, we have Jeffrey
       Friedl, author of Mastering Regular Expressions, to handle these for us.  He suggests (assuming your
       string is contained in $text):

            @new = ();
            push(@new, $+) while $text =~ m{
                "([^\"\\]*(?:\\.[^\"\\]*)*)",?  # groups the phrase inside the quotes
              | ([^,]+),?
              | ,
            }gx;
            push(@new, undef) if substr($text,-1,1) eq ',';

       If you want to represent quotation marks inside a quotation-mark-delimited field, escape them with back-
       slashes (eg, "like \"this\"".

       Alternatively, the Text:arseWords module (part of the standard Perl distribution) lets you say:

           use Text:arseWords;
           @new = quotewords(",", 0, $text);

       There's also a Text::CSV (Comma-Separated Values) module on CPAN.

作者: toniz    时间: 2011-01-04 17:50
禁用掉SMILES之后还有笑脸,郁闷。
作者: cnmtchbgs    时间: 2011-01-04 18:17
回复 16# meihuaqi


    果然是高,$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+"?.*?(?(1)"(?=,|$)/g){print $&,"\n";}这句话我研究了很久也没搞明白,特别是(?(1)"是什么意思,请指教!
作者: cnmtchbgs    时间: 2011-01-04 18:17
回复 16# meihuaqi
  1.     果然是高,$_= "ab:123,bc:\"333,444\",cd:456"; while(/\w+:(")?.*?(?(1)")(?=,|$)/g){print $&,"\n";}这句话我研究了很久也没搞明白,特别是(?(1)")是什么意思,请指教!
复制代码

作者: meihuaqi    时间: 2011-01-04 18:55
模糊的记得这个东西的学名叫 正则条件
作者: cnmtchbgs    时间: 2011-01-04 20:24
(?(1)")用于判断成对出现的匹配
作者: liyangole    时间: 2011-01-05 12:59
回复 25# cnmtchbgs


    这个是正解了,我昨天研究了一下,有了头绪。非贪婪匹配,然后(?=,|$)向前断言。确定匹配位置。值得学习借鉴了。
作者: wxlfh    时间: 2011-01-05 14:48
强烈建议使用Text::CSV模块。不要重复别人已经解决得很好的事情了。

另,用正则或者split操作符来解析CSV(就是以逗号分隔的文件)文件,实在是一件很痛苦的事情。
作者: iLRainyday    时间: 2011-02-02 22:48
我这个是不是有点傻??
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. my $string = q{ab:123,bc:"333,444",cd:456};
  5. my @elements = split /(?<="),|(?<=\d),(?=[a-z])/, $string;

  6. local $" = "\n";
  7. print "@elements";
复制代码

作者: bernana    时间: 2011-02-09 10:59
回复  cnmtchbgs


    这个是正解了,我昨天研究了一下,有了头绪。非贪婪匹配,然后(?=,|$)向前断 ...
liyangole 发表于 2011-01-05 12:59



    问下?=和?<=有什么区别呀?
作者: justlooks    时间: 2011-02-09 13:33

  1. $ echo 'ab:123,bc:"333,444",cd:456'|perl -ne 's/(,)(\w+:)/\n\2/g;print'
  2. ab:123
  3. bc:"333,444"
  4. cd:456
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2