从配置文件中读取模式以替换匹配的出现,但 AWK 混乱并且 gsub 无法删除特殊字符和空格

问题描述 投票:0回答:2

我正在尝试替换

list_file1
中存储的许多模式,这些模式与
data_file1
的字段 2 中的类似数据匹配,然后从
data_file1
完全替换它。

data_file1
应匹配存储在
list_file1
中的大写、小写或大小写模式的组合。

存储在

list_file1
中的模式将包含前导空格、尾随空格和特殊字符。下面给出一些例子。

list_file1

AIM TO CONVERT 
 AIM TO CONVERT 
(FAILED)
( FAILED) 
\REOCCUR

data_file1

UR4289~Deal,( FAILED) Involved~ON654-L
PR4299~Invoc,(failed)closed~BG657-C
UR4980~ AIM TO CONVERT ,JUL51~NN655-V
UR4659~aim To convert -DISSOLVE~MV694-M

预期输出:

UR4289~Deal,Involved~ON654~L
PR4299~Invoc,closed~BG657~C
UR4980~,JUL51~NN655~V
UR4659~-DISSOLVE~MV694~M

到目前为止,Awk 脚本已经准备好了:

awk -F"~" 'NR==FNR{a[$0];next}{for (i in a) {if (index($2,i)) {gsub(tolower(i),"",$0)} {gsub(toupper(i),"",$0)}} print $0}' list_file1 data_file1 >> new_data1

我在这里缺少什么?

unix awk gsub string-substitution
2个回答
0
投票

您的代码存在几个问题:

  • index($2,i)
    区分大小写,
  • gsub(tolower(i),"",$0)
    替换整行而不只是字段 2,
  • gsub(tolower(i),"",$0)
    tolower(i)
    视为正则表达式,而不是文字字符串...

你可以尝试:

awk -F'~' -v OFS='~' 'NR == FNR {a[tolower($0)] = length($0); next}
{
  for(i in a) {
    while(p = index(tolower($2), i)) {
      $2 = substr($2, 1, p - 1) substr($2, p + a[i])
    }
  }
  print
}' list_file1 data_file1

注意:这将满足您的要求。但是,如果

list_file1
中的一个字符串是另一个字符串的子部分,则两个字符串中的第一个将首先被删除。示例:
AIM TO CONVERT 
(带有尾随空格)是
AIM TO CONVERT
(带有前导和尾随空格)的子字符串。如果首先列出
AIM TO CONVERT 
(如您的示例所示),
UR4980~ AIM TO CONVERT ,JUL51~NN655-V
将替换为
UR4980~ ,JUL51~NN655-V
。如果您希望前导空格也被删除,则必须首先在
AIM TO CONVERT
中列出
list_file1


0
投票

我在这里缺少什么?

gsub
的第一个参数被视为正则表达式并且

AIM TO CONVERT 
 AIM TO CONVERT 
(FAILED)
( FAILED) 
\REOCCUR

包含特殊含义的字符,例如括号里,请考虑

echo "ABLE BAKER CHARLIE" | awk -v drop="(B)" '{gsub(drop,"",$0);print $0}'

提供输出

ALE AKER CHARLIE

请注意,即使输入中根本没有括号,B 也被删除了。

我会使用 GNU

AWK
以下方式来解决这个问题,让
file1.txt
内容为

 Able
(Baker)

注意:Able 和

file2.txt
内容 be

之前有前导空格
Able~Able~Able # no change - no leading space
Able~ Able~Able # remove
Able~ ABLE~Able # different case remove
Baker~Baker~Baker  # no change - no brackets
Baker~(Baker)~Baker  # remove
(Baker)~Baker~(Baker)  # no change - field different than 2nd

然后

awk 'BEGIN{FS=OFS="~";IGNORECASE=1}FNR==NR{arr[gensub(/(.)/,"[\\1]","g")];next}{for(i in arr){gsub(i,"",$2)};print}' file1.txt file2.txt

提供输出

Able~Able~Able # no change - no leading space
Able~~Able # remove
Able~~Able # different case remove
Baker~Baker~Baker  # no change - no brackets
Baker~~Baker  # remove
(Baker)~Baker~(Baker)  # no change - field different than 2nd

说明:我告知 GNU

AWK
,波形符既是字段分隔符 (
FS
) 又是输出字段分隔符 (
OFS
),并且它应该以不区分大小写的方式工作 (IGNORECASE)。在处理第一个文件时,我使用
gensub
字符串函数
将每个字符括在方括号中,这对于没有特殊含义的字符来说并不是绝对必要的,但更容易包围每个字符,这样
(Baker)
将被转换为
[(][B][a][k][e][r][)]
。对于以下所有文件,我在第二个字段中使用
gsub
以及数组
arr
的每个键。观察到不需要使用
if
,如果不匹配则
gsub
不进行操作。

(在 GNU Awk 5.1.0 中测试)

© www.soinside.com 2019 - 2024. All rights reserved.