代码之家  ›  专栏  ›  技术社区  ›  Sam Axe

为中的GAWK concat变量

  •  0
  • Sam Axe  · 技术社区  · 8 年前

    我当前的GAWK脚本使用短语文件,创建一个正则表达式模式数组,然后将每行按字符拆分,并循环每行的前10列,然后检查是否包含模式数组中的至少一个短语,如果包含,则跳过该行,不将其打印到文档中。

    问题:

    因为短语文件很大,它会创建大量迭代,并使脚本非常慢。

    (700个图案x 10列(由制表符分隔))x 1000行。

    为了提高速度,我想将前10列合并,并检查整个字符串是否至少包含一个模式。我不知道如何在FOR循环中连接行。

    工作示例:

    gawk 'BEGIN{
    FS=" *\t *";
    IGNORECASE=1;
    
    while(getline a < "'$phpath'") PATS["^.*"a".*$"]
    }
    
    {
        ok=1;
        for(i=1;i<=10;i++){
            for(p in PATS){
                if($i ~ p){
                ok=0
                }
            }
        }
    
    } 
    ok {print}' "$f" > "$newPath$filename" 
    

    我的尝试:

    gawk 'BEGIN{
        FS=" *\t *";
        IGNORECASE=1;
    
        while(getline a < "'$phpath'") PATS["^.*"a".*$"]
        }
    
        {
            phrase="";
            space=" ";
            ok=1;
    
            for(i=1;i<=10;i++){
                phrase = $space $phrase $i
            }
    
            for(p in PATS){
                if($phrase ~ p){
                    ok=0
                }
            }
    
        } ok {print}' "$f" > "$newPath$filename"
    
    3 回复  |  直到 8 年前
        1
  •  1
  •   glenn jackman    8 年前

    在awk中,您使用 $ 复引用运算符 哪里 $x 表示“给我一个数值为变量的列的值 x "

    要将前10列转换为字符串,请执行以下操作:

        for (i=1; i<=10; i++) {
            # not this => phrase = $space $phrase $i
            phrase = space phrase $i
        }
    

        for (p in PATS) {
            if (phrase ~ p) {   # <= no $
                ok = 0
                break           # no match, so break the loop early
            }
        }
    


    您也可以尝试这样做:

    gawk -v patternfile="$phpath" '
        BEGIN {
            FS = " *\t *"
            IGNORECASE = 1
            while ((getline a < patternfile) > 0)
                PATS["^.*"a".*$"]
        }
        {
            line = $0
            NF = 10         # this truncates the current record to 10 fields
            ok = 1
            for (p in PATS) 
                if ($0 ~ p) {
                    ok = 0
                    break
                }
            if (ok) 
                print line
        }
    ' "$f" > "$newPath$filename"
    
        2
  •  0
  •   kcoder24    8 年前

    这不是你问题的答案,而是你的问题的答案。

    我知道你的问题是关于性能的。

    据我所知,您遇到的一个主要问题是您正在使用RegEx。让我解释一下我的观点。在AWK中,当您使用像这样的正则表达式:/MyRegExp/时,您使用的是正则表达式的编译版本,因此每次需要检查匹配时,您只检查它,但当您使用类似于“MyRegExp”的正则表达式时,每次要检查字符串是否匹配时,都会编译它。

    你真的在检查正则表达式吗?也许你不是,函数“index”对你来说已经足够好了。

    为什么不尝试构建一个脚本并运行它呢?不是根据加载的模式检查第二个文件中的每一行,而是创建如下脚本:

    /pattern1/{
        print
        next
    }
    /pattern2/{
        print
        next
    }
    /pattern3/{
        print
        next
    }
    ...
    ...
    

    然后用第二个文件运行它。不管怎样,我希望这能有所帮助。

        3
  •  0
  •   James K. Lowden    8 年前
    while(getline a < "'$phpath'") PATS["^.*"a".*$"]
    

    ^.*"a".*$ a .而不是迭代模式,您可以直接使用 | .

    如果您的输入文件是

    every
    good
    boy
    does
    fine
    

    你的重新成为 every|good|boy|does|fine 并且您的代码减少到

    $0 ~ pattern { 
        for (i=1; i<=10; i++) {
            if( $i ~ pattern ) { 
               print "$f" > "$newPath$filename" # what's $f?  
               break
            }
        }
    }
    

    也就是说,首先扫描整条线。如果它找到了什么,则迭代前10列。我打赌这比无条件地迭代它们要快。