我有一个类似值的表格,不幸的是格式不同(不在我的控制范围内),而且我只想要那些$ 1和$ 2完全不同的行。我关注的两个主要问题是:
1)我没有运气
awk '$1 !~ /$2/' filename
甚至部分完成这项任务;它产生一个空集。我感觉这是我写/ $ 2 /部分的方式,但是找不到不会产生空集或错误的格式。
2)整个电路板的格式差异并不相同。以下是输入的示例:
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
我只想返回具有明显不同值的行,如下所示:
Q012345 D666666
q12345 23588
一条希望似乎是,如果字母有时会忽略前面的0,那么每对列都有相同的数字序列。任何帮助,将不胜感激。如果它有帮助,那就是korn shell。
更新:我看到我犯了一个常见的错误,就是假设每个人都知道我在说什么,没有充分的理由。通过“明显不同”,我的意思是前面0的值中的数字是不同的。输入后,我意识到这些字母对于我对此数据执行的特定任务实际上毫无意义。所以q12345和12345对于我的目的是相同的,012345和12345是相同的,但12345和78945不是,也不是12345和12346。
既然我输入了这个,那么只有一种简单的方法可以只返回每列中的数字,这样才能比较数字吗?这样,前面的零将毫无意义(012345 = 12345),我会得到我想要的东西。抱歉有任何困惑。
答案 0 :(得分:1)
如果模式包含在变量中,请不要使用斜杠 - 使用斜杠来包含静态正则表达式。你想要
awk 'tolower($1) !~ tolower($2)' filename
使用tolower
启用不区分大小写的匹配。或者,如果您使用的是GNU awk:
gawk -v IGNORECASE=1 '$1 !~ $2' filename
答案 1 :(得分:0)
嗯,这确实取决于你对'完全不同'的意思。我的意思是,你可以通过以下方式前进和后退子串匹配:
#!/usr/bin/env perl
use strict;
use warnings;
while ( <DATA> ) {
my ( $first, $second ) = split;
print unless ($first =~ /$second/i or $second =~ /$first/i);
}
__DATA__
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
哪会给你:
Q012345 D66666
q12345 23588
这个单行 - 如果:
perl -lane 'print unless ( $F[0] =~ /$F[1]/ or $F[1] =~ /$F[0]/ )'
或者你可以根据'Levenshtein距离'来做到这一点:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Levenshtein qw(distance);;
while ( <DATA> ) {
my ( $first, $second ) = split;
print unless distance ( $first, $second ) < 3;
}
__DATA__
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
注 - Q012345 - &gt; 12345是Levenshtein距离2,因此您可以调整相似度。
注意 - 我知道您已标记awk
并询问korn
shell。我给了perl
,因为当“korn”或“awk”都是时,通常。
您可以替换上面的__DATA__
,这对于创建自包含示例非常有用:
while ( <> ) {
my ( $first, $second ) = split;
#etc .
}
<>
是神奇的文件句柄,就像你期望的那样工作grep,sed或awk - 读取stdin或命令行中指定的文件,这样你就可以:
cat somefile | script.pl
或
script.pl somefile
在任何一种情况下它都会做正确的事。
答案 2 :(得分:0)
鉴于修改后的描述,这似乎完成了工作(示例数据位于我的机器上名为data
的文件中),但我承认可能有更紧凑的方法来实现相同的结果:
$ awk 'substr($1, match($1, /[0-9]+/)) +0 != substr($2, match($2, /[0-9]+/)) + 0 { print }' data
Q012345 D66666
q12345 23588
$
为POSIX awk
定义了match
和substr
函数。 match
函数返回第一个参数中正则表达式开头的偏移量,因此它返回$1
或$2
中第一个数字的索引。 substr
返回从该位置开始的字符串。 + 0
确保以数字方式处理值(因此忽略前导零) - 如果没有,则报告Q012345 12345
行。
在Mac上测试(macOS Sierra 10.12.13,原生(BSD)awk
和GNU awk
)。
我认为我遇到了类似于下面另一张海报答案的情况,我可能会对Awk有一些奇怪/旧的实现。代码一直返回非法语句错误。此版本的Awk没有
match
...
这只适用于sub
函数,该函数将正则表达式应用于变量并替换匹配的内容,在本例中为空字符串,从而删除字段开头的非数字(或,如果开头有数字,但后面有非数字,它会删除那些;天堂会帮助你,如果你有一个字段1234-5678-99
,因为你最终会将12345678与另一个字段进行比较)。还有gsub
,它会反复应用搜索和替换。
$ awk '{ v1 = $1; sub(/^[^0-9]*/, "", v1); v2 = $2; sub(/^[^0-9]*/, "", v2); if (v1 + 0 != v2 + 0) print }' data
Q012345 D66666
q12345 23588
$
如果您还没有sub
或gsub
,那么(a)请确定平台 - o / s和版本 - 以及Awk的版本,以及(b)请获取并安装GNU Awk所以你没有这样的未来。如果这是一个问题,请提供您所拥有的Awk版本的在线文档的链接,并且很可能是另一种解决方案。
如果您使用的是Solaris,请尝试nawk
(新的Awk)而不是oawk
(旧的Awk) - 其中awk
可能是指向oawk
或{的链接{1}}。如果这是问题,请重新调整系统以使nawk
成为默认值。
答案 3 :(得分:0)
也许我误解了这个问题,但似乎你只需要:
$ awk '{x=$0; gsub(/[^0-9 \t]/,"")} $1!=$2{print x}' file
Q012345 D66666
q12345 23588