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

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

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

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

Python

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

Q&A

解決済

1回答

3554閲覧

Python 正規表現 姓名の摘出について

daichanman

総合スコア6

正規表現

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

Python

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

0グッド

0クリップ

投稿2019/09/02 02:26

編集2019/09/02 03:00

正規表現で様々なパターンで来る姓名を摘出したいのですが少ないコードで書きたいと思っております。

python2.7 でメール
から氏名を抜き出したいと考えております
上下には他のデータも入ってる予定です。
現在このような形で書いており、
もう少しシンプルな書き方があるとは思いますが
どう書いたらいいのかわからず質問させていただきます。

該当のソースコード

Python

1 name = re.search(r"予約者名カナ:(\S+)\s+(\S*)", msg, re.MULTILINE) 2 if name: 3 name_first = name.group(1) 4 name_last = name.group(3) 5 if not name: 6 name = re.search(r"名前カナ:(\S+) (\S+)", msg, re.MULTILINE) 7 name_first = name.group(1) 8 name_last = name.group(2) 9 if not name: 10 name = re.search(r"名前カナ:(\S+)", msg, re.MULTILINE) 11 name_first = name.group(1)
日時:〜〜〜〜〜〜 パターン(1)名前カナ:田中太郎 パターン(2)名前カナ:田中 太郎 パターン(3)名前カナ:田中 太郎 生年月日:〜〜〜〜〜 後ろに半角スペース・全角スペース・改行が来ても 取り出せるようにしたいと思っております。

試したこと

これでパターン押さえれるかと思ったのですが、サーチにひっかりませんでした。どこが違うのでしょうか?

Python

1 name = re.search(r"名前カナ:([^ ]+)( | )+(\S*)", msg, re.MULTILINE) 2 if name: 3 name_first = name.group(1) 4       if name.group(3): 5 name_last = name.group(3)

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

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

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

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

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

maisumakun

2019/09/02 02:30

「平光清」のように、「平光 清」か「平 光清」か、切り方がわからない名前が来ることもあるかと思いますが、その点は大丈夫でしょうか?
daichanman

2019/09/02 02:37 編集

ご指摘ありがとうございます。 来るデータに空白があれば氏名を分ける考えで、空白がなければ 3番目のif で姓名一緒に摘出できたらと考えております。 後々はそういう事もやりたいとは思いますがまだまだ素人の為、 そこまでの実装は今回考えておりません。
guest

回答1

0

ベストアンサー

正規表現を使わずとも、str.splitで充分なように思います。

Python

1name_lst = msg.split() 2 3if len(name_lst) == 1: 4 name_first, = name 5elif len(name_lst) == 2: 6 name_first, name_last = name 7else: 8 非マッチ時の処理

余計な文字も工夫すれば適当に除去できます。

Python

1>>> 'Yamada Tarou'.split() 2['Yamada', 'Tarou'] 3>>> 4>>> 'Name:Yamada Tarou'.split() 5['Name:Yamada', 'Tarou'] 6>>> 'Name:Yamada Tarou'[5:].split() 7['Yamada', 'Tarou'] 8>>> 'Name:Yamada Tarou'.split(':')[1].split() 9['Yamada', 'Tarou']

その他、気になること

Python2.7を使っていること
サポートが2020年始に打ち切られるので、乗り換えることを強く推奨します。

re.MULTILINE
これはアンカー ^$ の振る舞いを制御するフラグで、行を跨いだマッチには向きません。
使うとすればre.DOTALLですが、これも . と併用して初めて効果を発揮します。

投稿2019/09/02 02:34

編集2019/09/02 03:04
LouiS0616

総合スコア35660

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

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

daichanman

2019/09/02 02:56

回答ありがとうございます。 質問の詳細が抜けており申しわけございません。 今回メールからデータを抜き出したいと思っておりました。 日時: 名前カナ: 誕生日: その他: のようなメールから摘出を考えております。 現在勉強中で的はずれな事言っていましたら申し訳ありません。 参考等や元データが2.7の為そのままやっておりました。 そうなのですね!ありがとうございます3.0に移行し勉強しいきたいと思います。 このような場合はre.MULTILINEはつけないほうがいいでしょうか? それとも ^名前カナ: で書いたほうがいいいのでしょうか?
LouiS0616

2019/09/02 02:59 編集

> このような場合はre.MULTILINEはつけないほうがいいでしょうか? 必要で無い限り付けなくて良いです。 > ^名前カナ: で書いたほうがいいいのでしょうか? アンカーを指定するなら、^$より\A\Zの方が後々の混乱が少ないかもしれません。 Python3.xはre.fullmatchを提供するので、それを使うのも良い方法です。
LouiS0616

2019/09/02 03:00

> ~のようなメールから摘出を考えております。 ええと、つまり次のような文面からも『山田』『太郎』を抽出したいのでしょうか? --- 日時: 名前カナ:山田 太郎 誕生日: その他:
daichanman

2019/09/02 03:11

ありがとうございます。勉強になります。 混乱させてしまい申し訳ありません。 名前:カナの1行の中にデータが来ます。 日時: 名前カナ:山田 太郎 ←この行に来るデータが(山田太郎 )(山田 太郎)(山田 太郎)だったりする 誕生日: その他:
LouiS0616

2019/09/02 03:14

ああ、なるほど。 『後ろに半角スペース・全角スペース・改行が来ても』という記述から、姓名が改行で分割されるパターンもあるのだと思っていました。 まずsplit('\n')で各項目を分割して、その後に姓名の抽出に取り組むのが楽でしょう。 辞書を適宜使うと今後拡張する際にスムーズかもしれません。
LouiS0616

2019/09/02 03:16 編集

文全体から一発で姓名を抽出したい(姓名以外の情報は無視する)のであれば、確かに正規表現が有用です。re.MULTILINEの出番もあります。 ちょっと回答に追記するので、少々お待ち下さい。
LouiS0616

2019/09/02 03:28

あー、しかし『山田太郎 』はちょっと厄介ですね。 『山田 太郎 』とか『 山田 太郎 』とかもあり得るんでしょうか?
daichanman

2019/09/02 03:32

ありがとうございます。理解しました。確かにsplitが楽ですね。考えてた時間が勿体なかったです。 splitは1つのデータの物という考えがあり \nで行を1行1行句切って使う考えが思いつきませんでした。 お手数かけますが正規表現も気になりますので、御教授して頂ければ大変助かります。
daichanman

2019/09/02 03:34

頭にスペースは無いですが、山田太郎の後ろに半角・全角スペースは有り得ます。
LouiS0616

2019/09/02 03:40 編集

『山田 太郎 』『山田太郎』みたいなパターンも踏まえると、強引には次のように書けます。 re.search(r'^名前カナ:(\S+)\s*?(\S*)\s*$', msg, flags=re.MULTILINE) 実際には名前部分だけ抽出してきて、stripして両端の空白文字を省いてからsplitするのが簡単でしょう。
daichanman

2019/09/02 04:03

わざわざありがとうございました。何度も追記していただき本当に感謝です。これを踏まえて色々試してやってみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問