我有一个库,其中包含一个函数,该函数根据多个正则表达式检查各种输入数据,以确保数据有效。该函数既可以通过CGI脚本从Web表单(通过lighttpd)接收输入,也可以从sqlite数据库读取输入(根据gammu-smsd收到的SMS,将输入放在那里)。 p>
输入有时是英语,有时是印地语,即Devnagari脚本。它应始终使用UTF-8编码。我一直在努力使用python的re和regex模块,这对于将字符类正确匹配到Devnagari字符似乎是错误的(你可以看到一个例子here - 在这种情况下使用正则表达式而不是重新修复问题,但我从那以后也遇到了正则表达式的麻烦)。命令行'grep'显得更加可靠和准确。因此,我已经使用子进程调用将必要的字符串传递给grep,如下所示:
def invalidfield(datarecord,msgtype):
for fieldname in datarecord:
if (msgtype,fieldname) in mainconf["MSG_FORMAT"]:
try:
check = subprocess.check_output("echo '" + datarecord[fieldname] + "' | grep -E '" + mainconf["MSG_FORMAT"][msgtype,fieldname] + "'",shell=True)
except subprocess.CalledProcessError:
return fieldname
return None
现在,让我们尝试使用以下字符串作为输入:न्याज अहमद्
和以下正则表达式进行检查:^[[:alnum:] .]*[[:alnum:]][[:alnum:] .]*$
奇怪的是,当从数据库中读取完全相同的输入时,清除此正则表达式(应该如此)并且函数正确返回。但是当通过webform输入相同的字符串时,subprocess.check_out失败并显示以下错误:
File "/usr/lib/python2.7/subprocess.py", line 537, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1259, in _execute_child
raise child_exception
TypeError: execv() arg 2 must contain only strings
我无法弄清楚发生了什么。我使用this script修改了我的lighttpd.conf,至少应该确保lighttpd.conf使用utf-8字符集。我还使用了chardet模块并对webform的输入运行了chardet.detect。我明白了:{'confidence': 1.0, 'encoding': 'ascii'}{'confidence': 0.99, 'encoding': 'utf-8'}
根据this answer我尝试用datarecord[fieldname]
替换上面的unicode(datarecord[fieldname]).encode('utf8')
,并首先尝试使用'ascii'编解码器解码datarecord [fieldname]。后者因通常的“序数不在范围内”错误而失败。
这里出了什么问题?我只是想不出来!
答案 0 :(得分:3)
在这种情况下,您希望避免使用echo
;将您的输入直接写入stdin
对象的Popen()
管道。
确保您的环境设置为正确的语言环境,以便grep
知道将输入解析为UTF-8:
env = dict(os.environ)
env['LC_ALL'] = 'en_US.UTF-8'
p = subprocess.Popen(['grep', '-E', mainconf["MSG_FORMAT"][msgtype,fieldname]], stdin=subprocess.PIPE, env=env)
p.communicate(datarecord[fieldname])
if p.returncode:
return fieldname
答案 1 :(得分:0)
只是为了添加Martijn Pieters的答案,他建议的解决方案在输入字符串为空的情况下会失败(与原始函数不同,即使正则表达式允许,grep也无法匹配空字符串) 。因此,原始函数的完整实现将是:
if (msgtype,fieldname) in mainconf["MSG_FORMAT"]:
if not datarecord[fieldname]:
if not regex.search(mainconf["MSG_FORMAT"][msgtype,fieldname],datarecord[fieldname],regex.UNICODE):
return fieldname
else:
curenv = os.environ
curenv['LC_ALL']="en_US.UTF-8"
check = subprocess.Popen(['grep','-E', mainconf["MSG_FORMAT"][msgtype,fieldname]], stdin=subprocess.PIPE, env=curenv, stderr=subprocess.STDOUT,stdout=subprocess.PIPE)
check.communicate (datarecord[fieldname])
if check.returncode:
return fieldname
return None
这适用于regex
匹配在空字符串上正常工作。