Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
bash子序列匹配加速_Bash_Performance_Subsequence - Fatal编程技术网

bash子序列匹配加速

bash子序列匹配加速,bash,performance,subsequence,Bash,Performance,Subsequence,我想知道是否有一种简单的方法可以检查一个字符串是否是bash中另一个字符串的子序列,实际上是一个具有额外规则的子序列。我会解释的 “苹果”的一些子序列是“aple”、“al”、“pp”和“ale”。我想得到的子序列有一个额外的规则,就是那些以与字符串相同的字母开始和结束的序列,所以只有“aple”和“ale”符合我的要求 我制作了以下程序: #!/bin/bash while read line do search=$(echo "$line" | tr -s 'A-Za-z' | se

我想知道是否有一种简单的方法可以检查一个字符串是否是bash中另一个字符串的子序列,实际上是一个具有额外规则的子序列。我会解释的

“苹果”的一些子序列是“aple”、“al”、“pp”和“ale”。我想得到的子序列有一个额外的规则,就是那些以与字符串相同的字母开始和结束的序列,所以只有“aple”和“ale”符合我的要求

我制作了以下程序:

#!/bin/bash
while read line
do
    search=$(echo "$line" | tr -s 'A-Za-z' | sed 's/./\.\*&/g;s/^\.\*//' )
    expr match "$1" "$search" >/dev/null && echo "$line"
done
其执行如下:

./program.sh greogdgedlqfe < words.txt
/program.sh greogdgedlqfe
这个程序可以工作,但速度很慢

它获取文件的每一行,将其修改为正则表达式,然后检查它们是否匹配,然后打印原始行。例如:

其中一行有单词google

$search变为g.*o.*g.*l.*e(重复的字母被压缩,额外规则)

然后我们用给定的参数检查这个表达式,如果它匹配,我们打印行:google

这很好,但是当words.txt文件太大时,这个程序会变得太慢。我如何加速我的程序,可能是通过更快的匹配子序列

在可能的Kamilcuk解决方案后编辑


该解决方案返回字符串“qwertyuihgfcvbnhjk”的quick、quin、qwerty,并且只返回quick,因此它几乎是正确的,但还不完全正确。

bash
不需要使用
expr
(外部程序)进行正则表达式匹配;它提供对系统库的内置访问

#!/bin/bash
while read line
do
    search=$(echo "$line" | tr -s 'A-Za-z' | sed 's/./\.\*&/g;s/^\.\*//' )
    [[ $1 =~ $search ]] && echo "$line"
done

bash
不需要使用
expr
(外部程序)进行正则表达式匹配;它提供对系统库的内置访问

#!/bin/bash
while read line
do
    search=$(echo "$line" | tr -s 'A-Za-z' | sed 's/./\.\*&/g;s/^\.\*//' )
    [[ $1 =~ $search ]] && echo "$line"
done

您可以使用模式而不是正则表达式。只需在每个单词的每个字母后插入星号(最后一个字母除外),并使用正常模式匹配

#!/bin/bash
while read line
do
    pattern=""
    for ((i=${#line}-1 ; i>=0 ; --i)) ; do
        pattern="${line:i:1}*"$pattern
    done
    pattern=${pattern%'*'}

    if [[ "$1" == $pattern ]] ; then
        echo "$line"
    fi
done

您可以使用模式而不是正则表达式。只需在每个单词的每个字母后插入星号(最后一个字母除外),并使用正常模式匹配

#!/bin/bash
while read line
do
    pattern=""
    for ((i=${#line}-1 ; i>=0 ; --i)) ; do
        pattern="${line:i:1}*"$pattern
    done
    pattern=${pattern%'*'}

    if [[ "$1" == $pattern ]] ; then
        echo "$line"
    fi
done
试着这样做:

grep -x "$(<<<"$1" tr -s 'A-Za-z' | sed 's/./&*/g;s/\*$//;s/\*//1')" words.txt
对于
set--greogdgedlqfe
它只输出
google

如果我没弄错的话,苹果公司的“后续”就是一切符合
ap*l*e
的东西

像这样尝试:

grep -x "$(<<<"$1" tr -s 'A-Za-z' | sed 's/./&*/g;s/\*$//;s/\*//1')" words.txt
对于
set--greogdgedlqfe
它只输出
google

如果我没弄错的话,苹果公司的“后续”就是一切符合
ap*l*e
的东西


使用regexp很难击败
perl

性能

性能的关键是避免分叉额外的进程。这里介绍的大多数bash解决方案(基于KamilCuk
grep
的解决方案除外,它并不总是正确的)都需要多次调用sed、tr等。Perl的性能将优于这些解决方案。即使可以实现一个纯bash解决方案(使用bash-RE,patterns),当单词列表的大小很大时,Perl的性能也可能优于它

考虑
program.pl appl

#! /usr/bin/perl
use strict ;

my $word = shift @ARGV ;

while ( <> ) {
    chomp ;
    my $p = $_ ;
    tr/A-Za-z//s ;
    s/(.)/.*$1/g ;
    s/^\.\*// ;
    print $p, "\n" if $word =~ "^$_\$" ;
} ;
#/usr/bin/perl
严格使用;
my$word=shift@ARGV;
而(){
咀嚼;
我的$p=$\;
tr/A-Za-z//s;
每克1美元;
s/^\.\*/;
打印$p,“\n”如果$word=~”^$\u\$”;
} ;
更新1:KamilCuk解决方案+修复的Perl实现。

在进行了一些小的修改之后,我相信可以使用基于grep的解决方案中的思想来创建一个速度更快的Perl程序。它创建一个REGEXP,并测试单词列表文件中的每个单词。我认为这是Perl的最佳选择

#! /usr/bin/perl
use strict ;

$_ = shift @ARGV ;
tr/A-Za-z//s ;
s/(.)/$1*/g ;
s/\*// ;
s/\*$// ;
my $re = "^$_\$" ;
print "RE=$re\n" ;

while ( <> ) {
        chomp ;
        print $_, "\n" if /$re/ ;
} ;
#/usr/bin/perl
严格使用;
$\ux=shift@ARGV;
tr/A-Za-z//s;
s/()/$1*/g;
s/\*/;
s/\*$/;
my$re=“^$\u\$”;
打印“RE=$RE\n”;
而(){
咀嚼;
如果/$re/,则打印“$\n”;
} ;

使用regexp很难打败
perl

性能

性能的关键是避免分叉额外的进程。这里介绍的大多数bash解决方案(基于KamilCuk
grep
的解决方案除外,它并不总是正确的)都需要多次调用sed、tr等。Perl的性能将优于这些解决方案。即使可以实现一个纯bash解决方案(使用bash-RE,patterns),当单词列表的大小很大时,Perl的性能也可能优于它

考虑
program.pl appl

#! /usr/bin/perl
use strict ;

my $word = shift @ARGV ;

while ( <> ) {
    chomp ;
    my $p = $_ ;
    tr/A-Za-z//s ;
    s/(.)/.*$1/g ;
    s/^\.\*// ;
    print $p, "\n" if $word =~ "^$_\$" ;
} ;
#/usr/bin/perl
严格使用;
my$word=shift@ARGV;
而(){
咀嚼;
我的$p=$\;
tr/A-Za-z//s;
每克1美元;
s/^\.\*/;
打印$p,“\n”如果$word=~”^$\u\$”;
} ;
更新1:KamilCuk解决方案+修复的Perl实现。

在进行了一些小的修改之后,我相信可以使用基于grep的解决方案中的思想来创建一个速度更快的Perl程序。它创建一个REGEXP,并测试单词列表文件中的每个单词。我认为这是Perl的最佳选择

#! /usr/bin/perl
use strict ;

$_ = shift @ARGV ;
tr/A-Za-z//s ;
s/(.)/$1*/g ;
s/\*// ;
s/\*$// ;
my $re = "^$_\$" ;
print "RE=$re\n" ;

while ( <> ) {
        chomp ;
        print $_, "\n" if /$re/ ;
} ;
#/usr/bin/perl
严格使用;
$\ux=shift@ARGV;
tr/A-Za-z//s;
s/()/$1*/g;
s/\*/;
s/\*$/;
my$re=“^$\u\$”;
打印“RE=$RE\n”;
而(){
咀嚼;
如果/$re/,则打印“$\n”;
} ;

您能否发布words.txt的一些摘录和示例输出。我无法测试您的脚本,对于某些输入,一些匹配和不匹配的单词将非常有用。
apppppppple
apple
的子序列吗?因为您的脚本将与
apple
匹配。如果我理解正确,只有
apple
的4个有效子序列:
ae
ale
ape
。是吗?是的,但是apppe在我的程序中也会匹配,这是故意的。Och?那么
apple
也是苹果的后继产品吗?“后续”看起来不像“子序列”,更像是一个扩展。因此,子序列就是与正则表达式匹配的任何东西,正则表达式由一个单词的字母组成,带有
*