Chinaunix

标题: 大侠请进:如何在英文和中文之间加入分隔符 [打印本页]

作者: tikico    时间: 2006-02-27 17:49
标题: 大侠请进:如何在英文和中文之间加入分隔符
小弟目前在用python处理一份txt文件,中英文夹杂,目前一个关键问题是想在中文和英文之间加上标记,最好能变成xml的格式,例如:
  1. 【地板】 dìbǎn ? 室内铺在地面上的木板,有时也指木质楼板flooring; wooden board laid
  2. on the floor; wooden floor ?
  3. 我的目标是变成:
  4. <w>【地板】</w><p> dìbǎn</p><chexp>室内铺在地面上的木板,有时也指木质楼板</chexp><enexp>flooring; wooden board laid
  5. on the floor; wooden floor </enexp>
复制代码

哪位大侠给点提示,不胜感激!

[ 本帖最后由 wolfg 于 2006-2-27 21:27 编辑 ]
作者: limodou    时间: 2006-02-27 18:58
只要判断字符的大小,如果小于127则为英文,否则为中文。然后有一个标志位,标识是中文状态,还是英文状态,状态切换时输出上一个格式的结束和下一个格式的开始。依此类推。
作者: tikico    时间: 2006-02-28 11:33
原帖由 limodou 于 2006-2-27 18:58 发表
只要判断字符的大小,如果小于127则为英文,否则为中文。然后有一个标志位,标识是中文状态,还是英文状态,状态切换时输出上一个格式的结束和下一个格式的开始。依此类推。


多谢,大致思路我懂了,可小弟是python的初学者,大致写成了这个样子,主要代码如下:

  1. fh =  open('c:\\Python24\\outputfile.txt','r')
  2. allLines =fh.readlines()
  3. for eachline in allLines:
  4.     i=0
  5.     length=len(eachline)
  6.    #初始化newline
  7.     if eachline[0]<127:
  8.         flag = 0   
  9.         newline='<en>'
  10.     else:
  11.         flag = 1   
  12.         newline='<zh>'
  13.     #将eachline的每个字符复制到newline遇到跳变加入标志
  14.     while i<length:
  15.         if flag==1 and eachline[i]<127:
  16.             newline = newline+'</zh><en>'+eachline[i]
  17.             flag = 0
  18.         elif flag==0 and eachline[i]>=127:
  19.             newline = newline+'</en><zh>'+eachline[i]
  20.             flag = 1
  21.         else:
  22.             newline=newline+eachline[i]
  23.         i = i+1
  24.       print newline
  25. fh.close()   
复制代码

     可是中间的标志还是打不上,就开始的标志打上了,而且以行为操作单位似乎还是不行,因为可能会多行间没出现跳变。
     关键问题在于字符串的插入,请大侠继续提示,谢谢!

[ 本帖最后由 tikico 于 2006-2-28 11:35 编辑 ]
作者: wolfg    时间: 2006-02-28 11:43
要读取的文件是什么样的?每行一个词的解释吗?
能否贴出一段来看看?
作者: limodou    时间: 2006-02-28 15:49
你的代码将文件拆成行来处理,我不是很清楚你的文件有多大。如果不大建议不要使用行来处理。如果不是以行来处理,因此象flag和标识串都应该是在循环之间先有一个初始值。然后再进行循环。
作者: tikico    时间: 2006-03-01 09:02
原帖由 limodou 于 2006-2-28 15:49 发表
你的代码将文件拆成行来处理,我不是很清楚你的文件有多大。如果不大建议不要使用行来处理。如果不是以行来处理,因此象flag和标识串都应该是在循环之间先有一个初始值。然后再进行循环。

      谢谢limodou大侠,我有看过您的blog,很受益。
      代码修改,加上ord函数后能实现加入标记。不知大侠所说的不拆成行处理是什么含义,难道把整个文件先读出来,作为一个字符串处理吗?那对内存的要求是不是更高,还请赐教,谢谢!

[ 本帖最后由 tikico 于 2006-3-1 10:15 编辑 ]
作者: limodou    时间: 2006-03-01 14:15
file对象有read()方法,可以传入每次读的大小.所以我问你文件大不大,不大就全读出来好了.不行就使用read()多读几次.为什么不使用行,我主要是想:


  1. 中文 English
  2. This is another line. 然后是中文
复制代码


象上面的情况,英文换行了,如果换行去处理,会有多余的标记.当然也不会有错.只是我不太清楚你的需求要求有多严格.而看成一个字符串则不会有这个问题.
作者: tikico    时间: 2006-03-02 11:03
确实存在这个问题,而事实上我要处理的文件比这个复杂,还有多个标记要加,其中一段原文件如下:


  1. dì (ㄉㄧˋ)
  2. 地 dì ? 地球;地壳 earth; earth's crust:天~ heaven and earth|~层stratum|~质geology
  3. ? 陆地land:~面earth's surface|~势terrain|高~highland|低~lowland|山~ mountainous area|~下水underground
  4. water ? 土地;田地land; field:荒~ wasteland|下~干活儿go to work in the field ? same as地面dìmiàn
  5. ②:水泥~ cement surface ? same as地区dìqū ①:各~various localities|内~inland area|外~places
  6. other than one's hometown ? same as地区dìqū ②:省~领导provincial and prefectural
  7. leader|~县两级干部cadres at prefectural and county levels ? same as地方dìfānɡ
  8. 【地板】 dìbǎn ? 室内铺在地面上的木板,有时也指木质楼板flooring; wooden board laid
  9. on the floor; wooden floor ? same as地面dìmiàn ②:~革plastic flooring|水磨石~ terrazzo
  10. floor ? 〈方 dial.〉田地field
  11. 【地磅】 dìbànɡ same as地秤dìchènɡ
复制代码


    希望能将字,词,拼音,解释,英语解释,汉语解释标记都列出来,例如“地板”:

  1. <w>【地板】</w><s> dìbǎn</s><exp><zh> 室内铺在地面上的木板,有时也指木质楼板</zh><en>flooring; wooden board laid
  2. on the floor; wooden floor ? same as地面dìmiàn</en> </exp>
复制代码

作者: limodou    时间: 2006-03-02 12:01
看了你的文本,其实这里面不仅有汉字与英文的判断,还有一些格式的判断.比如说: <w>如何判断,可以通过判断【作为开始,】作为结束.汉语拼音如何判断,一种方法是将所有的汉语拼音字符列成一个list,然后判断是否在这个list.还有简单的就是认为<w></w>后面的以空格分隔的就是汉语拼音,当然这完全是通过你的格式简化出来的,一旦格式变化就出问题了.然后就是中英文的判断.

在处理是有一个标志位表示是否进入和离开某个类型.首先有一个初始的状态.然后遇到第一个,判断出现在的状态,然后与flag进行比较,如果相符,则保存到缓冲区中,如果不附,首先判断是否输出过某个开始标记,如<w>,如果没有输出,则输出当前类型的开始标记,然后将内容保存到缓冲区中.循环.如果输出过某个开始标记,则输出对应的结束标记,然后是新的开始标记.flag保存为新的状态,然后将内容保存到缓冲区.循环.

上面写得我认为的大致的思路,可能许多地方可以优化的.可以参考.
作者: tikico    时间: 2006-03-03 09:35
原帖由 limodou 于 2006-3-2 12:01 发表
看了你的文本,其实这里面不仅有汉字与英文的判断,还有一些格式的判断.比如说: <w>如何判断,可以通过判断【作为开始,】作为结束.汉语拼音如何判断,一种方法是将所有的汉语拼音字符列成一个list,然后判断是否 ...

汉语拼音我想利用正则表达式处理,可编译器老报错“error: bad character range”,汉语拼音的编码是这样的,

  1. 252             A3E0        ` a b c d e f g h i j k l m n o
  2. 268             A3F0        p q r s t u v w x y z { | }
复制代码

有什么办法让编译通过吗?我的正则式为:'[a-z]+'。
另外试了一下List:

  1. >>>list_py=['a','b', 'c' ,'d', 'e', 'f', 'g', 'h', 'i' ,'j', 'k' ,'l' ,'m', 'n', 'o','p' ,'q', 'r', 's',
  2.          't', 'u' ,'v', 'w', 'x', 'y', 'z']
  3. >>>line='<w>【骶骨】</w> dǐɡǔ 腰椎下部五块椎骨合成的一块骨,呈三角形,上宽下窄,'
  4. >>> line.find('d',0,len(line))
  5. 16
复制代码

但是

  1. >>> line.find(list_py[3],0,str(line))

  2. Traceback (most recent call last):
  3.   File "<pyshell#8>", line 1, in -toplevel-
  4.     line.find(list_py[3],0,str(line))
  5. TypeError: slice indices must be integers
  6. >>> list_py[3]
  7. '\xa3\xe4'
复制代码

这些编码问题,弄得我郁闷不已,望哪位大侠帮忙解决!

[ 本帖最后由 tikico 于 2006-3-3 10:07 编辑 ]
作者: limodou    时间: 2006-03-03 13:57
汉单拼音不是ascii码,它是unicode.因此使用unicode来匹配即可.
作者: tikico    时间: 2006-03-06 13:57
原帖由 limodou 于 2006-3-3 13:57 发表
汉单拼音不是ascii码,它是unicode.因此使用unicode来匹配即可.

问题还是没有很好的解决,现在想对所有的汉语拼音加上标签,如:
  1. 【砥柱中流】 Dǐzhù zhōnɡliú  中流砥柱
复制代码

变成:
  1. 【砥柱中流】<p> Dǐzhù zhōnɡliú </p> 中流砥柱
复制代码

麻烦哪位大侠能给出代码,不胜感激!
作者: wolfg    时间: 2006-03-06 14:00
你自己的是如何尝试解决这个问题的?讨论问题,不能只要求别人想办法啊,也说说你的思路。
作者: tikico    时间: 2006-03-06 16:34
原帖由 wolfg 于 2006-3-6 14:00 发表
你自己的是如何尝试解决这个问题的?讨论问题,不能只要求别人想办法啊,也说说你的思路。

我的思路是:
1.利用正则表达式:写一个匹配所有汉语拼音的re,我找出其对应的字符如下:
252             A3E0        ` a b c d e f g h i j k l m n o
268             A3F0        p q r s t u v w x y z { | }
658             A8A0           ā á ǎ à ē é ě è ī í ǐ ì ō ó ǒ
674             A8B0        ò ū ú ǔ ù ǖ ǘ ǚ ǜ ü ê ɑ  ń ň 
将匹配的字符re.match(...).group()修改成<p>re.match(...).group()</p>
目前的困难在于 :a.这个re怎么写;b.字符串的修改,没有类似list的insert()函数,也没有replace()
2.利用字符操作:根据limodou兄的建议,将所有汉语拼音存成一个list,然后遍历查找文件,得出每行出现汉语拼音的首位置和尾位置,在首位置处插入‘<p>’,在尾位置插入'</p>'。位置查找如例:

  1. >>>s='【牴牾】 dǐwǔ 抵牾 contradiction;; conflict'
  2. >>>m='d'
  3. >>>s.find(m,0,len(s))
  4. 9
复制代码

关键难点在如何在9这个位置插入<p>这个标签?如何判断首位位置?然后就是速度可能有点问题。
还请大家指教!
作者: limodou    时间: 2006-03-06 17:02
我以前描述的处理方式是在一个扫描过程中进行分类与处理。比如:

s = []  #最后的结果
buf = [] #缓冲区
while get_next_char():
    flag = judge_flag():
    if flag=="w":
        buf = get_w()
    elif flag == "p":
        buf = get_p()
    ...
    s.append(''.join(buf))
    buf = []

上面的示例并不全面,因为中英文是混在一起的,只有w,p可以一次性分析出来。因此对于中英文可能要记住上次的字符,然后与本次的字符进行比较,然后就可以判断出它是第一次出现,还是后续的出现,因此可以判断出是否结束和开始。这里面的确有许多的细节要考虑。但关键是它只扫描字符串一次。而不是重复扫描,因此效率还可以。
作者: tikico    时间: 2006-03-06 17:44
原帖由 limodou 于 2006-3-6 17:02 发表
我以前描述的处理方式是在一个扫描过程中进行分类与处理。比如:

s = []  #最后的结果
buf = [] #缓冲区
while get_next_char():
    flag = judge_flag():
    if flag=="w":
        buf = g ...

limodou兄,上面的东东有点不明白,"w"是后面加进去的,judge_flag()怎么判断?
而且问题的关键似乎是细节,unicode我也试过,就是不知道如何给拼音打上标签,还请指教,谢谢!
作者: limodou    时间: 2006-03-06 20:26
judge_flag是一个函数,它可以返回一个标志啊。不过我也说了,这只是一个示例,完成你的任务还有一些东西要补充完整才行。象汉语拼音的判断,可以:

i = pos
buf = []
while text[i] in pinyin + ' ':
    buf.append(text[i])
    i += 1

pinyin为汉语拼音,而加上空格的目的是为了可以处理拼音中间的空格。
作者: tikico    时间: 2006-03-07 10:45
原帖由 limodou 于 2006-3-6 20:26 发表
judge_flag是一个函数,它可以返回一个标志啊。不过我也说了,这只是一个示例,完成你的任务还有一些东西要补充完整才行。象汉语拼音的判断,可以:

i = pos
buf = []
while text in pinyin + ' ':
     ...

谢谢limodou兄一直的关注。由于比较菜,用python还是没能解决问题,又不想用awk、sed,因为想好好学习一下python。
仔细观察文本发现,汉语拼音和前后文本之间都有空格分开。如果string.split(" ")只要找到表列中的汉语拼音再进行插入标记操作就简单了,当然还要考虑拼音之间的空格。问题是,利用str()函数转化为字符串好像不行。
现在很苦恼,希望能对汉语拼音加上标记就不错了。期待详细点示例描叙。
作者: limodou    时间: 2006-03-07 11:47
使用str可能不行。建议使用unicode。因此我上面的代码是把空格算为拼音的一部分了。
作者: tikico    时间: 2006-03-07 13:43
原帖由 limodou 于 2006-3-7 11:47 发表
使用str可能不行。建议使用unicode。因此我上面的代码是把空格算为拼音的一部分了。

不理解如何使用unicode,
list_py=[u'a',u'b'......],
eachline=eachline.encode('mbcs')
还是很模糊!
作者: limodou    时间: 2006-03-07 15:05
list_py=u'ab' #这是一个unicode字符串
eachline=unicode(eachline, 'gbk') #这是将eachline转为unicode
作者: tikico    时间: 2006-03-07 16:16
原帖由 limodou 于 2006-3-7 15:05 发表
list_py=u'ab' #这是一个unicode字符串
eachline=unicode(eachline, 'gbk') #这是将eachline转为unicode

按您的方法报错:
  1.     eachline = unicode(eachline,'gbk')
  2. UnicodeDecodeError: 'gbk' codec can't decode bytes in position 316-317: illegal multibyte sequence
复制代码


另外您的那个方法:
while eachline in pinyin +'':  
其中的pinyin是list还是string啊?对于一个字符串可以get_next_char()吗,是得到的下一个字节还是下一个字符?
作者: limodou    时间: 2006-03-07 16:49
UnicodeDecodeError: 'gbk' codec can't decode bytes in position 316-317: illegal multibyte sequence


这可能是你没有设置程序的编码,如在最开始加上:


  1. #coding=gbk
复制代码


  1. pinyin +''
复制代码


当然是一个字符串了。因此这个方法需要使用unicode。而get_next_char()不是指的pinyin这个串,是指你要处理的字典翻译文本。
作者: tikico    时间: 2006-03-08 14:48
还是不行,不知道怎么能让汉语拼音能像普通字母那样处理,
如:str1='a b'
str1[i] = ''a',那就简单多了。郁闷一个星期了。
作者: limodou    时间: 2006-03-08 14:59
不是已经说了嘛,使用unicode呀。因为unicode的一个字符就表示一个完整的汉字。而gbk汉字的话两个字符是一个汉字。如果使用gbk来处理的话,那么你要两个字符两个字符来处理,这样才是完整的。 
作者: tikico    时间: 2006-03-08 16:08
原帖由 limodou 于 2006-3-8 14:59 发表
不是已经说了嘛,使用unicode呀。因为unicode的一个字符就表示一个完整的汉字。而gbk汉字的话两个字符是一个汉字。如果使用gbk来处理的话,那么你要两个字符两个字符来处理,这样才是完整的。 

估计您也烦躁了,我自以为不是太笨,找了一些python中unicode的资料,还是不得要领。简单直接点问您吧,我有一行文本:
【牴牾】 dǐwǔ 抵牾 contradiction; conflict
保存在test.txt中,请问您要如何读取,然后如何操作(能把汉字和拼音像abcd一样处理),最好您就直接写段代码,将test.txt中的文本变成:
【牴牾】 <p>dǐwǔ</p> 抵牾 contradiction; conflict
我菜不是问题,问题是菜了还不承认。您也不要再教导了,如果我看不懂代码再来请教,谢谢!
作者: limodou    时间: 2006-03-08 17:19

  1. #coding=gbk

  2. a = u'【牴牾】 dǐwǔ 抵牾 contradiction; conflict 【牴牾】 dǐwǔ 抵牾 contradiction; conflict'

  3. FLAG_WORD = 1
  4. FLAG_PINYIN = 2
  5. FLAG_ZH = 3
  6. FLAG_EN = 4
  7. tags = {
  8.     FLAG_WORD:('<w>', '</w>'),
  9.     FLAG_PINYIN:('<p>', '</p>'),
  10.     FLAG_ZH:('<zh>', '</zh>'),
  11.     FLAG_EN:('<en>', '</en>')
  12. }

  13. flag = -1
  14. i = 0
  15. s = [] #结果
  16. buf = [] #缓冲区
  17. pinyin = u'dǐwǔ' + ' '
  18. last_begin_tag = ''
  19. last_flag = flag
  20. while i<len(a):
  21.     if a[i] == u'【': #开始处理单词
  22.         #判断buf是否有内容,有则输出,同时注意结束tag
  23.         if buf:
  24.             b, e = tags[last_flag]
  25.             buf.append(e)
  26.             s.append(''.join(buf))
  27.             buf = []
  28.         flag = FLAG_WORD
  29.         buf.append(a[i])
  30.         i += 1
  31.         while i < len(a) and a[i] != u'】':
  32.             buf.append(a[i])
  33.             i += 1
  34.         #将】也加到缓冲区中
  35.         buf.append(a[i])
  36.         i += 1
  37.         b, e = tags[flag]
  38.         s.append(b + ''.join(buf) + e)
  39.         
  40.         #开始处理拼音
  41.         flag = FLAG_PINYIN
  42.         buf = []
  43.         while i<a[i] and a[i] in pinyin:
  44.             buf.append(a[i])
  45.             i += 1
  46.         b, e = tags[flag]
  47.         s.append(b + ''.join(buf).strip() + e) #使用strip去掉多余的首尾空格
  48.         last_flag = flag
  49.         buf = []
  50.         continue
  51.     else:
  52.         if ord(a[i]) < 127: #英文
  53.             flag = FLAG_EN
  54.         else:
  55.             flag = FLAG_ZH
  56.         if last_flag != flag:
  57.             #判断是否上一个标志是否是中或英文,如果不是表示第一次进入则输出开始tag,
  58.             #否则先输出上一个的结束tag,然后是一个开始tag
  59.             if last_flag in (FLAG_ZH, FLAG_EN):
  60.                 b, e = tags[last_flag]
  61.                 buf.append(e)
  62.             b, e = tags[flag]
  63.             buf.append(b)
  64.             buf.append(a[i])
  65.             last_flag = flag
  66.         else:
  67.             buf.append(a[i])
  68.     i += 1

  69. if buf:
  70.     b, e = tags[last_flag]
  71.     buf.append(e)
  72.     s.append(''.join(buf))
  73.         
  74. print ''.join([x.encode('gbk') for x in s])
复制代码


这里我没有从文件中读出文本,直接使用了一个unicode串来处理的。而且可以处理多个汉语词组。因此最开始可以:

text = file('a.txt').read() #这样把文本全部读出来
然后转化为unicode

a = unicode(text, 'gbk')
作者: tikico    时间: 2006-03-08 17:45
limodou大侠真是热心,好感动!您的代码已经超出我的要求,呵呵,谢谢先!
您的代码肯定是没问题的,但我按您的提示,修改a:

  1. text=file('outputfile.txt').read()
  2. a= unicode(text,'gbk')
复制代码

结果报错:

  1. Traceback (most recent call last):
  2.   File "C:/Python24/limodou.py", line 5, in -toplevel-
  3.     a= unicode(text,'gbk')
  4. UnicodeDecodeError: 'gbk' codec can't decode bytes in position 266-267: illegal multibyte sequence
复制代码

这也是我一直郁闷的,我原来一直用的是直接定义字符串,调试unicode没问题,但是一旦读文件,再转unicode就报错,是不是我的编译环境问题啊?
作者: limodou    时间: 2006-03-08 17:47
有可能是你的文件有无法识别的汉字。可以考虑把示例的文本写入一个文件,用它先试一下。如果没有问题,那就考虑文件中的汉字有非法的。那可以考虑使用utf-8来处理了。但代码中有一处要转为gbk编码的也要转为utf-8才行。
作者: tikico    时间: 2006-03-08 18:45
标题: 回复 29楼 limodou 的帖子
好的,我再试试!
作者: tikico    时间: 2006-03-09 10:26
原帖由 limodou 于 2006-3-8 17:47 发表
有可能是你的文件有无法识别的汉字。可以考虑把示例的文本写入一个文件,用它先试一下。如果没有问题,那就考虑文件中的汉字有非法的。那可以考虑使用utf-8来处理了。但代码中有一处要转为gbk编码的也要转为utf-8 ...

我就把
【牴牾】 dǐwǔ 抵牾 contradiction; conflict
存成文本也不行,错误一样,应该不是修改编码能解决的,因为直接处理上面一行没问题。
还是试一下,改成了utf8,cp936,果然还是不行,报错:


  1. Traceback (most recent call last):
  2.   File "C:\Python24\limodou.py", line 5, in -toplevel-
  3.     a = unicode(test,'utf8')
  4.   File "C:\Python24\lib\encodings\utf_8.py", line 16, in decode
  5.     return codecs.utf_8_decode(input, errors, True)
  6. UnicodeDecodeError: 'utf8' codec can't decode byte 0xa0 in position 0: unexpected code byte
复制代码

作者: limodou    时间: 2006-03-09 12:12
存成文本的编码要与你转码的编码要一致。比如使用utf-8转码,那文本就需要是utf-8的。如果是gbk转码,那文本就需要是gbk的。不是简单地存一下就行的。
作者: tikico    时间: 2006-03-09 14:49
标题: 回复 32楼 limodou 的帖子
基本搞定了,感谢limodou大侠这么久以来的耐心的教授。
明年央视《感动中国》我题名您上,再次感谢!
作者: limodou    时间: 2006-03-09 16:09
希望你的python能更上一层楼。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2