如何将具有组合变音符号 ɔ̃、ɛ̃ 和 ɑ̃ 的字符与 python 中的无重音字符从 utf-8 编码文本文件导入进行比较?

问题描述

总结:我想比较ɔ̃、ɛ̃和ɑ̃与ɔ、ɛ和a,它们都不同,但是我的文本文件有ɔ̃、ɛ̃和ɑ̃写成ɔ~、ɛ~和a~。


我写了一个脚本,它同时沿着两个单词中的字符移动,比较它们以找到不同的字符 单词长度相等(除了引入额外字符的变音符号问题),并表示两个法语单词的国际音标发音只有一个音素。

最终目标是过滤一张 anki 卡片列表,以便只包含某些音素对,因为其他音素对太容易识别了。每对单词代表一个 anki 笔记。

为此,我需要区分鼻音 ɔ̃、ɛ̃ 和 ɑ̃ 形成的其他声音,因为它们只会与自身混淆。

如所写,代码将重音字符视为字符加 ~ 和两个字符。因此,如果一个单词中唯一的区别是最后一个重读字符和重读字符之间的差异,则脚本在最后一个字母上没有发现差异,并且按照书面形式将找到一个比另一个短的单词(另一个仍然有 ~ 左)和尝试再比较一个字符时抛出错误。这本身就是一个完整的“问题”,但如果我可以将重音字符作为单个单位读取,那么单词的长度将相同,并且会消失。

我不想用非重音字符替换重音字符,就像有些人为了比较所做的那样,因为它们是不同的声音。

我已经尝试将 unicode“规范化”为“组合”形式,例如 unicodedata.normalize('NFKC',line),但它没有改变任何东西。


这是一些输出包括它刚刚抛出错误的行;打印输出显示代码正在比较的每个单词的单词和字符;该数字是该字符在单词中的索引。因此,最后一个字母是剧本“认为”的两个字符,它对 ɛ̃ 和 ɛ 的看法相同。它还选择了错误的字母对,然后在报告差异时,这对是正确的很重要,因为我会与允许对的主列表进行比较。

0 alyʁ alɔʁ a a # this first word is done well
1 alyʁ alɔʁ l l
2 alyʁ alɔʁ y ɔ # it doesn't continue to compare the ʁ because it found the difference
...
0 ɑ̃bisjø ɑ̃bisjɔ̃ ɑ ɑ
1 ɑ̃bisjø ɑ̃bisjɔ̃ ̃ ̃  # the tildes are compared / treated  separately
2 ɑ̃bisjø ɑ̃bisjɔ̃ b b
3 ɑ̃bisjø ɑ̃bisjɔ̃ i i
4 ɑ̃bisjø ɑ̃bisjɔ̃ s s
5 ɑ̃bisjø ɑ̃bisjɔ̃ j j
6 ɑ̃bisjø ɑ̃bisjɔ̃ ø ɔ # luckily that wasn't where the difference was,this is
...
0 osi ɛ̃si o ɛ # here it should report (o,ɛ̃),not (o,ɛ)
...
0 bɛ̃ bɔ̃ b b
1 bɛ̃ bɔ̃ ɛ ɔ # an error of this type
...
0 bo ba b b
1 bo ba o a # this is working correctly 
...
0 bjɛ bjɛ̃ b b
1 bjɛ bjɛ̃ j j
2 bjɛ bjɛ̃ ɛ ɛ # AND here's the money,it thinks these are the same letter,but it has also run out of characters to compare from the first word,so it throws the error below
Traceback (most recent call last):

  File "C:\Users\tchak\OneDrive\Desktop\french.py",line 42,in <module>
    letter1 = line[0][index]

IndexError: string index out of range

代码如下:

def lens(word):
    return len(word)

# open file,and new file to write to
input_file = "./phonetics_input.txt"
output_file = "./phonetics_output.txt"
set1 = ["e","ɛ","œ","ø","ə"]
set2 = ["ø","o","ɔ","ə"]
set3 = ["ə","i","y"]
set4 = ["u","y","ə"]
set5 = ["ɑ̃","ɔ̃","ɛ̃","ə"]
set6 = ["a","ə"]
vowelsets = [set1,set2,set3,set4,set5,set6]
with open(input_file,encoding="utf8") as ipf,open(output_file,encoding="utf8") as opf:
    # for line in file; 
    vowelpairs= []
    acceptedvowelpairs = []
    input_lines = ipf.readlines()
    print(len(input_lines))
    for line in input_lines:
        #find word ipa transctipts
        unicodedata.normalize('NFKC',line)
        line = line.split("/")
        line.sort(key = lens)
        line = line[0:2] # the shortest two strings after splitting are the ipa words
        index = 0
        letter1 = line[0][index]
        letter2 = line[1][index]
        print(index,line[0],line[1],letter1,letter2)
            
        linelen = max(len(line[0]),len(line[1]))
        while letter1 == letter2:
            index += 1
            letter1 = line[0][index] # throws the error here,technically,after printing the last characters and incrementing the index one more
            letter2 = line[1][index]
            print(index,letter2)
            
        vowelpairs.append((letter1,letter2))   
        
    for i in vowelpairs:
        for vowelset in vowelsets:
            if set(i).issubset(vowelset):
                acceptedvowelpairs.append(i)
    print(len(vowelpairs))
    print(len(acceptedvowelpairs))

解决方法

Unicode 规范化对描述的特定字符组合没有帮助,因为 Unicode database UnicodeData.Txt 的摘录使用简单的正则表达式 "Latin.*Letter.*with tilde$" 给出了 ÃÑÕãñõĨĩŨũṼṽẼẽỸỹ(没有拉丁字母 Open O,{{1} } 或 Open E)。因此,您需要按如下方式分别遍历两个比较的字符串(省略了 a Minimal,Reproducible Example 上面的大部分代码):

Alpha

输出import unicodedata def lens(word): return len(word) input_lines = ['alyʁ/alɔʁ','ɑ̃bisjø/ɑ̃bisjɔ̃ ','osi/ɛ̃si','bɛ̃ /bɔ̃ ','bo/ba','bjɛ/bjɛ̃ '] print(len(input_lines)) for line in input_lines: print('') #find word ipa transctipts line = unicodedata.normalize('NFKC',line.rstrip('\n')) line = line.split("/") line.sort(key = lens) word1,word2 = line[0:2] # the shortest two strings after splitting are the ipa words index = i1 = i2 = 0 while i1 < len(word1) and i2 < len(word2): letter1 = word1[i1] i1 += 1 if i1 < len(word1) and unicodedata.category(word1[i1]) == 'Mn': letter1 += word1[i1] i1 += 1 letter2 = word2[i2] i2 += 1 if i2 < len(word2) and unicodedata.category(word2[i2]) == 'Mn': letter2 += word2[i2] i2 += 1 same = chr(0xA0) if letter1 == letter2 else '#' print(index,same,word1,word2,letter1,letter2) index += 1 #if same != chr(0xA0): # break

.\SO\67335977.py

注意变音符号测试为 Unicode 类别 6 0   alyʁ alɔʁ a a 1   alyʁ alɔʁ l l 2 # alyʁ alɔʁ y ɔ 3   alyʁ alɔʁ ʁ ʁ 0   ɑ̃bisjø ɑ̃bisjɔ̃ ɑ̃ ɑ̃ 1   ɑ̃bisjø ɑ̃bisjɔ̃ b b 2   ɑ̃bisjø ɑ̃bisjɔ̃ i i 3   ɑ̃bisjø ɑ̃bisjɔ̃ s s 4   ɑ̃bisjø ɑ̃bisjɔ̃ j j 5 # ɑ̃bisjø ɑ̃bisjɔ̃ ø ɔ̃ 0 # osi ɛ̃si o ɛ̃ 1   osi ɛ̃si s s 2   osi ɛ̃si i i 0   bɛ̃ bɔ̃ b b 1 # bɛ̃ bɔ̃ ɛ̃ ɔ̃ 2   bɛ̃ bɔ̃ 0   bo ba b b 1 # bo ba o a 0   bjɛ bjɛ̃ b b 1   bjɛ bjɛ̃ j j 2 # bjɛ bjɛ̃ ɛ ɛ̃ ;您可以针对其他条件进行测试(例如,来自以下列表):

  • Mn 一个非间距组合标记(零前进宽度)
  • Mn Nonspacing_Mark: 一个间距组合标记(正推进宽度)
  • Mc Spacing_Mark : 一个封闭的组合标记
  • Me Enclosing_Mark : M Mark :
,

我正在解决这个问题,方法是在处理这些字符之前对其进行查找和替换,并在完成后进行反向查找和替换。