【问题标题】:URL partial matchingURL 部分匹配
【发布时间】:2014-09-24 22:34:36
【问题描述】:

我有两个文件: 文件 1

http://www.hello.com        http://neo.com/peace/development.html, www.japan.com,  http://example.com/abc/abc.html
http://news.net             http://lolz.com/country/list.html,www.telecom.net, www.highlands.net, www.software.com
http://example2.com         http://earth.net, http://abc.gov.cn/department/1.html

文件 2:

www.neo.com/1/2/3/names.html
http://abc.gov.cn/script.aspx
http://example.com/abc/abc.html

file 2 是用于 file1 中 column2 的部分匹配的搜索 url。如果它有部分匹配,它必须返回第 1 列 url 和文件 1 的第 2 列中的部分匹配 url,如下所示:

期望的输出:

http://www.hello.com    http://neo.com/peace/development.html, http://example.com/abc/abc.html
http://news.net
http://example2.com     http://abc.gov.cn/department/1.html

我尝试了这个脚本,它可以在第 2 列为我提供完全匹配的 url 模式,如下所示:

awk -F '[ \t,]' '
FNR == NR {
    a[$1]
    next
}
{    o = $1
    c = 0
    for(i = 2; i <= NF; i++)
        if($i in a)
            o = o (c++ ? ", " : "\t") $i
    print o
}' file2 file1

输出是:

http://www.hello.com    http://example.com/abc/abc.html
http://news.net
http://example2.com

有什么建议可以解决这个问题吗?

【问题讨论】:

  • 我认为grep -f file2 file1 应该适用于大多数情况,除了在没有匹配项时返回 ing column1
  • http://abc.gov.cn/department/1.html 没有出现在file 2 中时,为什么它会出现在您的输出中。我想我不明白你在这里的目的。你不是用file 2搜索file 1,如果找到一个匹配则返回整行,如果没有找到匹配则只返回第一列?
  • @skamazin 如果与 File2 中的 URL 部分匹配,则应打印来自 File1 列 2 的 URL。 http://abc.gov.cn/department/1.html 被打印,因为文件 2 中与 http://abc.gov.cn/ 部分匹配。这就是我的解释方式。
  • 好的,所以它只需要匹配 URL 的第一部分......这相当困难......

标签: shell awk sed scripting


【解决方案1】:

这是一个 awk 可执行脚本:

#!/usr/bin/awk -f

function getHost( url,        host ) {
    c = split( url, uarr, /[/]|:/ )
    for(j=1;j<=c;j++ ) {
        if( index( uarr[j], "." ) ) { host=uarr[j]; break }
    }
    return( host )
}

FNR==NR { host=getHost($1); if( host!="" ) hosts[host]; next }

# file2 FS="[[:space:]]|," file1
{
    end=""
    start = $1 "\t"
    for(i=2;i<=NF;i++) {
        f1h=getHost( $i )

        for( f2h in hosts ) {
            if( length( f2h ) > length( f1h ) )
                { long_host=f2h; short_host=f1h }
            else
                { long_host=f1h; short_host=f2h }

            if( short_host!="" && index( long_host, short_host ) ) {
                if( end!="" ) end = end ", "
                end = end $i
                break
            }
        }
    }
    print start (end!="" ? end : "")
}

如果它被称为awkochmod +x awko,那么它可以像这样运行:

awko file2 FS="[[:space:]]|," file1

它至少有以下假设:

  • 您真正想要匹配的是来自 url 的主机元素
  • 每个有效主机中至少有一个.
  • \t 是第一个和找到的任何匹配字段之间的输出分隔符

细分:

  • getHost() 函数将返回第一个以 . 为宿主的元素
  • file2 主机被加载到 hosts 数组中
  • 在外部,在处理file1 之前,将, 添加到带有FS="[[:space:]]|," 的字段分隔符中
  • file1解析中,第一个字段存储在start中,后续字段中的任何主机匹配都附加到end中。
  • 在比较主机之前,找到最长的主机并将其设置为long_host,最短的主机设置为short_host
  • 如果在long_host 中找到short_host,则附加到end,并使用逗号进行一些整理。
  • 最后,打印start 和任何end 通过匹配file1 中的每一行生成

运行此程序会产生所需的输出,但需要注意的是,\t 当前始终附加到输出中的$1(即使没有匹配项)。

【讨论】:

    【解决方案2】:
    #!/usr/bin/awk -f
    function gethostname(url) {
        sub(/^[a-z]+:\/+/, "", url)
        sub(/^www[.]/, "", url)
        sub(/\/.*$/, "", url)
        return url
    }
    BEGIN { FS = "[ ,\t\r]*" }
    NR == FNR {
        a[gethostname($1)]++
        next
    }
    {
        t = ""
        for (i = 2; i <= NF; ++i) {
            if (gethostname($i) in a) {
                t = length(t) ? t ", " $i : $i
            }
        }
        print length(t) ? $1 "\t" t : $1
    }
    

    用法:

    awk -f script.awk file2 file1
    

    输出:

    http://www.hello.com    http://neo.com/peace/development.html, http://example.com/abc/abc.html
    http://news.net
    http://example2.com     http://abc.gov.cn/department/1.html
    

    你也可以统一输出:

    awk -f script.awk file2 file1 | column -t -s $'\t' -o '    '
    

    man column

    带有column的脚本版本:

    #!/bin/sh    
    awk -- '
        function gethostname(url) {
            sub(/^[a-z]+:\/+/, "", url)
            sub(/^www[.]/, "", url)
            sub(/\/.*$/, "", url)
            return url
        }
        BEGIN { FS = "[ ,\t\r]*" }
        NR == FNR {
            a[gethostname($1)]++
            next
        }
        {
            t = ""
            for (i = 2; i <= NF; ++i) {
                if (gethostname($i) in a) {
                    t = length(t) ? t ", " $i : $i
                }
            }
            print length(t) ? $1 "|" t : $1
        }
    ' "$@" | column -t -s '|' -o '    '
    

    用法;

    sh script.sh file2 file1
    

    【讨论】:

      猜你喜欢
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多