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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1184閲覧

Perlの正規表現による文字列抽出をPythonでやりたい

troublemaker

総合スコア7

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2017/11/21 00:16

編集2017/11/21 12:09

下記のようなPerlのコードと同じことをPythonでやりたくて調べています。

Perl

1 use utf8; 2 use feature 'unicode_strings'; 3 use open ':encoding(utf8)'; # I/O default encoding is UTF-8 4 use open ':std'; # stdio encoding = utf8 5 use Encode qw(encode_utf8 decode); 6 7 use strict; 8 9 my $regExp = qr/[\p{Han}\p{Katakana}a-zA-Z0-90-9%][\p{Han}\p{Katakana}a-zA-Z0-90-9%・ー]*/; 10 my $text = "三人行えば、必ずわが師あり"; 11 my @matchedList = (); 12 13 for ($text) { 14 s/($regExp)/ do{ push @matchedList,$1; ""; }; /ge; 15 } 16 17 print join( ",",@matchedList);

上記を実行すると、"三人行,必,師"という漢字だけを抽出した文字列を得ることができます。
これをPythonでもやりたいのですが、下記のようなコードを書いてみてもうまくいかず困っています。

Python

1 # coding: utf-8 2 import re 3 4 regExp = r'[一-龥ァ-ンa-zA-Z0-90-9%][一-龥ァ-ンa-zA-Z0-90-9%・ー]*' 5 text = '三人行えば、必ずわが師あり' 6 7 if re.match(regExp, text): 8 matched = re.findall(regExp, text) 9 print ','.join(matched)

これでは漢字のみを抽出することができず、一文すべてを抽出してしまい結果が異なります。
re.searchなども試してみましたが同様でした。
PythonでもPerlで書いたような抽出結果を再現することはできるのでしょうか。
お知恵をお貸し下さい。
よろしくお願いいたします。

追記:
ご回答頂き無事解決できました。
ありがとうございました。

Python

1# coding: utf-8 2import re 3 4regExp = ur'[一-龥ァ-ンa-zA-Z0-90-9%][一-龥ァ-ンa-zA-Z0-90-9%・ー]*' 5text = u'三人行えば、必ずわが師あり' 6 7if re.match(regExp, text): 8 matched = re.findall(regExp, text) 9 print ','.join(matched).encode('utf-8') 10

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

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

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

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

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

guest

回答3

0

ベストアンサー

文字データはユニコード文字列として処理しなければならない、という点はほかの方が回答しておられますので省きます。


Pythonのreが対応している正規表現には、Perlの拡張正規表現にある\p{用字}のようなものがありません。同じことができる文字クラスを書くしかないと思います。

特定の用字を[一-龥][ァ-ン]のように単一のコード範囲で表すことは、一般にできません。ユニコードではバージョンが上がるごとに文字の追加があるため、同じ用字の文字がコード表のあちこちに散らばって登録されているのが普通です。

  • [一-龥]は、ユニコードの最初のバージョンの1.0.0で登録されていた漢字しかカバーできません。
  • [ァ-ン]は、ユニコード1.0.0さえもカバーしていません。などが含まれません。後のバージョンで追加されたアイヌ語用拡張などはもちろんカバーできません。

ユニコードコンソーシアムが、ユニコード10.0.0での用字プロパティの完全な一覧を公開しています。これをもとにして正規表現を作ることができます。

  • \p{Han}と同等の文字クラス
[\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303A\u303B\u3400-\u4DB5\u4E00-\u9FEA\uF900-\uFA6D\uFA70-\uFAD9\U00020000-\U0002A6D6\U0002A700-\U0002B734\U0002B740-\U0002B81D\U0002B820-\U0002CEA1\U0002CEB0-\U0002EBE0\U0002F800-\U0002FA1D]
  • \p{Katakana}と同等の文字クラス
[\u30A1-\u30FA\u30FD-\u30FE\u30FF\u31F0-\u31FF\u32D0-\u32FE\u3300-\u3357\uFF66-\uFF6F\uFF71-\uFF9D\U0001B000]

となります。

U+10000以降の文字を省いたら正規表現が少しは簡単になるのでは……と思うかもしれませんが、そうしないほうがいいです。特にU+20000以降の漢字には、日本語のテキストデータで普通に使われているものがいくつもあります。

ちなみに、ユニコードのバージョンが上がると文字が追加されますから、上記の正規表現も見直す必要があります。特に漢字は追加される頻度が高いです。


クローズ後追記

濁点 、半濁点 、音引き は、用字プロパティがKatakanaではなくCommonやInheritedになっています。ので、「片仮名の一文字」にマッチさせるには\p{Katakana}だけでは十分でなく、次のようにする必要があると思います。

perl

1[\p{Katakana}\u30FC\uFF70][\u3099-\u309C\uFF9E\uFF9F]?

python

1[\u30A1-\u30FA\u30FD-\u30FE\u30FF\u31F0-\u31FF\u32D0-\u32FE\u3300-\u3357\uFF66-\uFF6F\uFF71-\uFF9D\U0001B000\u30FC\uFF70][\u3099-\u309C\uFF9E\uFF9F]?

[\u3099-\u309C\uFF9E\uFF9F]が濁点と半濁点、[\u30FC\uFF70]が音引きです。

投稿2017/11/21 04:57

編集2017/11/22 04:13
ikedas

総合スコア4335

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

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

troublemaker

2017/11/21 12:03

ご回答ありがとうございました。 正規表現の書き方の間違いも指摘して頂けて助かりました。 コード自体は動くようになったので、今度は正規表現の方も工夫したいと思います。
ikedas

2017/11/22 04:15

濁点などについて気がついたことを追記しました。
troublemaker

2017/11/22 23:01

追記ありがとうございます!
guest

0

多分 お使いの Pythonは Python2系だと思います。Python2では日本語を扱う時はunicode文字列として指定してください。 regExp, text ともに unicode文字列にしたら期待通りに動きました。

python

1regExp = ur'([一-龥ァ-ンa-zA-Z0-90-9%][一-龥ァ-ンa-zA-Z0-90-9%・ー]*)' 2text = u'三人行えば、必ずわが師あり' 3 4print ','.join(re.findall(regExp, text)) => 三人行,,

投稿2017/11/21 01:08

tell_k

総合スコア2120

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

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

troublemaker

2017/11/21 12:04

教えて頂いた通りunicodeに変換して動かすことができました! ご回答ありがとうございました。
guest

0

下記のように対応してみました。

python

1# coding: utf-8 2import re 3 4regExp = u'[一-龍]+' 5text = u'三人行えば、必ずわが師あり' 6 7if re.match(regExp, text): 8 matched = re.findall(regExp, text) 9 print(','.join(matched)) 10 # => 三人行,必,師

投稿2017/11/21 01:01

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

troublemaker

2017/11/21 12:05

unicode文字列にすれば良かったんですね! 参考になりました。 ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問