查找与通配符字符串的所有可能匹配项

时间:2016-07-02 16:35:57

标签: python linux bash perl sed

我正在尝试使用Linux脚本处理三元令牌文件:01XX“不在乎”,可能是01

例如我有这个文件:

010101X0X10
X1111111111

我需要这个输出文件:

01010100010    
01010100110    
01010110010
01010110110   
01111111111    
11111111111

5 个答案:

答案 0 :(得分:2)

此Perl解决方案使用glob函数。当在该解决方案中使用时,它产生笛卡尔积(用' 0'' 1')用于“不在乎”。值。 (在我为glob链接的文档末尾有一个例子。)

可以删除打印出$str的代码行;它就是为了显示整个字符串的样子。

结果是OP所期望的。

#!/usr/bin/perl
use strict;
use warnings;

while (<>) {
    display($_);
}

sub display {
    my $str = shift;
    $str =~ s/X/{0,1}/g;
    print "\t$str"; # to visualize $str
    print "$_\n" for glob $str; 
}

对于给定的输入文件(通过stdin传递或由arugment命名),输出如下:

        010101{0,1}0{0,1}10
01010100010
01010100110
01010110010
01010110110
        {0,1}1111111111
01111111111
11111111111

答案 1 :(得分:1)

>>> def rs(pre, suf):
...     if suf:
...         if suf[0] == 'X':
...             rs(pre+'0',suf[1:])
...             rs(pre+'1',suf[1:])
...         else:
...             rs(pre+suf[0],suf[1:])
...     else:
...         print pre
... 
>>> rs("",'011X1100X')
011011000
011011001
011111000
011111001

答案 2 :(得分:1)

直接的递归Bash函数:

f() {
    local a;
    if [[ $1 = *X* ]]; then
        for a in 0 1; do
            f "${1/X/$a}"
        done
    else
        echo "$1"
    fi
}

演示:

$ f 010101X0X10
01010100010
01010100110
01010110010
01010110110
$ f X1111111111
01111111111
11111111111

与文件一起使用:

while IFS= read -r line; do
    f "$line"
done < /path/to/file

答案 3 :(得分:0)

将其分成几部分

在分解最多时,你必须使用单个二进制字符串并让X = 0,1

target_str = "010101X0010"
x = re.findall("X",target_str)
n = 2**len(x)

for i in range(n):
    n_x = iter(bin(i)[2:].zfill(len(x)))
    print re.sub("X",lambda m:next(n_x),target_str)

这样做的方式......(可能不会有任何老板会欣赏它,因为它真的不太清晰......)

答案 4 :(得分:0)

这是Perl解决方案

您所需的输出中似乎缺少多个条目,我认为这是一个错误

我认为你可能想要这样的东西,它产生的所有价值都与“不在乎”#34;输入中的数字

如果您尝试使用平面列表,使用带有递归函数的map是解决字符索引转换问题的简单方法

请注意,大写X数字一旦被&#34;翻译为&#34;就会保留为小写x,因此$_ = uc for @final将其保留为最终名单已经计算

没有尝试从输出列表中删除重复值

use strict;
use warnings 'all';

use Data::Dumper;
$Data::Dumper::Terse = 1;

my @final = map { expand($_) } qw/ 010101X0X10  X1111111111 /;
$_ = uc for @final;

print Dumper \@final;

sub expand {
    my ($p) = @_;
    $p =~ /X/ ? map { expand($_) } s/X/0/r, s/X/1/r, s/X/x/r : $p;
}

输出

[
  '01010100010',
  '01010100110',
  '01010100X10',
  '01010110010',
  '01010110110',
  '01010110X10',
  '010101X0010',
  '010101X0110',
  '010101X0X10',
  '01111111111',
  '11111111111',
  'X1111111111'
]


更新

这是一个产生修订要求中所示输出的版本

现在无需以小写形式保留X个字符,因此程序更简单

use strict;
use warnings 'all';

use Data::Dumper;
$Data::Dumper::Terse = 1;

my @final = map { expand($_) } qw/ 010101X0X10  X1111111111 /;

print Dumper \@final;

sub expand {
    my ($p) = @_;
    $p =~ /X/ ? map { expand($_) } s/X/0/r, s/X/1/r : $p;
}

输出

[
  '01010100010',
  '01010100110',
  '01010110010',
  '01010110110',
  '01111111111',
  '11111111111'
]