{"id":627,"date":"2010-06-09T20:01:45","date_gmt":"2010-06-09T16:01:45","guid":{"rendered":"http:\/\/robert.kolatzek.org\/wblog\/627\/die-problemloser-fur-python-web-unicode"},"modified":"2010-06-09T20:01:45","modified_gmt":"2010-06-09T16:01:45","slug":"die-problemloser-fur-python-web-unicode","status":"publish","type":"post","link":"https:\/\/blog.kolatzek.org\/wblog\/627\/die-problemloser-fur-python-web-unicode","title":{"rendered":"Die Probleml\u00f6ser f\u00fcr Python + Web + Unicode"},"content":{"rendered":"<p>Ich kann es mir nicht erkl\u00e4ren, warum es mir die meisten nicht zutrauen, etwas richtig gutes in Python zu bauen. (Die meisten Chefs halten es ohnehin f\u00fcr einen Witz, wenn man \u00fcber diese smarte Programmiersprache spricht. Dabei ist sie genauso einfach wie PHP und stark wie Java.) Ich bin auf das folgende Problem beim entwickeln eines intelligenten directory listeners f\u00fcr lightty (ein leichtgewichtiger Webserver) auf meinem <a href=\"http:\/\/de.wikipedia.org\/wiki\/SheevaPlug\">SheevaPlug<\/a> (embedded linux\/ubuntu on ARMv5TEL). Das Dateisystem wird in UTF-8 gelesen, darf aber nur als String an den WSGIServer \u00fcbergeben werden. So m\u00fcssen alle Unicode-Zeichen in HTML-entities bzw. url-encoding umgewandelt werden. L\u00f6sungen f\u00fcr dieses Problem sind im Netz leider rar. So lag es nahe, selber etwas zu entwickeln. Und das ist etwas richtig schickes!<\/p>\n<p><!--more--><\/p>\n<h3>Wie wandle ich unicode in URL-Kodierung?<\/h3>\n<pre class=\"brush: python;\">\ndef unicode2html(str):\n\tret=\"\"\n\tfor ch in unicode(str):\n\t\ti = ord(ch)\n\t\tif i &gt; 127:\n\t\t\tret=ret+u'&amp;#'+unicode(i)+';'\n\t\telse:\n\t\t\tret=ret+ch\n\treturn ret\n<\/pre>\n<p>Alles bis auf Klein- und Gro\u00dfbuchstaben wird in &#8222;%XY&#8220; umgewandelt. Man nennt es in PHP auch &#8222;rawurlencode&#8220;, weil man keine R\u00fccksicht auf Leerzeichen etc nimmt, die als &#8222;+&#8220; kodiert werden d\u00fcrfen.<\/p>\n<h4>Was kann man damit kodieren?<\/h4>\n<\/p>\n<ul>\n<li>Parameternamen<\/li>\n<li>Parameterwerte<\/li>\n<li>Dateinamen<\/li>\n<li>Ordnernamen<\/li>\n<\/ul>\n<p>&#8230;also einzelne Teile einer URL. \u00dcbergibt man ein &#8222;http:\/\/&#8230;\/etwas?abc=123&#8220;, wird alles ausnahmslos kodiert, so dass man die URL kaum wieder erkennt.<\/p>\n<h3>Wie wandle ich einen URL-kodierten String wieder zur\u00fcck?<\/h3>\n<pre class=\"brush: python;\">\n\nimport re\ndef url2unicode(str):\n\ttry:\n\t\tp = re.compile('.*(%([0-9A-F]{2,2})%([0-9A-F]{2,2})%([0-9A-F]{2,2})%([0-9A-F]{2,2})).*',re.I+re.S)\n\t\twhile p.match(str):\n\t\t\tm = p.match(str)\n\t\t\tstr = str.replace(m.group(1), (chr(int(m.group(2),16))+chr(int(m.group(3), 16)+int(m.group(4),16))+chr(int(m.group(5), 16))).decode('utf-8'))\n\texcept:\n\t\tpass\n\t\n\ttry:\n\t\tp = re.compile('.*(%([0-9A-F]{2,2})%([0-9A-F]{2,2})%([0-9A-F]{2,2})).*',re.I+re.S)\n\t\twhile p.match(str):\n\t\t\tm = p.match(str)\n\t\t\tstr = str.replace(m.group(1), (chr(int(m.group(2),16))+chr(int(m.group(3), 16)+int(m.group(4),16))).decode('utf-8'))\n\texcept:\n\t\tpass\n\t\n\ttry:\n\t\tp = re.compile('.*(%([0-9A-F]{2,2})%([0-9A-F]{2,2})).*',re.I+re.S)\n\t\twhile p.match(str):\n\t\t\tm = p.match(str)\n\t\t\tstr = str.replace(m.group(1), (chr(int(m.group(2),16))+chr(int(m.group(3), 16))).decode('utf-8'))\n\t\t#return (chr(int(m.group(2),16))+chr(int(m.group(3), 16))).decode('utf-8')\n\texcept:\n\t\tpass\n\t\n\ttry:\n\t\tp = re.compile('.*(%([0-9A-F]{2,2})).*',re.I+re.S)\n\t\twhile p.match(str):\n\t\t\tm = p.match(str)\n\t\t\tstr = str.replace(m.group(1), (chr(int(m.group(2),16))).decode('utf-8'))\n\texcept:\n\t\tpass\n\t\n\treturn str\n\n<\/pre>\n<p>Warum so kompliziert? Nun, utf-8 kann 4, 3, 2 oder 1-Byte-Zeichen enthalten. (Wir wissen nicht welche vorkommen, also versuchen wir zun\u00e4chst die l\u00e4ngsten und dann die k\u00fcrzeren durch unicode zu ersetzen.) Solange in einer Kombination &#8222;p.match(str)&#8220; nicht null &#8211; also wahr &#8211; ist, muss man in diesem String ersetzungen vornehmen.<\/p>\n<h3>Es fehlt uns nur noch der dritte Nothelfer: unicode2html<\/h3>\n<pre class=\"brush: python;\">\ndef unicode2html(str):\n\tret=\"\"\n\tfor ch in unicode(str):\n\t\ti = ord(ch)\n\t\tif i &gt; 127:\n\t\t\tret=ret+u'&amp;#'+unicode(i)+';'\n\t\telif i == 042:\n\t\t\tret = ret+u'&amp;uot;'\n\t\telif i == 046:\n\t\t\tret = ret+u'&amp;'\n\t\telif i == 074:\n\t\t\tret = ret+u'&lt;'\n\t\telif i == 076:\n\t\t\tret = ret+u'&gt;'\n\t\telse:\n\t\t\tret=ret+ch\n\treturn ret\n<\/pre>\n<p>Bis aus &amp; &gt; &lt; und &quot; ersetzt er keine Zeichen Unterhalb vom 127 (im ASCII), daf\u00fcr aber alle oberhalb in &amp;#NUMMER;. So kann man notfalls schnell zur\u00fcck umwandeln.<\/p>\n<p>Wenn Sie also irgendwo im Saarland einen netten Python-Job f\u00fcr mich haben&#8230; Gerne!<\/p>\n<hr \/>\n<p>Sch\u00f6nen Dank an die folgenden Ideengeber:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.amk.ca\/python\/howto\/unicode\">Python Unicode HOWTO<\/a><\/li>\n<li><a href=\"http:\/\/de.wikipedia.org\/wiki\/Utf8\">Wikipedias Artikel \u00fcber UTF-8<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Ich kann es mir nicht erkl\u00e4ren, warum es mir die meisten nicht zutrauen, etwas richtig gutes in Python zu bauen. (Die meisten Chefs halten es ohnehin f\u00fcr einen Witz, wenn man \u00fcber diese smarte Programmiersprache spricht. Dabei ist sie genauso einfach wie PHP und stark wie Java.) Ich bin auf das folgende Problem beim entwickeln [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_sitemap_exclude":false,"_sitemap_priority":"","_sitemap_frequency":"","ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","ocean_post_oembed":"","ocean_post_self_hosted_media":"","ocean_post_video_embed":"","ocean_link_format":"","ocean_link_format_target":"self","ocean_quote_format":"","ocean_quote_format_link":"post","ocean_gallery_link_images":"on","ocean_gallery_id":[],"footnotes":""},"categories":[8],"tags":[],"class_list":["post-627","post","type-post","status-publish","format-standard","hentry","category-software","entry"],"_links":{"self":[{"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/posts\/627","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/comments?post=627"}],"version-history":[{"count":0,"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/posts\/627\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/media?parent=627"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/categories?post=627"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.kolatzek.org\/wblog\/wp-json\/wp\/v2\/tags?post=627"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}