awk - 如何在awk中简单地将这个字符串解析为kv

标签 awk

现在我在 awk 中有一个这样的 str:

str = "a='abc',b=1,c='http://xxxx,http://yyyy,http://zzz'"

如何解析它以获得此结果:

(a abc)(b 1)(c http://xxxx,http://yyyy,http://zzz)

现在我仍然以如此丑陋的方式实现它:

result = ""
while (match(str, /[^=]*=('[^']*'|[^,]*),/) != 0) {
    subs = substr(str, RSTART, RLENGTH)
    str = substr(str, RSTART + RLENGTH, length(str) - RSTART - RLENGTH + 1)
    split(subs, vec, "=")
    gsub(/'/, "", vec[1])
    gsub(/'/, "", vec[2])
    if (substr(vec[2], length(vec[2]), 1) == ",") {
        vec[2] = substr(vec[2], 0, length(vec[2]) - 1)
    }
    result = result"("vec[1]" "vec[2]")"
}

我想知道是否存在一些更优雅的方式。

最佳答案

使用 awk

这里的技巧是我们需要以不同的方式对待带引号的逗号和不带引号的逗号。可以按如下方式完成:

$ echo "$str" | awk -F"'" -v OFS="" '{for (i=1;i<=NF;i+=2) gsub(",", ")(", $i)} {gsub("=", " "); print "("$0")"}' 
(a abc)(b 1)(c http://xxxx,http://yyyy,http://zzz)

它是如何工作的

  • -F"'" -v OFS=""

    这将输入字段分隔符设置为单引号,并将输出分隔符设置为空字符串。

  • {for (i=1;i<=NF;i+=2) gsub(",", ")(", $i)}

    这会将不带引号的逗号(奇数​​字段)替换为 )( .

    偶数字段代表引用的字符串,它们在这里保持不变。

  • gsub("=", " ")

    这用空格替换等号。

  • print "("$0")"

    这会在开头和结尾添加括号并打印该行。

使用 sed

$ echo "$str" | sed -r ":a; s/^(([^']*'[^']*')*[^']*'[^,']*),/\1\n/; ta; s/,/)(/g; s/^/(/; s/$/)/; s/\n/,/g; s/'//g; s/=/ /g" 
(a abc)(b 1)(c http://xxxx,http://yyyy,http://zzz)

它是如何工作的

首先,请记住 sed 逐行处理输入。这意味着,除非我们在其中放入一个换行符,否则 sed 模式空间中的任何行都不会包含换行符。

此命令的工作原理是将所有引用的逗号替换为换行符。然后添加 (到行首,)到行尾,并将剩余的逗号替换为 )( 。换行符更改回逗号。接下来,单引号被删除。最后,=然后将符号替换为空格,我们就完成了。

我们可以通过逗号前面是否有奇数个或偶数个单引号来判断逗号是否被引号引起来。

更详细:

  • sed -r

    这会使用扩展正则表达式启动 sed。

  • :a; s/^(([^']*'[^']*')*[^']*'[^,']*),/\1\n/; ta

    这会将所有带引号的逗号转换为换行符。正则表达式 ^(([^']*'[^']*')*[^']*'[^,']*)从行首开始匹配任何奇数个单引号及其周围的文本,直到第一个逗号为止。替换命令s/^(([^']*'[^']*')*[^']*'[^']*),/\1\n/因此用换行符 \n 替换找到的第一个引号逗号。 .

    :a是一个标签。 ta是一个测试:它分支回标签 a如果进行了替换。因此,可以根据需要进行多次替换,以将所有带引号的逗号替换为换行符。

  • s/,/)(/g; s/^/(/; s/$/)/

    这三个替换命令将括号放在我们想要的任何地方。

  • s/\n/,/g

    现在我们在需要的地方有了括号,这会将我们添加回的换行符转换为逗号。

  • s/'//g

    这会删除所有单引号。

  • s/=/ /g

    这将用空格替换等号。

关于awk - 如何在awk中简单地将这个字符串解析为kv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30586764/

相关文章:

Bash - 仅使用 awk 打印矩阵的某些部分

awk - 如果条件匹配附加到行

linux - awk 查找两个字符串之间的第二条记录/awk 在文件中搜索

linux - 如何在 linux 中用另一行替换行

linux - 如何在包含模式 [ :alpha:], 的任何行之前添加字符串 "<fc=ff00>"但不添加两个连续行?

regex - 用注释替换字符串的特定出现

java - 从多个文本文件中提取特定行

regex - 如何到达文本文件的特定部分然后搜索

regex - AWK 匹配以数字开头的字符串

使用 Awk 的 Hadoop 示例 map reduce 程序