安全地运行几个字符串替换

时间:2018-01-29 21:23:27

标签: text awk gawk

我必须在文本文件上运行许多替换,并且我需要区分已经用相同字符串写入的字符串(如果它原来在那里)。

例如,假设我要将a替换为b,将b替换为以下文件的第二个字段中的c(以获取b c c })

a a
a b
b c

如果我明确地运行awk '$2 == "a" {$2 = "b"}; $2 == "b" {$2 = "c"} 1' file

a c
a c
b c

我可以注意我在这里进行替换的顺序,但实际上不是真实情况。我希望有一个灵活的脚本,我可以按任何顺序编写替换,而不必担心值被覆盖。我已经尝试过乐观的awk '$2 == "a" {$2 = b}; $2 == "b" {$2 = c}; b = "b"; c = "c"; 1' file,但它没有用。

2 个答案:

答案 0 :(得分:2)

由于您只想最多执行一次替换,因此您最好使用if ... else if ...

awk '{
    if      ($2 == "a") {$2 = "b"}
    else if ($2 == "b") {$2 = "c"}
    else if ($2 == "c") {$2 = "a"}
    print
}' <<END
a a
a b
b c
END
a b
a c
b a

根据您的风格格式化代码。

另一种可能更优雅的方法:

awk '
    BEGIN {repl["a"] = "b"; repl["b"] = "c"; repl["c"] = "a"}
    $2 in repl {$2 = repl[$2]}
    1
' <<END
a a
a b
b c
END

答案 1 :(得分:2)

不更改刚刚更改的字符串的一般惯用方法是将旧值映射到输入中不会出现的字符串,然后将这些字符串转换为新值:

$ cat tst.awk
BEGIN {
    old2new["a"] = "b"
    old2new["b"] = "c"
}
{
    # Step 1 - put an "X" after every "@" so "@<anything else>"
    # cannot exist in the input from this point on.
    gsub(/@/,"@X",$2)

    # Step 2 - map "old"s to intermediate strings that cannot exist
    c=0
    for (old in old2new) {
        gsub(old,"@"c++,$2)
    }

    # Step 3 - map the intermediate strings to the new strings
    c=0
    for (old in old2new) {
        gsub("@"c++,old2new[old],$2)
    }

    # Step 4 - restore the "@X"s to "@"s
    gsub(/@X/,"@",$2)

    # Step 5 - print the record
    print
}

$ awk -f tst.awk file
a b
a c
b c

我使用gsub()这是最常见的应用程序,但如果您的情况更适合if,请随时使用c++

显然,只在@末尾添加联接mask = df['P/E'] <= df['P/E'].quantile(0.1) df.loc[mask, 'pe_cond'] = 1 df.loc[~mask, 'pe_cond'] = 0 的方法仅适用于最多10次替换,您必须提供到其他字符的映射超过那个(这是微不足道的,但不会超过RE元字符)。