仅删除双引号中出现的逗号


10

在文本文件中,我要删除,(逗号)以及"(引号)(仅当双引号包含以逗号分隔的数字时)。

56,72,"12,34,54",x,y,"foo,a,b,bar"

预期产量

56,72,123454,x,y,"foo,a,b,bar"

注意:我仅以示例的方式显示上述行。我的文本文件包含很多行,如上,双引号中用逗号分隔的数字应有所不同。那是,

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

预期产量:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

n在双引号中有许多数字,用逗号分隔。并且还要保留包含字符的双引号。

我喜欢sed文字处理工具。如果您sed对此提出任何解决方案,我感到很高兴。


56,72,"12,34,54",x,y,"foo,a,b,bar"56,72,123454,x,y,"a,b"foo然后bar消失。是您想要的输出吗?
cuonglm

您使用的示例有些混乱,因为某些元素(如foobar)与逗号一起被删除了。此外,某些报价消失在其他报价中。更不要说a和之间的逗号也b保持不变。这些有什么模式吗?
HalosGhost 2014年

编辑对不起朋友。
阿维纳什·拉吉

您所做的修改尚未真正弄清您的示例。请看我的最后评论
HalosGhost 2014年

删除双引号内的所有逗号以及仅在引号包含数字的情况下才删除引号。
阿维纳什·拉吉

Answers:


7

尽管@rici的Perl一个简单得多,但这(从此处改编)应该可以满足您的需要:

$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;ta; s/""/","/g; 
          s/"([0-9]*)",?/\1,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

说明

  • :a:定义一个名为的标签a
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/ :这一个需要细分
    • 首先,采用这种结构:(foo(bar))\1foobar\2bar
    • "[0-9,]*",?:匹配0以上的0-9,,随后0或1 ,
    • ("[0-9,]*",?)* :匹配以上0个或多个。
    • "[0-9,]*:匹配0个或多个,0-9或者,紧跟在"
  • ta;:返回标签a如果替换成功,再次运行。
  • s/""/","/g;: 后期处理。替换""","
  • s/"([0-9]*)",?/\1,/g :删除数字周围的所有引号。

通过另一个示例可能更容易理解:

$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"

因此,尽管您可以在引号后找到一个数字,然后是逗号和另一个数字,但是将两个数字连接在一起并重复此过程,直到不再可行。

在这一点上,我认为info sed在描述高级功能的部分(如上面使用的标签)中出现引号是很有用的(感谢发现@Braiam):

在大多数情况下,使用这些命令表明您可能会更喜欢使用“ awk”或Perl之类的程序进行编程。


10

如果perl可以,这是一种简短的方法(可能很快速,如果不一定简单的话:)):

perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file

运算符的e标志s:::(这只是另一种写法s///)使得替换被视为每次都会求值的表达式。该表达式$1从正则表达式(已经缺少引号)中捕获并通过删除()所有逗号y///来转换(,也可以写成tr///)它/d。在r以标志y是必要的,以便获得的价值是翻译的字符串,而不是翻译的数量。

对于那些因某种原因而对perl感到沮丧的人,这里是python等效项。Python确实不是Shell一线工具,但是有时可以哄骗它进行协作。以下内容可以写成一行(不同于for循环,不能这样),但是水平滚动使其(甚至更多)无法读取:

python -c '
import re;
import sys;
r=re.compile("\"(\d+(,\d+)*)\"");
all(not sys.stdout.write(r.sub(lambda m:m.group(1).replace(",",""),l))
    for l in sys.stdin)
' < file

@rici:好一个!并使用y///而不是tr///再给我们节省一个角色。
cuonglm

6

对于CSV数据,我将使用具有实际CSV解析器的语言。例如使用Ruby:

ruby -rcsv -pe '
  row = CSV::parse_line($_).map {|e| e.delete!(",") if e =~ /^[\d,]+$/; e} 
  $_  = CSV::generate_line(row)
' <<END
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
END
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

0

块引用

嗨,这是用双引号替换逗号的Python代码,逗号用竖线(|)替换

该Python代码将替换双引号中的逗号

例如:x,y,z,1,2,“ r,e,t,y”,h,8,5,6

如果替换为管道x,y,z,1,2,“ r | e | t | y”,h,8,5,6

如果替换为null x,y,z,1,2,“ rety”,h,8,5,6

writingFile = open('FileToWrite', 'w')
with open('FileToRead') as f:

    while True:

        c = f.read(1)
        if not c:
            print ("End of file")
            break
        print ("Read a character:", c)


        if c=='"':
            writingFile.write(c) 
            c = f.read(1)
            while c != '"':
                if c== ',':
                    c= '|'
                writingFile.write(c)
                c = f.read(1)


        writingFile.write(c)


writingFile.close()

几乎不需要解释。
Mongrel,2013年

此python代码用于替换双引号中的内容
Vijay Kumar Akarapu,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.