3

我一直在使用 sep 来尝试这个,基本上我有一个文本文件,其中包含合理数量的同一行,例如

4444 username "some information" "someotherinformation" "even more information"

我需要用下划线替换引号内的空格,所以它看起来像这样

4444 username "some_information" "someotherinformation" "even_more_information"

目前我已经能够分离出引用的信息

sed 's/"\([^"]*\)"/_/g' myfile.txt

关于如何进行的建议?

4

4 回答 4

6
sed -r ':a; s/^((([^"]*"){2})*[^"]*"[^" ]*) /\1_/;ta'
4444 username "some_information" "someotherinformation" "even_more_information"

或者

sed ':a; s/^\(\(\([^"]*"\)\{2\}\)*[^"]*"[^" ]*\) /\1_/;ta'
4444 username "some_information" "someotherinformation" "even_more_information"
  • :a- 为循环标记“a”
  • s///- 执行替换
  • ^(- 将整个搜索字符串锚定在行首
  • (([^"]*"){2})*- 捕获(在第 1 组中)两组零个或多个非引号,后跟一个引号(零次或多次)
  • [^"]*"- 后跟零个或多个非引号,后跟一个引号
  • [^" ]*- 后跟零个或多个不是空格或引号的字符
  • )- 结束锚定序列并寻找需要替换的空间
  • \1- 将捕获的组和下划线替换为匹配的序列
  • ta- 分支(转移执行)标记:a是否成功替换(如果没有成功,则继续执行下一条指令 - 在这种情况下,该指令结束这一行的处理并读取下一条,开始新一轮的处理)

这会在最后一个带引号的字符串中找到第一个空格并替换它。然后下一个,如果有的话,直到引用的字符串完成。等等任何额外的空间。

然后下一个包含空格的先前引用的字符串......等等。

:a这就是模式空间在...ta循环的每一步中的样子:

4444 username "some information" "someotherinformation" "even_more information"

4444 username "some information" "someotherinformation" "even_more_information"

4444 username "some_information" "someotherinformation" "even_more_information"

然后它会多走几次以查找行首的任何匹配项。

于 2012-05-24T00:47:59.810 回答
3

已编辑

以前的版本会添加不需要的空格。这个版本完全符合 OP 的要求。

这可能是得到你想要的最简单的方法。

awk -F'"' '
  BEGIN {
    OFS="\""
  }
  {
    for (i = 2; i < NF; i += 2) {
      gsub(/[ \t]+/, "_", $i)
    }

    print $0
  }
' file > outputFile
于 2012-05-23T23:53:47.493 回答
1

这可能对您有用:

echo '4444 username "some information" "someotherinformation" "even more information"' |
sed 's/"[^"]*"/\n&/g;:a;s/\(\n"[^"]*\) /\1_/g;ta;s/\n//g'
4444 username "some_information" "someotherinformation" "even_more_information"
  • 将标记 ( \n) 添加到引用的字符串。sed 's/"[^"]*"/\n&/g;
  • 用 .替换引用字符串中的所有空格_:a;s/\(\n"[^"]*\) /\1_/g;ta
  • 删除标记。s/\n//g
于 2012-05-24T08:07:03.143 回答
0

我实际上会在 C 中执行此操作,这使得执行逐字符状态机比大多数高级语言更容易。

#include <stdio.h>
int main(void)
{
    int inside_quotes = 0;
    int backslash = 0;
    int c;
    while ((c = getchar()) != EOF) {
        switch (c) {
        case ' ':
            if (inside_quotes)
                c = '_';
            break;
        case '"':
            if (!backslash)
                inside_quotes = !inside_quotes;
            break;
        case '\\':
            if (!backslash)
                backslash = 2;
            break;
        default:
            break;
        }
        if (backslash > 0) backslash--;
        putchar(c);
    }
    return 0;
}

未经测试甚至编译。特别是反斜杠处理很可能是错误的。

于 2012-05-24T00:01:06.490 回答