在VIM中查找并将逗号分隔的字符串替换为Cassandra列表格式

时间:2013-08-09 22:40:36

标签: regex list vim replace cassandra

我想转换""引用的所有以逗号分隔的字符串,如下所示:

"hello,world,stack,overflow"

使用VIM进入以下Cassandra list format

"['hello','world','stack','overflow']"

其中每个元素都被''包围,整个原始字符串被"[]"包围。我可以知道如何在VIM中进行操作吗?

在我的输入中,""引用的逗号分隔字符串是csv格式化行的一部分。以下是一个例子:

other,fields,123,456,"hello,world,stack,overflow"
second,row,567,890,"another,comma,separated,string"
...

我希望将其转换为:

other,fields,123,456,"['hello','world','stack','overflow']"
second,row,567,890,"['another','comma','separated','string']"
...

我的每个目标字符串都不会跨越多行。

2 个答案:

答案 0 :(得分:5)

试试这个

:%s/\v(".*)@<=\s*([^,"]+)\s*(.*")@=/'\2'/g
:%s/"/"[
:%s/"\[\@!/]"

或者一下子

:%s/\v(".*)@<=\s*([^,"]+)\s*(.*")@=/'\2'/ge | %s/"/"[/e | %s/"\[\@!/]"

这适用于该示例。如果该行上有多对引号,则无效。

解释

:%s/\v(".*)@<=\s*([^,"]+)\s*(.*")@=/'\2'/g

这会查找一个字符串,该字符串在其前后都有一个带有lookaheads和lookbehinds的引号。然后我们捕获所有不是逗号或引号的内容,并用单引号中的捕获部分替换它。这会抛出任何前导或尾随空格。

:%s/"/"[

如果您在

之前使用过:s,那么这应该是自我解释的
:%s/"\[\@!/]"

这使用负前瞻来查找第一个引号,后面没有左括号,并用右括号和引号替换它。


在考虑了这一点之后,我认为你可以一次性完成整个文件,不管天气如何都有一对以上的报价。

第一个函数只是一个辅助函数,它使得替换命令更容易输入。 (你可以在一行中完成三个替代命令,但这样做会很难看)。它与上面的内容完全相同。

function! ReplaceCommaSeperated(string)
    let l:tmp = substitute(a:string, '[^,"]\+', "'\\0'", 'g')
    let l:tmp = substitute(l:tmp, '"', '"[', '')
    return substitute(l:tmp, '"\[\@!', ']"', '')
endfunction

function! RunCommaReplace()
    %s/".\{-}"/\=ReplaceCommaSeperated(submatch(0))/g 
endfunction

第二个函数查找所有引用的字符串并将其传递给函数,并立即替换它。你知道哪一个是开头和结尾的引号,因为保证只有一对引号。

这种方法起作用并且正则表达式解析器不会混淆的原因是模式匹配在第一次匹配结束后开始。所以如果你有字符串" A " B " C "
 " A "将是第一个匹配,而" C "将是第二个匹配,因为当解析器在B之后尝试匹配时,它会看到B " C "且不匹配。

要在你的vim中运行它,只需将两个函数复制到你的vimrc中。在要运行的文件中,运行以下命令。

:call RunCommaReplace()

答案 1 :(得分:1)

很有可能在一次运行中解决问题 :substitute命令。我可以看到两个略有不同的实现 这种方法。它们都遵循相同的模式 用表达式替换:

:%s/"\([^"]*\)"/\='"['.Q.']"'/g

根据上面的命令,所有零个或多个字符的序列 用双引号括起来取代评价结果 在\=符号后指定的表达式(请参阅 :help sub-replace-\=)。什么与周围的连接 替换表达式Q中的括号和引号代表a 表达式转换以逗号分隔的列表的文本 模式的(仅)子匹配,与相同列表的字符串 用单引号括起来的元素。表达式的两个版本 Q如下。

第一个版本很简单:

  1. 使用逗号将匹配的文本分解为元素列表 作为分隔符:

    split(submatch(1), ',', 1)
    

    (最后一个参数在这里是可选的,只有当时才需要 空元素可以在开头或结尾处 双引号字段。)

  2. 用引号括起来:

    map(‹…›, '"''".v:val."''"')
    
  3. 并将它们连接起来,以便与...交替 分隔逗号:

    join(‹…›, ',')
    
  4. 将所有步骤组合在一起,我们获得表达式

    join(map(split(submatch(1), ',', 1), '"''".v:val."''"'), ',')
    

    第二个,表达式Q的表现更为高效的版本不是 更复杂;它只是一个替代品(里面的 替换,因为Q:s命令中。我们支配 我们有substitute()函数,其功效相当于 同名的命令。

    表达式

    substitute(submatch(1), '[^,]\+', "'&'", 'g')
    

    会导致所有非空字符序列出现 包含逗号,并附加单引号 在两端。

    如果我们希望这个表达式也处理空列表项(作为第一个 我们需要做的就是将最后一个模式更改为

    '\%(^\|,\)\zs[^,]*'
    

    这样,它也允许空序列,但受限制 它们要么在开头,要么在逗号之后。 (看到 :help \zs:help \%(可以更好地了解更改后的模式 工作的。)

    因此,我们有以下两个命令。

    :%s/"\([^"]*\)"/\='"['.join(map(split(submatch(1),',',1),'"''".v:val."''"'),',').']"'/g
    

    :%s/"\([^"]*\)"/\='"['.substitute(submatch(1),'\%(^\|,\)\zs[^,]*',"'&'",'g').']"'/g
    

    它们都适用于一行上的所有引用字段。