awk/perl 打印回文(如果不在括号之间)

awk/perl 打印回文(如果不在括号之间)

我有一个包含一堆字符串的文件,每行一个。我只想查找并打印一个字符串,前提是它包含回文并且该回文不在括号之间。例子:

abba[cdef]gh    # print
abcd[effe]gh    # do not print

我目前有一个单行代码,如果字符串是回文,它会打印一行

awk 'BEGIN { system("perl -lne \"print if length == 4 && reverse eq \\$_\" " ARGV[1]) }' words.txt

修改自这里

我正在考虑使用sed删除括号之间的所有内容,然后评估剩余的回文。

关于如何在一行中完成此任务还有其他想法吗?

答案1

要查找不在 内的所有 1 个 3 个或更多字符的回文[...]

$ echo 'cac[ada]abacab' | perl -nle '
    while (/\[.*?\]|(?=(([^][])(?1)\2|[^][]?))./g) {
      print $1 if length $1 >= 3
    }'
cac
aba
bacab
aca

(请注意,它假设单字节字符,添加-Mopen=locale字符的区域设置定义)。

回文匹配的核心是递归正则表达式。回文匹配为空字符串或单个字符或一对匹配字符,中间有另一个回文。那就是((.)(?1)\2|.?)(?1)递归部分在哪里(与 的第一部分中的内容匹配(),除了这里我们替换.[^][](除了]和之外的任何字符[)。

匹配时全部出现 时/.../g,perl 在第一个出现后搜索下一个出现,因此,如果我们有\[.*?\]|(([^][])(?1)\2|[^][]?),我们将找不到bacabin,abacab因为它会首先找到aba,然后在该之后继续搜索aba。因此,在这里,我们匹配(?=(palindrome)).匹配单个字符 ( .) 的条件,前提是它位于一个字符的开头回文然后被捕获在$1.这意味着我们继续搜索该单个字符。


严格来说,它会在字符串中的每个位置查找最长的(3 个字符或更多)回文,跳过 s [...],因此可能找不到全部的事件。例如,在 中ababa,它会ababa在第一个位置、bab第三个位置、aba第二个位置找到,但不会aba在第一个位置找到。

答案2

说好的单线呢?使用括号内的单词作为字段分隔符:

perl -F'\[.*?\]' -le 'for $word (@F) {if ($word eq reverse $word) {print; break}}' file

这里没有考虑一些边缘情况:

  • 它不考虑字符串长度
  • 它看起来没有找到回文数之内单词:整个单词必须是回文。

答案3

虽然[...]可以提前过滤掉,但使用类似 lex 的扫描仪走这条线:

#!/usr/bin/env perl
use strict;
use warnings;
LINE: while (readline) {    # for each line (files or stdin)
    LEX: {
        # skip any [] or [...] bits
        redo LEX if m{ \G \[ [^\]]* \] }cgx;
        # two or more not-[ not-vertical-whitespace (\r, \n) chars
        if (m{ \G ([^\[\v]{2,}) }cgx) {
            # palindrome? print the whole line
            if ( $1 eq reverse $1 ) {
                print;
                next LINE;
            }
            # may be more to come...
            redo LEX;
        }
        # advance the lexer a single character
        redo LEX if m{ \G . }cgx;
        # oh it's the end of the line as we know it
    }
}

其中具有针对各种边缘条件的扩展测试用例:

% < input
abba[cdef]gh    # print
abcd[effe]gh    # do not print
[effe]f00f
asdf[]prinirp
a[]b[]edgegde
% perl palin < input
abba[cdef]gh    # print
[effe]f00f
asdf[]prinirp
a[]b[]edgegde
% 

这可以很容易地适应忽略尾随注释或其他此类输入。

相关内容