よし、座って計算した。plsは私に腹を立てないでください。ΤΖΩΤΖΙΟΥの解決策について具体的に議論することに答えますが、これはコメント内に押し込むのがやや難しいので、このようにさせてください。実際、OPの質問に関連するいくつかの考慮事項も放映します。
最初に、私は ΤΖΩΤΖΙΟΥ と彼のアプローチの優雅さ、正確さ、実行可能性について話し合ってきました。提案のように見えますが、置換ペアを格納するためのレジスタとして (本質的に順序付けされていない) 辞書を使用していますが、実際には一貫して正しい結果を返します。これはitertools.starmap()
、以下の 11 行目の への呼び出しが、2 番目の引数として、単一の文字/バイトのペア (詳細は後述) のイテレータを取得するため[ ( 'h', 'h', ), ( 'e', 'e', ), ( 'l', 'l', ), ... ]
です。これらの文字/バイトのペアは、最初の引数replacer.get
が繰り返し呼び出されるものです。'>'
最初に変換され'>'
、次に不注意で再び変換される状況に遭遇する機会はありません。'>'
これは、各文字/バイトが置換のために 1 回だけ考慮されるためです。したがって、この部分は原則として問題なく、アルゴリズム的に正しいです。
次の質問は実行可能性であり、これにはパフォーマンスの検討が含まれます。重要なタスクが厄介なコードを使用して 0.01 秒で正しく完了し、素晴らしいコードを使用して 1 秒で完了する場合、実際には厄介なコードが望ましいと見なされる可能性があります (ただし、1 秒の損失が実際に耐えられない場合に限ります)。テストに使用したコードは次のとおりです。さまざまな実装が含まれています。それはpython 3.1で書かれているので、それ自体が素晴らしい識別子にUnicodeギリシャ文字を使用できます(zip
py3kではpy2と同じを返しますitertools.izip
):
import itertools #01
#02
_replacements = { #03
'&': '&', #04
'<': '<', #05
'>': '>', #06
'"': '"', #07
"'": ''', } #08
#09
def escape_ΤΖΩΤΖΙΟΥ( a_string ): #10
return ''.join( #11
itertools.starmap( #12
_replacements.get, #13
zip( a_string, a_string ) ) ) #14
#15
def escape_SIMPLE( text ): #16
return ''.join( _replacements.get( chr, chr ) for chr in text ) #17
#18
def escape_SIMPLE_optimized( text ): #19
get = _replacements.get #20
return ''.join( get( chr, chr ) for chr in text ) #21
#22
def escape_TRADITIONAL( text ): #23
return text.replace('&', '&').replace('<', '<').replace('>', '>')\ #24
.replace("'", ''').replace('"', '"') #25
タイミング結果は次のとおりです。
escaping with SIMPLE took 5.74664253sec for 100000 items
escaping with SIMPLE_optimized took 5.11457801sec for 100000 items
escaping TRADITIONAL in-situ took 0.57543013sec for 100000 items
escaping with TRADITIONAL took 0.62347413sec for 100000 items
escaping a la ΤΖΩΤΖΙΟΥ took 2.66592320sec for 100000 items
「伝統的な」方法が「すぐに醜くなり、アルゴリズムのパフォーマンスが低下するように見える」という元の投稿者の懸念は、このコンテキストに入れると部分的に不当に見えることが判明しました. 実際に最高のパフォーマンスを発揮します。関数呼び出しに隠しておくと、8% のパフォーマンスの低下が見られます (「メソッドの呼び出しはコストがかかります」が、一般的にはそれでも行う必要があります)。比較すると、ΤΖΩΤΖΙΟΥ の実装は、従来の方法の約 5 倍の時間がかかります。これは、python の長年にわたって磨かれた最適化された文字列メソッドと競合しなければならない複雑さがより高いことを考えると、驚くことではありません。
ここにはさらに別のアルゴリズム、SIMPLE があります。私が見る限り、これは ΤΖΩΤΖΙΟΥ のメソッドが行うこととまったく同じです: テキスト内の文字/バイトを反復処理し、それぞれのルックアップを実行し、すべての文字/バイトを結合して、結果のエスケープされたテキストを返します。これを行う方法の 1 つは、かなり長くて謎めいた定式化を伴う場合であることがわかりますが、SIMPLE 実装は実際には一目で理解できます。
ただし、ここで本当につまずくのは、SIMPLE アプローチのパフォーマンスがいかに悪いかということです。従来の方法の約 10 倍遅く、ΤΖΩΤΖΙΟΥ の方法の 2 倍も遅いです。私はここで完全に途方に暮れています。おそらく、誰かがなぜそうすべきなのかを考え出すことができます。Python の最も基本的なビルディング ブロックのみを使用し、2 つの暗黙的な反復で動作するため、使い捨てリストやすべてを構築することは回避されますが、それでも遅く、その理由はわかりません。
ΤΖΩΤΖΙΟΥ のソリューションのメリットについて述べて、このコード レビューを締めくくります。私はそれを十分に明確にしましたが、コードが読みにくく、目の前のタスクには誇張されすぎています。しかし、それよりも重要なのは、彼が文字を扱う方法を見つけて、特定の小さな範囲の文字に対してバイトのような方法で動作することを確認することです。目の前のタスクでは確実に機能しますが、たとえばバイト文字列「ΤΖΩΤΖΙΟΥ」を反復処理するとすぐに、単一の文字を表す隣接するバイトを反復処理します。ほとんどの場合、これはまさに避けるべきことです。これがまさに、py3k の「文字列」が古い「Unicode オブジェクト」になり、古い「文字列」が「bytes」および「bytearray」になった理由です。2 シリーズから 3 シリーズへのコードの移行に費用がかかる可能性がある py3k の機能を 1 つ挙げるとしたら、それは py3k のこの 1 つの特性です。それ以来、すべてのエンコーディングの問題の 98% が解消されたばかりであり、私の動きを真剣に疑うような巧妙なハックはありません。上記のアルゴリズムは「概念的に8ビットクリーンでユニコードセーフ」ではありません.2010年であることを考えると、これは私にとって深刻な欠点です.