ホームページ  >  記事  >  バックエンド開発  >  Python で珍しい単語を検出する方法

Python で珍しい単語を検出する方法

高洛峰
高洛峰オリジナル
2017-03-11 10:53:532648ブラウズ

最近仕事で、フィールドに珍しい単語や ~!@#$%^&* などの不正な文字が含まれているかどうかを検出する必要があるという要件に遭遇しました。インターネットで情報を検索して解決しました。解決プロセスとサンプルコードを共有します。必要な方は参考にしてください。以下を見てみましょう。

解決策

最初に思い浮かぶのは、Python の正規表現を使用して不正な文字と一致し、不正なレコードを見つけることです。しかし、理想は常に満たされていますが、現実は残酷です。実装プロセス中に、文字エンコーディングと Python の内部文字列表現に関する知識が不足していることがわかりました。この間、たくさんの落とし穴を経験し、最終的にはまだ曖昧な部分もありましたが、最終的には全体的に明確な理解を得ることができました。将来同じ状況に陥ることを避けるために、ここにあなたの経験を記録してください。

以下のテスト環境は、ArcGIS 10.3 に付属の Python 2.7.8 環境です。他の Python 環境も適切であるという保証はありません。

Python正規表現

Pythonの正規関数は、主に3つの関数を使用する組み込みのre関数ライブラリによって提供されます。 re.compile() は再利用可能な正規表現を提供し、 match() 関数と search() 関数は一致する結果を返します。 違いは次のとおりです。 code> match() は指定された位置から照合を開始し、 search() は一致する文字列が見つかるまで指定された位置から逆方向に検索します。たとえば、次のコードでは、 match_result は最初の文字 f から照合を開始し、照合が失敗した場合は null 値を返します。 search_result は f から最初の文字まで逆方向に検索します。一致する文字 a が見つかり、group() 関数を通じて一致結果を文字 a として出力します。 re.compile() 提供可重用的正则表达式,match() search() 函数返回匹配结果,两者之间的区别在于: match() 从指定位置开始匹配,search() 会从指定位置向后搜索直到找到匹配字符串。例如下面的代码中,match_result 从第一个字符 f 开始匹配,匹配失败返回空值;search_result 从 f 开始向后搜索,直到找到第一个匹配的字符 a, 然后通过 group() 函数输出匹配结果为字符 a。

import re

pattern = re.compile('[abc]')
match_result = pattern.match('fabc')
if match_result:
 print match_result.group()

search_result = pattern.search('fabc')
if search_result:
 print search_result.group()

以上的实现方式需要先编译一个 pattern,然后再进行匹配。实际上,我们可以直接利用 re.match(pattern, string) 函数来实现相同的功能。但是直接匹配的方式没有先编译再匹配的方式灵活,首先是正则表达式没办法重用,如果大量数据进行同一模式匹配,意味着每次都需要内部编译,造成性能损失;另外,re.match() 函数没有 pattern.match() 功能强大,后者可以指定从哪个位置开始匹配。

编码问题

了解 python 正则的基本功能后,剩下的事情就是找到一个合适的正则表达式来匹配生僻字和非法字符。非法字符很简单,采用以下 pattern 就可以实现匹配:

pattern = re.compile(r'[~!@#$%^&* ]')

然而对于生僻字的匹配,着实难倒了我。首先是对于生僻字的定义,什么样的字算生僻字?经过咨询项目经理,规定非 GB2312 的字符属于生僻字。接下来的问题是,如何匹配 GB2312 字符?

经过查询,GB2312 的范围是 [xA1-xF7][xA1-xFE] ,其中汉字区的范围是 [xB0-xF7][xA1-xFE] 。因此,添加生僻字匹配后的表达式为:

pattern = re.compile(r'[~!@#$%^&* ]|[^\xA1-\xF7][^\xA1-\xFE]')

问题似乎是顺理得当地解决了,然而我还是 too simple too naive 。由于要判断的字符串都是从图层文件读取的,arcpy 贴心地将读取的字符编码为 unicode 格式。因此,我需要找出 GB2312 字符集在 unicode 中的编码范围。但现实是,GB2312 字符集在 unicode 中的分布并不是连续的,使用正则表示这个范围必定是非常复杂的。使用正则表达式匹配生僻字的构想,似乎陷入了死胡同。

解决方案

既然提供的字符串是 unicode 格式,那么我可不可以将其转换为 GB2312 再进行匹配呢?实际上是不行,因为 unicode 字符集要远大于 GB2312 字符集,因此 GB2312 => unicode 总是可以实现的,而反过来 unicode => GB2312 不一定能成功。

这突然为我提供了另外一种思路,假设一个字符串的 unicode => GB2312 转换会失败,那么是不是恰恰说明了它不属于 GB2312 字符集?所以,我使用 unicode_string.encode('GB2312')

import re

def is_rare_name(string):
 pattern = re.compile(u"[~!@#$%^&* ]")
 match = pattern.search(string)
 if match:
 return True

 try:
    string.encode("gb2312")
  except UnicodeEncodeError:
   return True

  return False
上記の実装では、最初にパターンをコンパイルしてからマッチングする必要があります。実際、 re.match(pattern, string) 関数を直接使用して、同じ機能を実現できます。ただし、直接一致する方法は、最初にコンパイルしてから一致するほど柔軟ではありません。まず、大量のデータが同じパターンで一致する場合は、毎回内部コンパイルが必要になります。さらに、re .match() 関数は、一致を開始する場所を指定できる pattern.match() ほど強力ではありません。

エンコーディングの問題

Python 正規表現の基本的な機能を理解したら、残っているのは、珍しい単語や不正な文字に一致する適切な正規表現を見つけることだけです。不正な文字のマッチングは非常に簡単で、次のパターンを使用できます: rrreee

🎜🎜 しかし、珍しい文字のマッチングには本当に困惑します。まず、珍しい単語の定義ですが、どのような単語が珍しいと考えられますか。プロジェクトマネージャーと相談した結果、GB2312以外のキャラクターはレアキャラクターであると判断されました。次の質問は、GB2312 文字をどのように照合するかということです。 🎜🎜クエリ後、GB2312の範囲は [xA1-xF7][xA1-xFE] 、漢字領域の範囲は [xB0-xF7][xA1-xFE] 。したがって、稀な単語の一致を追加した後の式は次のようになります。 🎜🎜🎜rrreee🎜🎜🎜 問題は論理的に解決されているように見えますが、私はまだ単純すぎて世間知らずすぎます。判定対象の文字列はすべてレイヤー ファイルから読み取られるため、arcpy は読み取った文字を慎重に Unicode 形式にエンコードします。したがって、Unicode における GB2312 文字セットのエンコード範囲を調べる必要があります。しかし実際には、Unicode における GB2312 文字セットの分布は連続的ではなく、正規表現を使用してこの範囲を表すのは非常に複雑になるはずです。正規表現を使用して珍しい単語を照合するというアイデアは行き詰まったようです。 🎜🎜🎜🎜解決策🎜🎜🎜🎜提供された文字列はUnicode形式なので、GB2312に変換して一致させることはできますか?実際には、これは不可能です。Unicode 文字セットは GB2312 文字セットよりもはるかに大きいため、 GB2312 => unicode は常に実現可能であり、逆に unicode => GB2312 は実現可能です。 >成功しない可能性があります。 🎜🎜これにより、突然別のアイデアが浮かび上がりました。文字列の unicode => GB2312 変換が失敗すると仮定すると、それは GB2312 文字セットに属さないということなのでしょうか。そこで、unicode_string.encode('GB2312') 関数を使用して文字列を変換し、まれな文字を識別するために UnicodeEncodeError 例外をキャッチしました。 🎜🎜🎜🎜最終的なコードは次のとおりです: 🎜🎜🎜🎜🎜rrreee🎜🎜🎜🎜🎜概要🎜🎜🎜

以上がPython で珍しい単語を検出する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。