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

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

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

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

Python

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

Q&A

解決済

5回答

5041閲覧

特定の文字を大文字に変換をするプログラムでn個まで文字数を対応させたい

true_zaku1997

総合スコア8

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2018/04/03 22:29

編集2018/04/04 01:20

前提・実現したいこと

Python3で、特定の文字に該当する文字列の大文字変換をするプログラムを書いています。
一応動くものになっていますが、条件に該当する文字が増えるほど、条件が増えていってしまうような記述方法になっているので、スッキリしたコードがあればご助言いただきたいです。
現状、一致する文字数が4個までのプログラムになっているので、n個でも対応できるようなプログラムにしたいです。
(追記)
hayataka2049さんの仰る通り変換できうるパターンを全て列挙したいです。

該当のソースコード

Python

1#例 2string = "tera-tail" 3rule = "te" 4 5i = 0 6sol1 = [] 7sol1.append(string.lower()) 8positions = [] 9characters = [] 10 11#1文字だけ順に小文字から大文字に変換 12for s in list(string.lower()): 13 sol2 = '' 14 if s in rule.lower(): 15 string2 = list(string.lower()) 16 s = s.upper() 17 string2[i] = s 18 for s2 in string2: 19 sol2 += s2 20 sol1.append(sol2) 21 #変換した文字の位置番号と文字をリスト化して後述で使用 22 positions.append(i) 23 characters.append(s) 24 i = i + 1 25 26import itertools 27permu = [] 28permu_list = [] 29#リスト化した位置番号と文字を1つのリストにまとめる 30for p,c in zip(positions,characters): 31 permu = [[p,c]] 32 permu_list.extend(permu) 33 34#ruleに合致する文字が2個の組み合わせ処理 35if len(positions) > 2: 36 for p1,p2 in list(itertools.combinations(permu_list,2)): 37 sol2 = '' 38 string2 = list(string.lower()) 39 string2[p1[0]] = p1[1] 40 string2[p2[0]] = p2[1] 41 for s2 in string2: 42 sol2 += s2 43 sol1.append(sol2) 44 45#ruleに合致する文字が3個の組み合わせ処理 46if len(positions) > 3: 47 for p1,p2,p3 in list(itertools.combinations(permu_list,3)): 48 sol2 = '' 49 string2 = list(string.lower()) 50 string2[p1[0]] = p1[1] 51 string2[p2[0]] = p2[1] 52 string2[p3[0]] = p3[1] 53 for s2 in string2: 54 sol2 += s2 55 sol1.append(sol2) 56 57#ruleに合致する文字全て大文字に変換 58for p,c in zip(positions,characters): 59 string2[p] = c 60sol2 = '' 61for s2 in string2: 62 sol2 += s2 63sol1.append(sol2) 64 65print(sol1) 66#['tera-tail', 'Tera-tail', 'tEra-tail', 'tera-Tail', 'TEra-tail', 'Tera-Tail', 'tEra-Tail', 'TEra-Tail'] 67

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

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

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

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

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

guest

回答5

0

ベストアンサー

以下でどうでしょう?

  • stringの各文字についてruleに含まれるなら大文字小文字の2文字、それ以外は1文字。
  • itertools.productで上記の各文字を組み合わせた全パターンを列挙

Python

1import itertools 2 3string = "tera-tail" 4rule = "te" 5 6pat = [(c,c.upper()) if c in rule else tuple(c) for c in string] 7print(pat) 8# [('t', 'T'), ('e', 'E'), ('r',), ('a',), ('-',), ('t', 'T'), ('a',), ('i',), ('l',)] 9 10l = [''.join(s) for s in itertools.product(*pat)] 11print(l) 12# ['tera-tail', 'tera-Tail', 'tEra-tail', 'tEra-Tail', 'Tera-tail', 'Tera-Tail', 'TEra-tail', 'TEra-Tail']

投稿2018/04/04 01:34

can110

総合スコア38233

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

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

hayataka2049

2018/04/04 02:57

あー、なるほど。これ良いですね
guest

0

リスト内包表記、条件演算子、in演算子、joinを使ってすっきり書いてみました。以下は対話的インタプリタに打ち込んだコードと結果です。

python

1>>> string = "hogehogehoge" 2>>> lst = ["o", "g"] 3>>> "".join([c.upper() if c in lst else c for c in string]) 4'hOGehOGehOGe'

こんな感じでどうでしょう。

追記

質問文のコードを見直して、もしかして可能な変換をすべて列挙したかったのかと気づきました。
書き方は色々あると思いますが、一例を示しておきます。素直に書いたつもりですが、あまりすっきりはしていないかもしれません。

python

1>>> string = "tera-tail" 2>>> lst = ["t", "e"] 3>>> char_pos = [i for i, c in enumerate(string) if c in lst] 4>>> def int_to_bool(num, base): 5 return [bool(num & (1<<n)) for n in range(base)] 6... 7>>> result = [] 8>>> for i in range(2**len(char_pos)): 9... bool_lst = int_to_bool(i, len(char_pos)) 10... result.append(("".join([(c.upper() if bool_lst.pop(0) else c) if i in char_pos else c for i, c in enumerate(string)]))) 11... 12>>> print(result) 13['tera-tail', 'Tera-tail', 'tEra-tail', 'TEra-tail', 'tera-Tail', 'Tera-Tail', 'tEra-Tail', 'TEra-Tail']

更に追記

上のコードがなんだかすっきりしていなかったので、見た目が綺麗な処理方法を考えました。

python

1>>> string = "tera-tail" 2>>> lst = ["t", "e"] 3>>> result = [""] 4>>> for c in string: 5... if c in lst: 6... result = [s+c for s in result] + [s+(c.upper())for s in result] 7... else: 8... result = [s+c for s in result] 9... 10>>> print(result) 11['tera-tail', 'Tera-tail', 'tEra-tail', 'TEra-tail', 'tera-Tail', 'Tera-Tail', 'tEra-Tail', 'TEra-Tail']

性能面で課題があるかもしれません。

投稿2018/04/03 22:45

編集2018/04/03 23:39
hayataka2049

総合スコア30933

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

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

0

hayataka2049さんの更に追記を少しだけ高速化してみました。
できるだけ違う書き方にしてあります。

python

1string = "tera-tail" 2string = string*5 3lst = ["t", "e"] 4result = [""] 5 6iter_string = iter(list(string) + [None]) 7c = next(iter_string) 8b = '' 9while c: 10 if c not in lst: 11 b += c 12 else: 13 result = [s+b+c for s in result] + [s+b+(c.upper())for s in result] 14 b = '' 15 c = next(iter_string) 16if b != '': 17 result = [s+b for s in result]

測定。
strのjoinが遅い…ナゼ??

python

1from contextlib import contextmanager 2 3import time 4import itertools 5 6string = "tera-tail" 7string_org = string 8rule = "te" 9 10def f_can110(string, rule): 11 pat = [(c,c.upper()) if c in rule else tuple(c) for c in string] 12 l = [''.join(s) for s in itertools.product(*pat)] 13 return l 14 15def f_hayataka2049(string, lst): 16 result = [""] 17 for c in string: 18 if c in lst: 19 result = [s+c for s in result] + [s+(c.upper())for s in result] 20 else: 21 result = [s+c for s in result] 22 return result 23 24def f_rev_hayataka2049(string, lst): 25 iter_string = iter(list(string) + [None]) 26 c = next(iter_string) 27 b = '' 28 result = [''] 29 while c: 30 if c not in lst: 31 b += c 32 c = next(iter_string) 33 else: 34 result = [s+b+c for s in result] + [s+b+(c.upper())for s in result] 35 b = '' 36 c = next(iter_string) 37 if b != '': 38 result = [s+b for s in result] 39 return result 40 41@contextmanager 42def timer(name): 43 t0 = time.time() 44 yield 45 print(f'[{name:20}] done in {time.time() - t0:.3f} s') 46 47string = string_org*5 48for i in range(5, 8): 49 string = string+string_org 50 print('-'*30) 51 with timer(f'rev_hayataka2049_{i}'): 52 res1 = f_rev_hayataka2049(string, rule) 53 54 with timer(f'can110_{i}'): 55 res2 = f_can110(string, rule) 56 57 with timer(f'hayataka2049_{i}'): 58 res3 = f_hayataka2049(string, rule) 59 60 res1 = sorted(res1) 61 res2 = sorted(res2) 62 res3 = sorted(res3) 63 assert(all([x==y for x,y in zip(res1, res2)])) 64 assert(all([x==y for x,y in zip(res1, res3)])) 65''' 66------------------------------ 67[rev_hayataka2049_5 ] done in 0.184 s 68[can110_5 ] done in 0.225 s 69[hayataka2049_5 ] done in 0.338 s 70------------------------------ 71[rev_hayataka2049_6 ] done in 1.713 s 72[can110_6 ] done in 2.289 s 73[hayataka2049_6 ] done in 3.259 s 74------------------------------ 75[rev_hayataka2049_7 ] done in 15.343 s 76[can110_7 ] done in 20.240 s 77[hayataka2049_7 ] done in 31.384 s 78'''

投稿2018/04/04 12:43

編集2018/04/04 14:02
mkgrei

総合スコア8560

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

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

0

replaceメソッドを使えば一発ですよ。

python

1string = "tera-tail" 2rule = "te" 3print(string.replace(rule, rule.upper())) 4# => TEra-tail 5 6rule = "a" 7print(string.replace(rule, rule.upper())) 8# => terA-tAil

投稿2018/04/04 00:05

編集2018/04/04 00:10
hiramekun

総合スコア428

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

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

0

conv("aaaaa","a",3)を"AAAaa"のように変換回数を指定したいように見える

コメントしたつもりが誤爆してる

投稿2018/04/03 23:57

編集2018/04/04 01:55
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問