【问题标题】:Match strings in 2 files and return the line above in file 2 if they match匹配 2 个文件中的字符串,如果匹配则返回文件 2 中的上述行
【发布时间】:2017-02-15 20:36:25
【问题描述】:

我在文件 1 中有一个电子邮件地址列表,我正在尝试在文件 2 中查找这些电子邮件地址(来自文件 1)。如果电子邮件地址在文件 2 中,我希望它返回上面的行,这是他们的用户名。例如:

这是文件 1:

test@test.com
bob@test.com
sally@test.com
eve@test.com

这是文件 2:

testing
test@test.com
robert
bob@test.com
sally
sally@test.com
eve92
eve@test.com

我希望输出是:

testing
robert
sally
eve92

我正在调查awk,但似乎无法弄清楚。关于如何最好地做到这一点的任何想法?愿意通过 bash 或 python 或任何你认为最好的方式来完成。谢谢!

【问题讨论】:

  • 高于还是低于?你的例子不同意你的解释
  • set(f2.readlines()) - set(f1.readlines()) 适用于您的示例,请给出一个更能代表您希望应用的逻辑的示例。
  • 这两个文件是否会以相同的方式排序(如果test@test.com 存在,它将在bob@test.com... 之前)并且文件1 中的所有电子邮件是否都在文件2 中?
  • 对不起,@TemporalWolf,它应该在示例中。考虑反转文件 2(现在更新)
  • 如果两个文件看起来都像 file1,你的输出会是什么样子?

标签: python bash shell awk


【解决方案1】:

这是执行您想要的操作的稳健、高效的方法:

$ awk 'NR==FNR{a[$1];next} NR%2{prev=$0;next} $1 in a{print prev}' file1 file2
testing
robert
sally
eve92

它从电子邮件地址中去除前导/尾随空格,对两个文件中的整个电子邮件地址进行字符串(而不是正则表达式)匹配,并且仅将电子邮件地址与文件 2 的每 2 行进行比较,因此出现错误的可能性为零虚假匹配,错过真正匹配的机会为零。

【讨论】:

  • 不错。 Ed Morton == awk 向导 :)
【解决方案2】:

首先用 file2 中的所有先前行创建一个数组。
第一步中的每个命令都以 next 结尾。
现在解析 file1(NR 将大于 FNR)并在数组中查找它们。

awk 'NR==FNR{a[$1]=x;x=$0;next} $1 in a{print a[$1]}' file2 file1

【讨论】:

    【解决方案3】:

    这应该可以:grep -B1 -F -f file1 file2

    -B1 : 在匹配前获取 1 行 (GNU grep)
    -F :固定字符串匹配,而不是正则表达式
    -f :在您的情况下从 file = file1 加载模式
    file2:应用grep并获取上一行的文件(B1)

    更新:
    经过一番测试,这个解决方案有个bug:grep返回两行。
    模式匹配的一行 = 电子邮件
    模式匹配前的另一行 = 用户名。

    由于 -B1 grep 运算符,模式匹配之前的行先行。

    仅获取第一行 = 用户名而不获取模式匹配(第二行)的简单方法是:

    grep -B1 -F -f file1 file2 |grep -v "@"
    

    考虑到用户名不包含“@”,这将起作用。

    【讨论】:

    • 看看这个 - 这也会提取电子邮件地址,你如何让它只提取用户名?我正在为此寻找 grep 但有没有办法 grep @test.com 然后只取它上面的行?
    • @Neemaximo 您可能需要仔细检查更复杂的输入。 -v 应该给你与正则表达式不匹配的行。
    • @Neemaximo -v 在您的情况下不应该工作。 -v 给出的行与正则表达式不匹配。我们不需要隔离用户名(或者我们必须这样做?)我们查看 file1 - 第一行 - pattern = "test@test.com"。使用此模式 (test@test.com) grep 在 file2 中查找。如果在 file2 上找到模式,则 grep 返回找到的行之前的行。就这么简单。这里没有 -v 选项的空间。
    • 我确实想隔离用户名。我想检查电子邮件地址,然后只返回用户名。
    • @Neemaximo 是的,我的解决方案有一个错误: grep -B1 将匹配前的行与匹配一起返回。所以它返回两行:电子邮件和用户名。这可以通过额外的 grep 来解决。在一分钟内查看更新的答案
    【解决方案4】:

    假设列表是无序的并且 file2 不是太大,为第二个文件构建字典似乎是一个不错的选择:

    users = {}
    with open("file2") as file2:
        try:
            email = ""  # initialize
            while True:
                while "@" not in email:
                    username = email
                    email = file2.next().strip()
                users[email] = username
                email = ""
                username = ""
        except StopIteration:
            pass
    print users
    result = []
    with open("file1") as file1:
        try:
            for line in file1:
                result.append(users[line.strip()])
        except StopIteration:
            pass
    

    result 将包含带有O(m+n) 时间和O(m) 空格的用户名列表(用于file2 的字典)

    【讨论】:

    • 我想这是 python.... 在您对其他读者的回答中澄清它会有所帮助。
    • 我正在测试这个但有一个问题。似乎正在切换字典中的键和值,这会引发一些错误。例如,在某些时候,它给我一个电子邮件地址的KeyError,因为它是字典中的一个值,而不是一个键。但对于其他人来说,电子邮件地址是字典中的关键。
    • @Neemaximo 我更新了它以跳过坏行,只添加好的对......显然你的输入文件不是一个纯粹的列表......也许有一个标题行?
    【解决方案5】:

    如果电子邮件是唯一的(可能是唯一的),您可以使用文件 2 构建一个数组,然后使用文件 1 对其进行索引:

    $ awk 'NR==FNR{getline l; arr[l]=$1; next} $1 in arr {print arr[$1]}' f2 f1
    testing
    robert
    sally
    eve92
    

    在 Python 中,您可能会这样做:

    with open("f2") as f2:
        keys=[(next(f2).strip(), k.strip()) for k in f2]
    
    with open("f1") as f1:
        emails=[e.strip() for e in f1]
    
    for e in emails:
        for t in keys:
            if t[0]==e:
                print t[1]
    

    支持重复条目。如果您知道您的电子邮件地址是唯一的,那么效率会更高:

    with open("f2") as f2:
        keys={next(f2).strip(): k.strip() for k in f2}      
    
    with open("f1") as f1:
        for e in f1:
            e=e.strip()
            print keys.get(e, "{} not found".format(e))
    

    这与awk 程序基本相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-21
      • 2023-01-12
      • 1970-01-01
      • 2015-09-08
      • 1970-01-01
      • 2015-04-13
      • 2020-10-08
      • 2013-02-18
      相关资源
      最近更新 更多