Encoding 如何进行不区分重音的grep?

Encoding 如何进行不区分重音的grep?,encoding,grep,matching,diacritics,iconv,Encoding,Grep,Matching,Diacritics,Iconv,有没有一种方法可以使用grep进行不区分重音的搜索,最好保留--color选项?我的意思是说,grep——不区分重音的秘密选项aei将匹配a ei,但也可能匹配aēì和I 我知道我可以使用iconv-tscii//translatit来删除文本中的重音,但我不知道如何使用它来匹配,因为文本已转换(它适用于grep-c或-l)我不认为这可以在grep中实现,除非您愿意编写一个使用iconv和diff的shell脚本,这与你的要求在视觉上有点不同 通过一个快速perl脚本,这里有一些非常接近您的请求

有没有一种方法可以使用grep进行不区分重音的搜索,最好保留--color选项?我的意思是说,
grep——不区分重音的秘密选项aei
将匹配a ei,但也可能匹配aēì和I


我知道我可以使用
iconv-tscii//translatit
来删除文本中的重音,但我不知道如何使用它来匹配,因为文本已转换(它适用于grep-c或-l)

我不认为这可以在grep中实现,除非您愿意编写一个使用
iconv
diff
的shell脚本,这与你的要求在视觉上有点不同

通过一个快速perl脚本,这里有一些非常接近您的请求:

#/usr/bin/perl
#tgrep 0.1 Adam Katz 2014版权所有,GPL版本2或更高版本
严格使用;
使用警告;
使用开放式qw(:标准:utf8);
使用Text::Unidecode;
my$regex=shift或die“缺少模式。\n用法:tgrep模式[文件…]”;
我的$retval=1;#默认为false(无点击)
while(){
my$line=“”,my$hit=0;
而(/\G(\S*(?:\S+|$)/G){#对于每个单词(带尾随空格)
我的$word=$1;
if(unidecode($word)=~qr/$regex/){#如果有匹配
$hit++#注意这个事实
$retval=0;#最终退出代码将为0(真)
$line.=“\e[1;310M$word\e[0;0m”#以红色显示word
}否则{
$line.=$word;#正常显示不匹配的单词
}
}
如果$hit,则打印$line;#仅显示匹配的行
}
退出$retval;
Markdown不允许我生成红色文本,因此这里的输出中使用了引号中的点击:

$echo“匹配ei,但也匹配ēì和可能的æi”| tgrep aei
匹配“ei”,但也匹配“ēì”和可能的“æi”
这将突出显示匹配的单词,而不是实际的匹配,如果不创建大量字符类和/或组成一个分段正则表达式解析器,这将非常困难。因此,搜索模式“ae”而不是“aei”,将产生相同的结果(在本例中)


在这个玩具示例中,没有复制任何grep的标志。我想让它保持简单。

对于我来说,使用php中的grep比perl解决方案更快(可以调整)

Strtolower您的查询字符串不带重音,然后用重音形式替换一些字母,grep-i用于不区分大小写的研究(注意$q中的引号):


您正在寻找一整套POSIX正则表达式:

14.3.6.2等价类运算符(
[=…=]

    Regex识别列表中的等价类表达式。等价类表达式是一组所有元素都属于同一等价类的排序元素。您可以通过在开放等价类运算符和封闭等价类运算符之间放置排序元素来形成等价类表达式。
    [=
    表示开放等价类运算符,
    =]
    表示封闭等价类运算符。例如,如果
    a
    a
    是等价类,则
    [[=a=]
    [=a=]]
    将同时匹配
    a
    a
    。如果等价类表达式中的排序元素不是等价类的一部分,则匹配者将等价类表达式视为排序符号。
我在下一行中使用了插入符号来指示实际的颜色。我还调整了测试字符串以说明有关case的一点

$echo“我匹配ei,但也匹配ēì和可能的æI”| grep'[[=a=][[=e=][[=I=]]
我和艾相配,但也可能和艾相配
^^^          ^^^
这匹配所有的单词,比如
aei
。它与
æi
不匹配的事实应该提醒您,您必须遵守您正在使用的正则表达式库中存在的任何映射(可能是gnulib,这是我链接和引用的),尽管我认为这很可能是最好的等价类映射所无法达到的

你不应该期望等价类是可移植的,因为它们太神秘了


更进一步说,如果您只需要重音字符,事情会变得复杂得多。在这里,我将您对
aei
的请求更改为
[aei]

$echo“我匹配ei,但也匹配ēì和可能的æI”| grep'[[=a=][=e=[=I=]'
我和艾相配,但也可能和艾相配
^  ^    ^^^     ^    ^^^ ^       ^     ^
为避免非重音匹配而清理这一点需要两个等价类和向前看/向后看,虽然BRE(基本POSIX正则表达式)和ERE(扩展POSIX正则表达式)支持前者,但它们都缺少后者和
perl
支持后者,但缺少前者:

使用libpcre:failure尝试#1:
grep

$echo“我匹配ei,但也匹配ēì和可能的æI”\
|grep-P'[=a=][=e=][=i=]](?支持!这样的例子并不多。(不要介意抱怨第二个等价类,它仍然抱怨只给出了
/[=a=]/
)这进一步证明了等价类是神秘的

事实上,似乎没有任何PCRE库能够实现等价类;本节声称只有实现POSIX标准的正则表达式库才具有这种支持。GNU
grep
最接近,因为它可以实现BRE、ERE和PCRE,但它不能将它们结合起来

所以我们将分两部分来做

尝试4:恶心的诡计:成功

$echo“我匹配ei,但也匹配ēì和可能的æI”\
|grep--color=始终'[[=a=][=e=][=i=]'\
|perl-pne“s/\e\[[0-9;]*m\e\[K(?i)
// Your query string
$q = 'Maxime Bernié';

$accents = array(
    'a' => '[aáàâäãå]',
    'e' => '[eéèêë]',
    'i' => '[iíìîï]',
    'o' => '[oóòôöõ]',
    'u' => '[uúùûü]',
    'c' => '[cç]',
    'n' => '[nñ]',
    'y' => '[ýÿ]'
);

$q = remove_accents(strtolower($q));
$qa = str_split($q);

foreach ($qa as $k => $v) {
    if (isset($accents[$v])) {
        $qa[$k] = $accents[$v];
    }
}

$q = implode('', $qa);

echo system('cat file.txt | grep -i "'.$q.'"');

function remove_accents($str, $charset='utf-8')
{
    $str = htmlentities($str, ENT_NOQUOTES, $charset);

    $str = preg_replace('#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
    $str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str);
    $str = preg_replace('#&[^;]+;#', '', $str);

    return $str;
}