Python 2.x:如何自动化强制使用Unicode而不是字符串?

5
如何自动化测试以确保Python 2.x代码库不包含字符串实例(仅包含unicode实例)?
例如。
我能否在代码内部执行此操作?
是否有静态分析工具具有此功能?
编辑:
我想为Python 2.5应用程序使用它,但事实证明这不是真正可能的,因为:
1.2.5不支持“unicode_literals” 2.kwargs字典键不能是unicode对象,只能是字符串
因此,即使出于不同的原因,我也接受说这是不可能的答案 :)

2
from __future__ import unicode_literals - Ignacio Vazquez-Abrams
@Ignacio,听起来很有前途!但是如果代码还导入了不知道它的第三方模块,这会阻碍它吗? - Ian Mackinnon
不,通过 __future__ 的编译器指令只会影响当前模块。 - Ignacio Vazquez-Abrams
@Ignacio,您是否想将此作为答案添加,以便我可以接受它? - Ian Mackinnon
3个回答

1

我觉得你需要使用一个真正的Python解析器来解析代码。然后,你需要深入分析解析器生成的AST,看看它是否包含任何字符串字面量。

看起来Python自带一个解析器。从这个文档中,我得到了以下代码示例:

import parser
from token import tok_name

def checkForNonUnicode(codeString):
    return checkForNonUnicodeHelper(parser.suite(codeString).tolist())

def checkForNonUnicodeHelper(lst):
    returnValue = True
    nodeType = lst[0]
    if nodeType in tok_name and tok_name[nodeType] == 'STRING':
        stringValue = lst[1]
        if stringValue[0] != "u": # Kind of hacky. Does this always work?
            print "%s is not unicode!" % stringValue
            returnValue = False

    else:
        for subNode in [lst[n] for n in range(1, len(lst))]:
            if isinstance(subNode, list):
                returnValue = returnValue and checkForNonUnicodeHelper(subNode)

    return returnValue

print checkForNonUnicode("""
def foo():
    a = 'This should blow up!'
""")
print checkForNonUnicode("""
def bar():
    b = u'although this is ok.'
""")

打印输出

'This should blow up!' is not unicode!
False
True

现在文档字符串不是Unicode,但应该被允许,因此您可能需要做一些更复杂的事情,例如from symbol import sym_name,在那里您可以查找哪些节点类型用于类和函数定义。然后,第一个子节点只是一个字符串,即不是赋值或其他内容的一部分,应该被允许不是Unicode。

好问题!

编辑

只是一个跟进评论。方便起见,parser.suite实际上不会评估您的Python代码。这意味着您可以在不担心命名或导入错误的情况下运行此解析器来处理Python文件。例如,假设您有一个包含以下内容的myObscureUtilityFile.py

from ..obscure.relative.path import whatever

你可以

checkForNonUnicode(open('/whoah/softlink/myObscureUtilityFile.py').read())

你不需要解析代码,只需生成词元即可;如果任何词元不是Unicode,则您的文件未通过测试。如果您的文件包含“外部引用”(例如,from_future),则在没有解析所有涉及的文件的情况下,您无法知道,但我怀疑这不是您问题定义的一部分。 - Ira Baxter

1

你不能强制所有字符串都是Unicode的;即使在模块中使用了from __future__ import unicode_literals,字节字符串仍然可以写成b'...',就像在Python 3中一样。

曾经有一个选项可以用来全局获取与unicode_literals相同的效果:命令行选项-U。但是,在2.x系列早期就被放弃了,因为它基本上破坏了每个脚本。

你的目的是什么?废除字节字符串并不可取。它们并不“坏”,Unicode字符串也不普遍“更好”;它们是两种不同的类型,你需要同时使用它们。字节字符串肯定需要用于访问二进制文件和网络服务。

如果你想准备过渡到Python 3,最好的方法是对于所有你真正想要作为字节的字符串使用b'...',对于本质上是Unicode的字符串使用u'...'。默认字符串'...'格式可用于其他所有地方,即你不关心和/或Python 3是否更改了默认字符串类型的地方。


1
目的是我正在编写一个多语言应用程序,必须在2.5中运行,并且我经常忘记在不需要Unicode的字符串上键入“u”,但如果它们被编辑可能会需要。我知道在许多情况下普通字符串都可以,但在这种情况下,我需要一些帮助来保持一致并清楚地表达我的意图。 - Ian Mackinnon

0

我们的SD源代码搜索引擎(SCSE)可以直接提供此结果。

SCSE提供了一种快速搜索大量文件的方法,使用语言结构来实现精确查询和最小化误报。它处理各种语言,甚至同时处理Python。GUI显示搜索命中和包含所选命中的实际文本页面。

它使用源语言的词汇信息作为查询的基础,由各种语言关键字和模式令牌组成,匹配不同的内容语言元素。SCSE知道语言中可用的词素类型。您可以搜索通用标识符(使用查询令牌I)或与某个正则表达式匹配的标识符。同样,您可以搜索通用字符串(使用查询令牌“S”表示“任何类型的字符串文字”)或特定类型的字符串(对于Python,包括“UnicodeStrings”,非Unicode字符串等,这些共同构成了Python事物的集合“S”)。

因此,一个搜索:

 'for' ... I=ij*

查找关键字“for”附近(“…”)前缀为“ij”的标识符,并显示所有命中项。忽略特定于语言的空格,包括换行和注释。

一个简单的搜索:

  S

查找所有字符串字面量。这通常是一个相当大的集合 :-}

搜索

 UnicodeStrings

查找所有以Unicode字符串(u“…”)词法定义的字符串字面量。

您想要的是所有不是Unicode字符串的字符串。SCSE提供了一个“减去”运算符,它可以减去与另一种重叠的一种命中。因此,您的问题“哪些字符串不是Unicode”可以简洁地表达为:

  S-UnicodeStrings

所有显示的结果都将是非Unicode字符串,这是您确切的问题。

SCSE提供日志记录功能,以便您可以记录命中情况。您可以从命令行运行SCSE,启用脚本查询以获取答案。将其放入命令脚本中将提供一个直接给出答案的工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接