提问人:Sam 提问时间:11/14/2023 最后编辑:Arvind Kumar AvinashSam 更新时间:11/16/2023 访问量:136
将整列替换为所有多行中的新值
Replace whole column with a new value in all multiple lines
问:
我的文件中有以下几行
$ cat test.txt
69|1074330570|1,sip:+121345633210x3Bverstat=TN-Validation-Passed|tel:+12134565534|0
69|1077822111|2,;tel:+2223120011~sip:[email protected];|sip:[email protected]|0
69|1077988012|1,sip:+121510016070x3Bverstat=TN-Validation-Passed|tel:+136965339510x3Bnpd|0
我想将文件中的第三列和第四列替换为电话号码,如下所示:
69|1074330570|2134563321|2134565534|0
69|1077822111|2223120011|3123120022|0
69|1077988012|2151001607|3696533951|0
好的部分是所有文件在第三列和第四列中都有一个“+”。现在困难的部分是,有时我们会得到 11 位数字,如第一行第三列 (121345633210) 中所注意到的那样,有时在“+”之后没有添加“1”。因此,如果加号后有 1,则排除 1。否则,请在“+”号之后开始长度。同样,如果有 11 位数字,则只需子字符串 10。此外,如果像第 2 行这样的数字超过 1 个,我需要像 2223120011 而不是 2223120051一样选择“+”号后面的第一个数字。
我尝试了以下方法
awk -F"|" 'BEGIN {FS="+"}{print substr($3,2,10)}' test.txt
但它为第二行提供了不正确的值,因为它需要在“+”号之后开始。
答:
4赞
markp-fuso
11/14/2023
#1
当前代码的问题:
-F"|"
两者都定义了输入字段分隔符,因此,从技术上讲,您应该选择一个或另一个,但不能同时选择两者;在这种情况下优先(即被忽略)FS="+"
FS="+"
-F"|"
- 由于总体要求是“替换”第 3 列和第 4 列,因此您需要保留 ,但也将其定义为输出字段分隔符(建议:
-F"|"
BEGIN { FS=OFS="|"}
- 然后考虑使用字符串函数的某种组合(例如、、、、
awk
split()
match()
index()
substr()
)
假设/理解:
- 第 3/4 个字段始终具有
+
- 后面的字符串始终是 10 位或 11 位数字
+
- 如果第 3/4 个字段有多个字段,那么我们只对第一个字段感兴趣(例如,我们不必根据 或
+
+
tel
sip
) - 看来我们正在处理北美电话号码格式(例如,我们不必担心其他国家/地区的不同电话号码格式)
一个想法:awk
awk '
BEGIN { FS=OFS="|" }
{ for (i=3; i<=4; i++) { # loop through 3rd and 4th fields
split($i,a,"+") # split on "+"
d1 = substr(a[2],1,1) # get 1st digit after the "+"
$i = substr(a[2],(d1==1 ? 2 : 1),10) # redefine ith field based on value of 1st digit
}
}
1 # print current line
' test.txt
笔记:
- 此逻辑是基于我们只需要处理北美电话号码格式(10 位/11 位,国家/地区代码 = 1)的假设进行硬编码的
这将生成:
69|1074330570|2134563321|2134565534|0
69|1077822111|2223120011|3123120022|0
69|1077988012|2151001607|3696533951|0
5赞
anubhava
11/14/2023
#2
您可以使用以下解决方案:awk
awk '
function extphone(s) {
sub(/^[^+]*\+1?/, "", s) # remove all text before + then + and optional 1
return substr(s, 1, 10) # extract first 10 characters now
}
BEGIN {FS=OFS="|"}
{
$3 = extphone($3)
$4 = extphone($4)
} 1' file
69|1074330570|2134563321|2134565534|0
69|1077822111|2223120011|3123120022|0
69|1077988012|2151001607|3696533951|0
3赞
Ed Morton
11/14/2023
#3
使用 GNU awk 用于:gensub()
$ awk '
BEGIN { FS=OFS="|" }
{
for ( i=3; i<=4; i++ ) {
$i = gensub(/[^+]+\+1?([0-9]{10}).*/,"\\1",1,$i)
}
print
}
' test.txt
69|1074330570|2134563321|2134565534|0
69|1077822111|2223120011|3123120022|0
69|1077988012|2151001607|3696533951|0
或使用任何 awk:
$ awk '
BEGIN { FS=OFS="|" }
{
for ( i=3; i<=4; i++ ) {
if ( match($i,/\+1?[0-9]{10}/) ) {
$i = substr($i,RSTART+RLENGTH-10,10)
}
}
print
}
' test.txt
69|1074330570|2134563321|2134565534|0
69|1077822111|2223120011|3123120022|0
69|1077988012|2151001607|3696533951|0
2赞
RavinderSingh13
11/15/2023
#4
对于您展示的示例,请尝试以下 GNU 代码。awk
awk '
match($0,/^([^|]*\|[^|]*\|)[^+]*\+1*([0-9]+)[^|]*(\|)[^+]*\+1*([0-9]+)[^|]*(\|.*$)/,arr){
sub(/0$/,"",arr[2])
sub(/0$/,"",arr[4])
print arr[1] arr[2] arr[3] arr[4] arr[5]
}
' Input_file
解释:为上述代码添加详细说明。
- 使用 GNU 的函数在其中使用正则表达式,这会创建捕获组,稍后我们可以使用这些来获取所需的输出。
awk
match
- 使用正则表达式 inside 函数。
^([^|]*\|[^|]*\|)[^+]*\+1*([0-9]+)[^|]*(\|)[^+]*\+1*([0-9]+)[^|]*(\|.*$)
match
- 如果找到正则表达式匹配项,则使用 此处 删除第 2 个和第 4 个捕获组的最后部分。
0
sub
- 然后打印所有 5 个捕获组以获得所需的输出。
评论