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

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

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

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

Q&A

7回答

208閲覧

Pythonで文字列を分割したい(Noと商品番号を分けたい)

kaiji24

総合スコア5

Python

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

1グッド

0クリップ

投稿2024/11/19 09:53

実現したいこと

ナンバー(必ず数字)と商品番号(必ず先頭一桁はアルファベット)が混ざっているレコードを、
ナンバーと商品番号に分割したいです。

1DF→1/DF
2→2
10F0→10/F0
300AAA→300/AAA
1100A0→1100→A0

発生している問題・分からないこと

自分の書いているプログラムだと、ナンバーの桁数が増えるたびに、
条件分を追加しないといけないのと、
商品番号が始まる桁数がバラバラのため、下記方法を拡張しようとするとエラーになります。
もう少しスマートな方法はないでしょうか。

該当のソースコード

python

1list = ['1DF', '2', '10F0','300AAA','1100A0'] 2no=[] 3syohin=[] 4for s in range(len(list)): 5 if len(list[s])== 0: 6 no.append("") 7 for t in range(len(list[s])): 8 if t==0: 9 if list[s][t].isnumeric() == True: 10 no.append(list[s][t]) 11 if t==1: 12 if list[s][t].isnumeric() == True: 13 no[s]+=list[s][t] 14 elif list[s][t].isalpha() == True: 15 syohin.append(list[s][t]) 16 if t==2: 17 if list[s][t].isnumeric() == True: 18 no[s]+=list[s][t] 19 elif list[s][t].isalpha() == True: 20 syohin.append(list[s][t]) 21 22print(no) 23print(syohin) 24 25['1', '2', '10', '300', '110'] 26['D', 'F', 'F']

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

正規表現を使う方法があるのかなと思いましたが、実現方法が具体的にはわかりませんでした。

補足

特になし

melian👍を押しています

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

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

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

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

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

guest

回答7

0

正規表現を使うという意味では同様ですが,re.compile()re.sub() を用いた記述例を下記に示します。

Python

1import re 2 3rcd = ['1DF', '2', '10F0', '300AAA', '1100A0'] 4ptn = re.compile(r'^(\d+)((\D.*)?)$') 5 6no = [re.sub(ptn, r'\1', s) for s in rcd] 7syohin = [re.sub(ptn, r'\2', s) for s in rcd] 8 9print(no) 10# ['1', '2', '10', '300', '1100'] 11print(syohin) 12# ['DF', '', 'F0', 'AAA', 'A0']

投稿2024/11/19 15:43

編集2024/11/20 00:36
little_street

総合スコア402

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

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

0

内包表記を使用した例です。

Python

1lst = ['1DF', '2', '10F0', '300AAA', '1100A0'] 2 3idx = [[i for i,s in enumerate(st) if s.isalpha()][:1] for st in lst] 4no = [s[:i[0]] if i else s for s,i in zip(lst, idx)] 5print(no) # ['1', '2', '10', '300', '1100'] 6syohin = [s[i[0]:] if i else '' for s,i in zip(lst, idx)] 7print(syohin) # ['DF', '', 'F0', 'AAA', 'A0']

投稿2024/11/19 14:13

lehshell

総合スコア1156

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

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

0

EchoAPI、文字列を簡単に分割できるんです!「ナンバー」と「商品番号」の分割もサクッとできます。数字とアルファベットが混ざったレコードを、希望通りにきれいに分けてくれます。Pythonでの処理もスムーズになって、作業効率がぐんと上がります。試してみてください!

投稿2024/11/19 13:03

isai

総合スコア148

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

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

0

回答じゃなくて補足です。

他の方の回答で使っている表現方法は**「正規表現」**と呼ばれるものです。
検索するといろいろな記事がみつかると思います。また、それだけで分厚い本できるほど奥の深いものです。

基本的には文字列を使って、任意の特徴を持つ文字列を表現する方法です。
・ 大文字英字と数字1つでできた文字列 : "[A-Z][0-9]"
・ 携帯電話番号「‐」付き: "0[789]0-[0-9]{4}-[0-9]{4}"
書き方は扱うシステムによって拡張されていろいろなものがあったりします。

正規表現で目的の文字列を表現したら、それを使って、文字列を抽出したり、分類したり、置き換えたりなどいろいろな操作をします。

pythonで正規表現を扱うモジュールは「re」というモジュールです。名前は「正規表現」を表わす英語「Regular Expression」のから来ています。 詳しい使いかたは、ドキュメントを参照してください。

https://docs.python.org/ja/3/library/re.html

投稿2024/11/19 12:49

TakaiY

総合スコア13687

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

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

0

正規表現でやるのが簡単そうですが、正規表現を使わない方法を参考まで。
文字列の先頭から見て行って数字以外の文字が見つかったら、スライスを使って、その前までをナンバー、そこから後を商品番号としています。(定義のままです)

12行目のelseifではなく6行目のforに対応していて、forbreakされなかったときに実行されるブロックです。(つまり、数字以外が出てこなかった場合)

python

1l = ['1DF', '2', '10F0', '300AAA', '1100A0'] 2no = [] 3syohin = [] 4 5for s in l: 6 for i in range(len(s)): 7 # 数字以外が見つかった場合 8 if not s[i].isnumeric(): 9 no.append(s[:i]) 10 syohin.append(s[i:]) 11 break 12 else: 13 # 全部数字だった場合 14 no.append(s) 15 syohin.append('') 16 17print(no) 18print(syohin) 19 20#['1', '2', '10', '300', '1100'] 21#['DF', '', 'F0', 'AAA', 'A0']

投稿2024/11/19 12:17

bsdfan

総合スコア4774

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

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

kaiji24

2024/11/19 13:32

ベストアンサーは別の方を選ばせていただきましたが、やりたかったことがずばり出来ていて、 自分は頭が固いなと思った次第です。 ありがとうございます。
guest

0

まず、listという変数名は使わない方が良いです。以降でlist関数が使えなくなります。その他、標準的な関数の名前も同じです。

・単語の先頭からの、(1個以上の)数字の並び
・単語の先頭であくても良いが、英字1文字の後に(0個以上の)英数字が並んだもの
ということですかね?

Python

1import re 2 3text_list = ['1DF', '2', '10F0','300AAA','1100A0'] 4text = "\n".join(text_list) 5 6no = re.findall(r'^\d+',text,re.MULTILINE) 7syohin = re.findall(r'[A-Za-z][A-Za-z\d]*',text) 8print(no) 9print(syohin)

1つながりの文字列にして、条件に合うものをfindallで探します。

別解:

Python

1no = [ y.group(0) for x in text_list if (y:=re.match(r'\d+',x)) ] 2syohin = [ y.group(0) for x in text_list if (y:=re.search(r'[A-Za-z][A-Za-z\d]*',x)) ]

こういうのはRubyだと、自然に書けるのですが。

投稿2024/11/19 11:02

編集2024/11/19 11:34
otn

総合スコア85762

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

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

kaiji24

2024/11/19 13:27

回答ありがとうございます。 試したところ問題が解決しました! ところで、 no = re.findall(r'^\d+',text,re.MULTILINE)には、re.MULTILINEが必要なのに、 syohin = re.findall(r'[A-Za-z][A-Za-z\d]*',text) にはなぜ必要ないのでしょうか。 re.MULTILINEは、2行目以降も検索という意味ですよね?
otn

2024/11/20 06:43 編集

> re.MULTILINEは、2行目以降も検索という意味ですよね? いいえ。その意味は公式リファレンスを調べれば書いてありますので、調べて読みましょう。 https://docs.python.org/ja/3/library/re.html#re.MULTILINE > 指定されると、パターン文字 '^' は、文字列の先頭および各行の先頭(各改行の直後)とマッチします。 > デフォルトでは、 '^' は、文字列の先頭とだけマッチ このあたりはPython独自機能で、例えばRubyだと '^' は常に「文字列の先頭もしくは改行文字の直後にマッチ」で、「文字列の先頭にのみマッチ」は別の記号です。 他言語やツールもそれぞれ違う場合があるでしょうね。 以下蛇足。 数字だけからなる文字列は、リストの各要素の先頭である必要があるという抽出要件だと思います。 別解のように、リストの各要素を個別に扱うなら、「文字列の先頭からの数字の並び」でいいので、re.MULTILINE は不要で、別解には書いてません。 1つ目の案では「改行区切りで1つの文字列に連結」してから正規表現で探しているので、「文字列の先頭からの数字の並び」ではだめで、「文字列の先頭もしくは改行の直後からの数字の並び」を検索するためにre.MULTILINEをつけています。 連結する際の区切り文字は改行である必要はないですが、別の文字(例えばタブ)にした場合はちょっとわかりにくくなりますので、簡潔に書ける改行にしました。 syohin の方は、「各要素の先頭」という要件がそもそも無いので、正規表現「^」を使う必要が無いです。 「^」も「$」も使ってない正規表現だと、それらだけに関係する re.MULTILINE の出番がないです。
guest

0

re.split() を利用する場合です。

python

1import re 2 3lst = ['1DF', '2', '10F0', '300AAA', '1100A0'] 4no, syohin = map(list, zip(*[re.split(r'^(\d+)', s)[1:] for s in lst])) 5print(no) 6print(syohin) 7 8# ['1', '2', '10', '300', '1100'] 9# ['DF', '', 'F0', 'AAA', 'A0']

投稿2024/11/19 10:17

編集2024/11/19 16:34
melian

総合スコア20574

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

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

kaiji24

2024/11/19 13:38

ベストアンサーは別の方を選ばせていただきましたが、こちらの回答も非常に参考になりました。 ちなみに、以下で[1:]としている理由は何でしょうか。 m = re.split(r'^(\d+)', s)[1:] [1:]なしのものをプリントしたら、左に余計なものがいるのは分かったのですが、 なぜそうなるのかよくわかりませんでした。。 ['', '1', 'DF'] ['', '2', ''] ['', '10', 'F0'] ['', '300', 'AAA'] ['', '1100', 'A0']
melian

2024/11/19 13:42

以下に説明されています。 re.split: re 正規表現操作 https://docs.python.org/ja/3/library/re.html#re.split > セパレータ中にキャプチャグループがあり、それが文字列の先頭にマッチするなら、結果は空文字列で始まります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問