質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

Q&A

解決済

1回答

14414閲覧

Python 3.5でのバックスラッシュを含む文字列置換について

shutosg

総合スコア20

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

1グッド

0クリップ

投稿2016/05/01 22:44

編集2016/05/01 22:46

やりたいこと

文字列strが与えられていて、strから文字列の置換を用いてstr2のような文字列を生成したいのですが、どうやっても出来ませんでした。どうすれば実現できるでしょうか?

Python

1str = '\\x80\\x00\\x00\\x00\\x00\\x00\\xb0' 2str2 = '\x80\x00\x00\x00\x00\x00\xb0'

以下、奮闘の結果を記しますが、結構長いので最後まで読んで頂かなくても構いません。。。

試したこと1

  • '\x'を'\x'で置き換える

Python

1str.replace('\\x', '\x') 2# SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: truncated \xXX escape

ググってもエラーの意味がよく分からなかった(position 0-1とはどこのこと?)のですが、文字列'\x'で置き換えようとして、「そもそも文字列とは'\xXX'の形式ですよ。'\x'は文字列じゃないですよ」って怒られてると解釈しています。

'\\x'->'\x'の置換で怒られるなら、'\\xXX'->'\xXX'の置換をしよう。

Python

1str.replace('\\x00', '\x00') 2# '\\x80\x00\x00\x00\x00\x00\\xb0'

一応できたっぽい。でも、str2のようにするには

Python

1str.replace('\\x00', '\x00').replace('\\x80', '\x80').replace('\\xb0', '\xb0')

のように全パターン手動で置き換えないといけません。不格好だし、数が増えた時にツライので却下。

試したこと2

  • strを文字列として扱ってるから'\\x'->'\x'の置換が出来ない。じゃあバイト列として扱おう。

Python

1byte = str.encode() 2# b'\\x80\\x00\\x00\\x00\\x00\\x00\\xb0' 3 4byte.replace(b'\\x', b'\x') 5# SyntaxError: (value error) invalid \x escape at position 0

またなんかエラー出てきた…
調べたのですが、\xというのはそれ単体で、後ろの2文字を16進数として扱うためのエスケープ記号を表しているっぽい??

試したこと3

  • \\\に置き換える
  • 文字列(str)じゃなくてバイト列を使う
  • そもそも\ってエスケープ記号によく使われるので、これ単体での置換は面倒臭い事になりそうな気がしていて避けていましたが、今までがことごとくダメだったので試してみることに…

Python

1byte.replace(b'\\', b'\') 2# SyntaxError: EOL while scanning string literal

これもエラー文でググったのですが、最後のb'\'の部分が\のせいで'(シングルクォーテーション)が閉じ記号として扱われていないそうで、エラー吐かれます。

では、シングルクォーテーションをエスケープしてみます。こうすればバイト列中の\\\に置き換わってくれるはず。

Python

1byte.replace(b'\\\\', b'\\') 2# b'\\x80\\x00\\x00\\x00\\x00\\x00\\xb0

予想に反して全く置換がされません。

更に色々試していて、こんなことも起きました…

Python

1str.encode().replace(b'\\', b'') 2# b'x80x00x00x00x00x00xb0'

byte.replace(b'\\', b'\')をした時は、第2引数のb'\'\'のエスケープに使われて怒られたのに、今度はb'\\'\はエスケープに使われていない…

この辺りで完全にお手上げ状態ですが、一応reモジュールを読み込んで正規表現も色々試しましたが、結局うまく行きませんでした。

ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

根本的な勘違いをされているようです。
strを作った時点でもうstr2と同じ文字列ができてますよ。
もしエスケープが嫌ならr''を使うことができます。

python

1>>> s = '\\x80\\x00\\x00\\x00\\x00\\x00\\xb0' 2>>> print(s) 3\x80\x00\x00\x00\x00\x00\xb0 4>>> s = r'\x80\x00\x00\x00\x00\x00\xb0' 5>>> print(s) 6\x80\x00\x00\x00\x00\x00\xb0 7>>>

-- 追記1
最初からあるので変数名strは避けましょう。

-- 追記2: あ、質問の意味が分かりました...
んーちょっとキレイで簡単な方法は思いつきませんねぇ。
evalに嫌悪感なければこういうのとか。

python

1>>> s = '\\x80\\x00\\x00\\x00\\x00\\x00\\xb0' 2>>> eval('"{}"'.format(s)) 3'\x80\x00\x00\x00\x00\x00°' 4>>>

投稿2016/05/01 23:18

編集2016/05/01 23:49
sharow

総合スコア1149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shutosg

2016/05/01 23:39 編集

ご回答ありがとうございます。 >strを作った時点でもうstr2と同じ文字列ができてますよ。 とおっしゃいますが、str2は最後の`\xb0`以外は文字列としては有効でないので、 ```Python >>> print(str2) €° ``` となります。私が欲しいのはこの有効ではない文字を含むstr2なのです。 >追記1 確かにクラス名にstrというのがありました。ご指摘ありがとうございます
sharow

2016/05/01 23:51

作りたいのは文字列じゃなくてバイト列だった、という可能性はありますか?
sharow

2016/05/01 23:57

> この有効ではない文字を含むstr2なのです。 表示できないだけで、str2はすべてを含んでいますよ。 >>> print(s) ° >>> print(repr(s)) '\x80\x00\x00\x00\x00\x00°' >>> len(s) 7 >>>
shutosg

2016/05/02 00:09

>作りたいのは文字列じゃなくてバイト列だった、という可能性はありますか? その通りで、欲しかったのはバイト列でした。正確でない表現をしてしまって申し訳ありませんでした。 evalを使った方法も、いくつか調べながら試してみてできなかったのですが、、、まさにこれでした…!!ありがとうございます!!!
sharow

2016/05/02 00:22

バイト列を得る場合は eval('b"{}"'.format(s)) でいけそうですね。 ただ、一般的にはevalは要注意人物みたいな関数ですので、用途によっては使うことができません。「eval 危険」みたいなキーワードでググっていただけるといろいろ出るかと思います(検索に出てくるのはJavaScriptのevalが多いでしょうけど、避けるべき理由はどの言語でも似ています)。 ので、比べるとちょっと複雑になってしまいますが、こっちの方がよいかもしれません。 >>> s = '\\x80\\x00\\x00\\x00\\x00\\x00\\xb0' >>> bytes(int(x, base=16) for x in s.split('\\x') if x) b'\x80\x00\x00\x00\x00\x00\xb0' >>>
sharow

2016/05/02 00:36

書き忘れてましたのでここで。 奮闘した理由ですが、おそらくエスケープ処理が常にされると考えていたからだと思います。エスケープ処理はPythonが文字列リテラルを読み込む(解析する)ときに行われます。一度メモリに乗ったPython上の文字列オブジェクトにはエスケープ処理はされません。これがreplaceで解決できない理由です。
shutosg

2016/05/02 02:16

JavascriptやPHPのevalも存在も知っていたのでその危険性はある程度理解しているつもりですが、解決した後もわざわざご指摘いただきありがとうございます。 また、奮闘した理由についても考察頂きありがとうございます! Pythonにおいてエスケープ処理が行われるタイミングというのを全く考慮していませんでした。(というか知らなかったのですが) 今後はその辺りも想定しながら学んでいこうと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問