【问题标题】:Python: Removing particular character (u"\u2610") from stringPython:从字符串中删除特定字符(u“\ u2610”)
【发布时间】:2013-10-31 23:19:18
【问题描述】:

我一直在努力解决 Python 中的解码和编码问题,但我不知道如何解决我的问题。我正在遍历显然用 utf-8 编码的 xml 文本文件 (sample),使用 Beautiful Soup 解析每个文件,然后查看文件中的任何句子是否包含来自两个不同单词列表的一个或多个单词.因为 xml 文件来自 18 世纪,所以我需要保留 xml 中的破折号。下面的代码可以很好地做到这一点,但它也保留了我希望删除的讨厌的框字符。我相信方框字符是this character

(您可以在上面示例文件的第 3682 行找到我希望删除的字符的示例。在此网页上,该字符看起来像一个“或”管道,但是当我在 Komodo 中读取 xml 文件时,它看起来像一个框。当我尝试将该框复制并粘贴到搜索引擎中时,它看起来像一个“或”管道。但是,当我打印到控制台时,该字符看起来像一个空框。)

总而言之,下面的代码运行没有错误,但它打印出我想删除的空框字符。

for work in glob.glob(pathtofiles):

    openfile = open(work)
    readfile = openfile.read()
    stringfile = str(readfile)

    decodefile = stringfile.decode('utf-8', 'strict') #is this the dodgy line?
    soup = BeautifulSoup(decodefile)

    textwithtags = soup.findAll('text')

    textwithtagsasstring = str(textwithtags)

    #this method strips everything between anglebrackets as it should
    textwithouttags = stripTags(textwithtagsasstring)

    #clean text
    nonewlines = textwithouttags.replace("\n", " ")
    noextrawhitespace = re.sub(' +',' ', nonewlines)

    print noextrawhitespace #the boxes appear

我尝试使用删除框

noboxes = noextrawhitespace.replace(u"\u2610", "")

但是 Python 抛出了一个错误标志:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 280: ordinal not in range(128)

有谁知道如何从 xml 文件中删除这些框?如果其他人可以提供任何帮助,我将不胜感激。

【问题讨论】:

  • 哇,谁在 18 世纪生成 XML 文件?莱布尼茨?
  • (确实是莱布尼茨,但牛顿击败了他。)
  • 同时,str(readfile) 应该做什么?文件上的read 方法已经返回str
  • U+2610 的有趣之处在于它应该是一个empty ballot box,但在许多字体中它并不存在,这意味着它被打印为一个缺少字符的空框,这很难区分。 (一些画线和其他空框字符也有类似的问题。)

标签: python xml string unicode ascii


【解决方案1】:

试试这个:

noextrawhitespace.replace("\\u2610", "") 

我认为你只是缺少那个额外的'\'

这也可能有效。

print(noextrawhitespace.decode('unicode_escape').encode('ascii','ignore'))

【讨论】:

  • 非常感谢@jramirez,但我相信.rstrip() 只会删除 noextrawhitespace 对象之后的任何尾随空格。我相信我需要像 .replace(boxcharacter, "")re.sub() 这样的方法来消除盒子字符。
  • 再次感谢@jramirez。这种方法确实消除了方框,但它也消除了我希望保留的破折号。有没有办法保留破折号但消除盒子?非常感谢您的建议。
  • 大声笑我再次编辑了答案。让我知道这是否有效。
  • 再次感谢您,@jramirez。我认为我们已经接近了,但也许我错误地识别了这个角色,因为框不断出现,即使使用您识别的替换方法也是如此。有没有一种万无一失的方法可以让我确定哪个角色困扰着我?当我尝试将字符复制并粘贴到搜索引擎中时,它看起来像一个“或”运算符,但搜索不会产生任何命中。最令人费解...
  • for c in noextrawhitespace: print hex(c)
【解决方案2】:

问题是你混合了unicodestr。每当你这样做时,Python 必须将一个转换为另一个,这是通过使用 sys.getdefaultencoding(),通常是 ASCII,这几乎不是你想要的。*

如果异常来自这一行:

noboxes = noextrawhitespace.replace(u"\u2610", "")

...修复很简单...除了您必须知道noextrawhitespace 应该是unicode 对象还是UTF-8 编码str 对象)。如果是前者,那就是:

noboxes = noextrawhitespace.replace(u"\u2610", u"")

如果是后者,就是这样:

noboxes = noextrawhitespace.replace(u"\u2610".encode('utf-8'), "")

但实际上,您必须使代码中的所有字符串保持一致;将两者混合起来会在比这更多的地方引起问题。


由于我没有要测试的 XML 文件,所以我自己编写了:

<xml>
    <text>abc&#9744;def</text>
</xml>

然后,我将这两行添加到代码的底部(并在顶部添加了一点,以便打开我的文件,而不是使用任何内容):

noboxes = noextrawhitespace.replace(u"\u2610".encode('utf-8'), "")
print noboxes

现在的输出是:

[<text>abc☐def</text>]
[<text>abc☐def</text>]
[<text>abcdef</text>]

所以,我认为这就是你想要的。


* 当然有时你想要 ASCII……但通常不是你有 unicode 对象的时候……

【讨论】:

  • 非常感谢您的回复,@abarnert。我花了一些时间,不得不做一些外部研究,似乎当脚本到达打印行时,文本对象已被转换回 ascii 字符串(因为textwithtagsasstring 行,它将文本转换为字符串,以便我可以运行 removeNonAscii() 方法,该方法将字符串作为输入。但问题是,我尝试了 所有三种 您建议的方法,但是讨厌的框仍在打印到控制台。我错过了什么?
  • @duhaime:您的真正意思是“转换回 ascii 字符串”还是“转换回 UTF-8 字符串”?因为后者你可以处理;前者,太晚了……不管怎样,你试过我的测试代码了吗?对你起作用吗?您的 XML 是否看起来像这样,或者它是否直接存储了未转义字符的 Unicode?如果是后者,你确定它是 UTF-8 吗? (文件中的实际字节数是多少?)
  • 啊,我用print isinstance(noextrawhitespace, unicode)得到“False”,然后用import chardetprint chardet.detect(noextrawhitespace)得到“{'confidence': 0.99, 'encoding': 'utf-8'}” .然后我使用我的 IDE 编辑我的“当前文件设置”并选择“utf-8”作为我的编码。然后我可以简单地使用noboxes = noextrawhitespace.replace('∣', ''),除了这个盒子看起来像IDE中的一个盒子。然后 noboxes 按预期打印。这是盗版解决方案吗?会不会带来意想不到的问题?我非常感谢您的 cmets。
  • @duhaime:首先,如果你想将非 ASCII 文字放入你的代码中,你需要添加一个coding declaration 来告诉 Python 文件是 UTF-8,而不仅仅是告诉你的 IDE该文件是UTF-8。实际上,如果您不使用 Unicode 文字,事情会简单得多。在某些情况下,可读性的好处是值得的,但在这种情况下,我认为它的可读性会less。想象一下,在 6 个月内使用您的代码并试图找出 '☐'u'\u2610'.encode('utf-8')'\xe2\x98\x90';第一个不是最难的吗?
【解决方案3】:

阅读您的示例,以下是文档中的非 ASCII 字符:

0x2223 DIVIDES
0x2022 BULLET
0x3009 RIGHT ANGLE BRACKET
0x25aa BLACK SMALL SQUARE
0x25ca LOZENGE
0x3008 LEFT ANGLE BRACKET
0x2014 EM DASH
0x2026 HORIZONTAL ELLIPSIS

\u2223 是第 3682 行中的实际字符,它被用作软连字符。其他用于标记难以辨认的字符,例如:

<GAP DESC="illegible" RESP="oxf" EXTENT="4+ letters" DISP="\u2022\u2022\u2022\u2022\u2026"/>

这里有一些代码可以执行您的代码正在尝试的操作。确保以 Unicode 处理:

from bs4 import BeautifulSoup
import re

with open('k000039.000.xml') as f:
    soup = BeautifulSoup(f)  # BS figures out the encoding

text = u''.join(soup.strings)      # strings is a generator for just the text bits.
text = re.sub(ur'\s+',ur' ',text)  # Simplify all white space.
text = text.replace(u'\u2223',u'') # Get rid of the DIVIDES character.
print text

输出:

[[截断]] 也认为我自己是新郎。扣上。我怀疑基奇不会找到他这样的人。 [旁白] 萨戈夫人。好吧,——可怜的凯基一定要表现得很好,或者她已经完全失去了帕迪的宠爱。我要为《财富》的这番怨恨吗?——不。我很高兴我被原谅了。一些邻居的妻子最近才出现,当配偶离开他们时,他们所有的朋友都飞走了。那么你们所有的妻子会避免我的命运。对您目前的状态 FINIS 保持满意。

【讨论】:

  • 感谢您的反馈,@Mark Tolonen。我尝试实施您的建议,这似乎比我的 Rube Goldberg 方法快得多,但是当我尝试写入磁盘时出现错误。我正在尝试write() 几个制表符分隔的字段,后跟'\n' 每次满足条件时,但我收到一条尝试写入'\n'的行的错误消息:UnicodeEncodeError: 'ascii' codec can't encode character u'\u2014' in position 0: ordinal not in range(128)。您碰巧知道我如何解决该错误吗?如果您能提供任何见解,我将不胜感激。
  • 使用codecs.open 函数打开文件并指定编码。这是将 Unicode 写入文件的正确方法。
猜你喜欢
  • 1970-01-01
  • 2017-07-09
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
相关资源
最近更新 更多