Python Devnagari字符串比较

Python Devnagari字符串比较,python,shell,perl,Python,Shell,Perl,我在文本文件中有几十万个devnagari单词(每行一个单词)。我必须复制最相似的词,比如“अक्तूबर, अक्‍टूबर" "कौम, क़ौम" 在另一个文件中进行更正。复制时允许最大两个位置的差异。为此,我使用“awk”查找单词的差异,并将类似的单词复制到另一个文件中。但它失败了,因为此命令仅适用于罗马字符,而不适用于devnagari字符 awk -v string=कौम -v string1=क़ौम '{ for (i=1;i<=length(string);i++) {

我在文本文件中有几十万个devnagari单词(每行一个单词)。我必须复制最相似的词,比如“अक्तूबर, अक्‍टूबर" "कौम, क़ौम" 在另一个文件中进行更正。复制时允许最大两个位置的差异。为此,我使用“awk”查找单词的差异,并将类似的单词复制到另一个文件中。但它失败了,因为此命令仅适用于罗马字符,而不适用于devnagari字符

awk -v string=कौम -v string1=क़ौम '{ for (i=1;i<=length(string);i++) { if (substr(string,i,1) != substr(string1,i,1)) { count++ } }} END { print (count/length(string)*100"% difference") }' <<< ""

awk-v字符串=कौम -v弦1=क़ौम '{for(i=1;i您似乎想要比较grapheme集群

use open ':std', ':encoding(UTF-8)';

use charnames qw( :full );

for my $arg_idx (0..$#ARGV) {
   my $arg = $ARGV[$arg_idx];

   utf8::decode($arg);

   for my $grapheme_cluster ($arg =~ /\X/g) {
      printf("%s %v04X\n", $grapheme_cluster, $grapheme_cluster);
      for my $code_point (unpack('W*', $grapheme_cluster)) {
         printf("   %04X %s\n", $code_point, charnames::viacode($code_point));
      }
   }

   print("\n") if $arg_idx != $#ARGV;
}
字素簇表示文本的水平可分段单元,由一些字素基(可能由韩国语音节组成)以及应用于其上的任意数量的非空格标记组成

这只是一种“奇特”的方式,每一个字形集群都是一个“视觉角色”

让我们确认一下。下面的程序允许我们查看您的字符串,分为多个grapheme集群

use open ':std', ':encoding(UTF-8)';

use charnames qw( :full );

for my $arg_idx (0..$#ARGV) {
   my $arg = $ARGV[$arg_idx];

   utf8::decode($arg);

   for my $grapheme_cluster ($arg =~ /\X/g) {
      printf("%s %v04X\n", $grapheme_cluster, $grapheme_cluster);
      for my $code_point (unpack('W*', $grapheme_cluster)) {
         printf("   %04X %s\n", $code_point, charnames::viacode($code_point));
      }
   }

   print("\n") if $arg_idx != $#ARGV;
}
对于你的一组字符串,我们得到

$ grapheme_clusters क़ौम              $ grapheme_clusters क़ौम           
कौ 0915.094C                         क़ौ 0915.093C.094C                 
   0915 DEVANAGARI LETTER KA            0915 DEVANAGARI LETTER KA       
                                        093C DEVANAGARI SIGN NUKTA      
   094C DEVANAGARI VOWEL SIGN AU        094C DEVANAGARI VOWEL SIGN AU   
म 092E                               म 092E                             
   092E DEVANAGARI LETTER MA            092E DEVANAGARI LETTER MA       
$ grapheme_clusters अक्तूबर            $ grapheme_clusters अक्‍टूबर
अ 0905                               अ 0905         
   0905 DEVANAGARI LETTER A             0905 DEVANAGARI LETTER A
क् 0915.094D                          क्‍ 0915.094D.200D
   0915 DEVANAGARI LETTER KA            0915 DEVANAGARI LETTER KA
   094D DEVANAGARI SIGN VIRAMA          094D DEVANAGARI SIGN VIRAMA
                                        200D ZERO WIDTH JOINER
तू 0924.0942                          टू 091F.0942
   0924 DEVANAGARI LETTER TA            091F DEVANAGARI LETTER TTA
   0942 DEVANAGARI VOWEL SIGN UU        0942 DEVANAGARI VOWEL SIGN UU
ब 092C                               ब 092C           
   092C DEVANAGARI LETTER BA            092C DEVANAGARI LETTER BA
र 0930                               र 0930
   0930 DEVANAGARI LETTER RA            0930 DEVANAGARI LETTER RA       
到目前为止还不错;这产生了预期的单一差异

对于另一组字符串,我们得到

$ grapheme_clusters क़ौम              $ grapheme_clusters क़ौम           
कौ 0915.094C                         क़ौ 0915.093C.094C                 
   0915 DEVANAGARI LETTER KA            0915 DEVANAGARI LETTER KA       
                                        093C DEVANAGARI SIGN NUKTA      
   094C DEVANAGARI VOWEL SIGN AU        094C DEVANAGARI VOWEL SIGN AU   
म 092E                               म 092E                             
   092E DEVANAGARI LETTER MA            092E DEVANAGARI LETTER MA       
$ grapheme_clusters अक्तूबर            $ grapheme_clusters अक्‍टूबर
अ 0905                               अ 0905         
   0905 DEVANAGARI LETTER A             0905 DEVANAGARI LETTER A
क् 0915.094D                          क्‍ 0915.094D.200D
   0915 DEVANAGARI LETTER KA            0915 DEVANAGARI LETTER KA
   094D DEVANAGARI SIGN VIRAMA          094D DEVANAGARI SIGN VIRAMA
                                        200D ZERO WIDTH JOINER
तू 0924.0942                          टू 091F.0942
   0924 DEVANAGARI LETTER TA            091F DEVANAGARI LETTER TTA
   0942 DEVANAGARI VOWEL SIGN UU        0942 DEVANAGARI VOWEL SIGN UU
ब 092C                               ब 092C           
   092C DEVANAGARI LETTER BA            092C DEVANAGARI LETTER BA
र 0930                               र 0930
   0930 DEVANAGARI LETTER RA            0930 DEVANAGARI LETTER RA       
啊,这里有一个意外的
ZERO-WIDTH JOINER
。如果我们删除它(例如使用
s/\N{ZERO-WIDTH JOINER}//g
,或者通过使用
s/\pC//g
删除所有控制字符),我们将得到预期的单个差异


现在我们已经确定了需要什么,我们可以编写一个解决方案

use List::Util qw( max );

sub count_diffs {
   my ($s1, $s2) = @_;

   s/\N{ZERO WIDTH JOINER}//g for $s1, $s2;

   my @s1 = $s1 =~ /\X/g;
   my @s2 = $s2 =~ /\X/g;

   no warnings qw( uninitialized );
   return 0+grep { $s1[$_] ne $s2[$_] } 0..max(0+@s1, 0+@s2)-1;
}
这种方法的一个主要问题是它不能很好地处理插入或删除。例如,它认为
abcdef
bcdef
有6个差异。计算集群序列的长度而不是通过索引进行比较会更有效

use Algorithm::Diff qw( traverse_balanced );

sub count_diffs {
   my ($s1, $s2) = @_;

   s/\N{ZERO WIDTH JOINER}//g for $s1, $s2;

   my @s1 = $s1 =~ /\X/g;
   my @s2 = $s2 =~ /\X/g;

   my $diffs = 0;
   traverse_balanced(\@s1, \@s2,
      {
         DISCARD_A => sub { ++$diffs; },
         DISCARD_B => sub { ++$diffs; },
         CHANGE    => sub { ++$diffs; },
      },
   );

   return $diffs;
}

最后,出于性能原因,您不希望一次只比较两个字符串;您希望一次将每个字符串与另一个字符串进行比较。我不知道一个易于使用的解决方案。

另请参见,您能否解释如何计算差异?例如上面的示例“अक्तूबर, अक्‍टूबर“仅在一个位置上存在差异,因此预期输出为1(差异计数)。另请参阅@daxim。有关详细信息,请参阅我的答案。失败原因”कंडिशंस कंडीशन,得出的结果相似性为25.0%,相似性为75.0%difference@Amol,你期待什么?为什么?怎么会失败?कं = कं, डि ≠ डी, शं ≠ श, स ≠ न 四分之一是25%,我的目的是纠正写错的单词。@Amol,这仍然不能解释你为什么说“失败”कंडिशंस कंडीशन"", (你需要包括
@ikegami
,我才能得到通知,因为我没有写你要回复的帖子。)