質問するログイン新規登録
Python

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

Q&A

解決済

7回答

1086閲覧

コメントを残したまま数値データを読み込みたい

yyicp

総合スコア84

Python

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

1グッド

3クリップ

投稿2025/08/12 02:40

1

3

実現したいこと

sample.txtは次のようなファイルです。

0 #num
1 #a[1]
2 #a[2]
3 #ns

0、1、2、3これらの変数は入力パラメータで、変数の説明のために「#以下の部分」を残したいです。このファイルを読み込みたくて、「該当のソースコード」を書きました。(昔に作ったコードなので、参考にしたサイトのURLは分かりませんでした。申し訳ありません)

行数も比較的少なく、正しく動きます。しかし、このような問題に出会ったときに「該当のソースコード」は自然なコードなのか、皆様がどのようなコードを書かれるかが気になりました。もっと自然なコードがあれば教えてください。(「自然」をどう考えるかが難しいですが・・・)

該当のソースコード

python

1a = [0 for i in range(3)] 2 3with open("sample.txt", "r", encoding="utf-8") as f: 4 list = f.readlines() 5 6para= [] 7for i in list: 8 word = i.split() 9 para.append(word) 10 11num = para[0][0] 12a[1] = para[1][0] 13a[2] = para[2][0] 14ns = para[3][0] 15 16print(num) #0 17print(a[1]) #1 18print(a[2]) #2 19print(ns) #3
melian👍を押しています

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

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

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

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

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

guest

回答7

0

データの扱いの要件がわからないのでどうすればいいかは全くわかりませんが、一点、気になったところだけコメント。

データの分割にsplitを使うのは悪手だと思う。 コメントにスペースが含まれていたら、正常に分離できません。コメントが固定なのであれば、それは、とっておく意味がないし。
「#」の前の数値がデータで、以降がコメントだとすると、たとえば正規表現で分離。

python

1import re 2 3para =[] 4with open("sample.txt", "r", encoding="utf-8") as f: 5 for l in f.readlines(): 6 m = re.match(r'^(\d+) *#(.*$)', l) 7 if m: 8 para.append({'value': int(m.groups()[0]), 9 'comment': m.groups()[1]}) 10 11print(para)

データによってはfloatにしたいとかは、仕様がわからないので対応不能。

投稿2025/08/12 07:09

TakaiY

総合スコア14588

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

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

cametan

2025/08/12 07:28

FC2ブログのMTファイル読み込みが恐らく正規表現で正確に書かれてないから、この「分割」が上手く行かないバグがあるんだよね〜(笑)。 何の言語か知らないけど、":"でsplit、みたいな指令にしてるからdropされるトコが一意に決まってなかったりする(笑)。
melian

2025/08/12 07:30 編集

str.split() ではセパレータを指定できますので、例えば以下の様にしてもよいかと思います。 data = [i.strip() for i in l.split('#', maxsplit=1)]
yyicp

2025/08/12 08:02

ありがとうございました。 勉強になりました。
TakaiY

2025/08/12 08:11

melianさんのコメント、勉強になります。
guest

0

回答はいくつかついていますので、

このような問題に出会ったときに「該当のソースコード」は自然なコードなのか、

について。
問題(やりたいこと)を正しく文章化して、それをコード化するのが良いです。
一般的な言い方をすると、「プログラムの仕様を決めてからその仕様に合わせてコーディングしましょう」ということです。

質問のコードだと、split()で分解してその[0]をデータとして取得してます。
このコードから、「やりたいこと」を予想して復元すると、
「各行を空白文字で分割して、各行の最初の非空白の塊を文字列型として取り出す」
ですが、これが本当にやりたいことであれば、これで良いです。

ただ、質問文章を読むと「行中に#があれば#以降を無視して(削除して)、#より前の部分を(前後の空白を削除したうえで)文字列型として取り出す」がやりたいことに見えるので、もしそうであれば、このコードはやりたいことをストレートに反映してないので、良くないです。「#以降はコメントである」という認識で1#コメントという#の前に空白が無いデータを作ってしまうと破綻します。

あるいは、「#の後に、代入したい変数名が書いてあるので、その変数に代入する」がやりたいことなら、全然違うコードになります。cametanさんの回答はそういう方向ですね。

まあ、「今、目の前にあるこのデータだけで正しく動けばいい」という使い捨てプログラムなら設計段階から手抜きして問題ありません。今回のデータだと、「空白で区切った1つめ」と「#以降(と空白)を無視」は同じなので、そこを明確にせずに進めるということです。ただし、再利用されないようにちゃんとプログラムを削除しておきましょう。
一方、使い捨てでないプログラムの場合、「今回はこういうデータだけだけど、今後~~という形式のデータもあり得るので、そういったときにも無修正で対応できるといい(or簡単な修正で対応したい)」ということであれば、それも含めて「やりたいこと」ですから、それに応じたコードにします。

投稿2025/08/15 11:57

otn

総合スコア86395

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

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

otn

2025/08/15 14:35

データファイルの形式をゼロから設計するなら、JSONやYAML等も候補ですね。場合によってはヘッダ行のあるCSVも。 この時も、「データファイルに求められる要件」を整理して文章化してからです。
yyicp

2025/08/18 01:51

プログラムを作るときの考え方、勉強になりました。 どうもありがとうございました。
guest

0

pythonのテクニックに関するご質問であれば以下は読み飛ばしてください。
(split、スライス、正規表現を使うだとか。については言及しません)


Pythonなら関数を定義するのが自然だと思います。

(A) '#'以降の文字列を削除する関数
(B) ファイルの中身の意味のあるデータだけを抽出する中間処理
の二つを私は考えました。

フローとしとしては(B)の処理で(A)を使い行(文字列)毎に処理をします。
以下の例ではジェネレータ構文を使っていますが、想定しているスクリプトは別に全行読み込んで処理をしてもいいとは思います。
理想だけでいえばmap関数のように処理自体を引数として受け取れる方がいいかもしれません。

py

1 2def remove_after_hash(s: str) -> str: 3 # '#'までの文字列を返す 4 if '#' in s: 5 return s.split('#', 1)[0] 6 return s 7 8 9def extract_data(file: TextIO) -> Iterator[str]: 10 # ファイルの必要な部分だけを返す 11 for line in file: 12 line = remove_after_hash(line) 13 yield line 14

remove_after_hashは手続き的な命名なのでコメントを消すとか、意味のある部分だけを残すみたいな意味に変えたほうが人によっては自然に感じるかもしれません。
そうしたほうが空文字を消すみたいな処理もここでカスタマイズしやすいと思います。

「該当のソースコード」は自然なコードなのか、皆様がどのようなコードを書かれるかが気になりました。もっと自然なコードがあれば教えてください。(「自然」をどう考えるかが難しいですが・・・)

フローそのものの自然さに着目しても有益なことがないので、カプセル化されているものだと考えたほうが様々な利点があります。
カプセル化というか、関心の分離というか。正しい言葉ではないでしょうがそういうノウハウが活きるという話です。

*もっと汎用性について議論したい人がextract_dataの関数定義について、指摘してくるかもしれませんが、好きなようにリッチ(笑)にカスタマイズすればよろしいかと思います。空行を無視するだとかね。

投稿2025/08/12 17:23

u2025

総合スコア68

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

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

yyicp

2025/08/13 01:11 編集

ご回答ありがとうございました。 私はまだ初心者なので、ご提示のコード、そのコードの使い方がよく分かりませんでした。 前後も含めて、動くコードをご提示いただけると、色々自分で調べることもできるので、私の理解が進むと思います。 申し訳ありません。
melian

2025/08/13 07:43 編集

> yyicpさん 一例としてですが、以下の様に使います。(ブラウザ上では sample.txt にアクセスできないのでコードをローカルにコピーして実行してください) https://www.mycompiler.io/view/FLGFeiAArhz
u2025

2025/08/13 11:14

使い方の説明ありがとうございます 元の関数定義を歪めたくなかったのか、どうしてもラムダ式を書きたかったのか分かりませんが、行自体に意味(型)があるのであれば、第2引数でtypを受け取るなどした方がわかりやすいかもしれませんね
yyicp

2025/08/18 01:42

>melian様 お返事遅くなって申し訳ありません。 できました。 どうもありがとうございました。
guest

0

既に解決済みなので,御参考です。

re.sub() 関数を用いてコメント部分(# から末尾まで)を取り除き,条件式(三項演算子) を用いて浮動小数点数(float())と整数(int())を切り替えて数値化しています。

Python

1import re 2 3with open('sample.txt', 'r', encoding='utf-8') as f: 4 lst = [s for s in f.read().splitlines()] 5lst = [re.sub('#.*$', '', s) for s in lst] 6lst = [float(s) if i == 1 or i == 2 else int(s) for i, s in enumerate(lst)] 7 8a = [0.0] * 4 9num, a[1], a[2], ns = lst 10 11print(num, a, ns) 12# 0 [0.0, 1.5, 2.0, 0.0] 3

投稿2025/08/12 09:37

little_street

総合スコア479

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

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

yyicp

2025/08/13 00:49

できました。 どうもありがとうございました。
guest

0

例えばこんなん、とか?

Python

1#!/usr/bin/env python3 2 3import sys 4 5a = [0] 6 7if __name__ == '__main__': 8 with open(sys.argv[1], "r") as f: 9 para = [x.split() for x in f.readlines()] 10 for i, j in para: 11 match j: 12 case '#num': 13 num = i 14 case '#ns': 15 ns = i 16 case _: 17 a.append(i) 18 print(f'{num}\n{a[1]}\n{a[2]}\n{ns}') 19 20

個人的には、「リスト内包表記が使えてるのに惜しいな」って感想。もっと縮められる。
それから、せっかく「付属情報を付けてる」状態なんだから、判別に利用すべきだと思った。
そういう場合、Python3.10から追加されたmatch文を上手く使うべきだと思う。
パターンマッチは極めて強力なんで、ガンガン使おう。

そんなトコかな?

実行例

投稿2025/08/12 06:17

cametan

総合スコア158

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

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

yyicp

2025/08/12 08:07

私はnotepad++を使っているのですが、私の環境ではご提示のコードは動作しませんでした。 調べてみると、notepad++では第二引数を指定できないみたいです。 申し訳ありません。
cametan

2025/08/12 09:08

ひょっとしてCtrl+F5? ええとね、僕の書いたブツは「端末上で動く」スクリプトになっている。要はDOS窓上で実行する前提。 sys.argv[1]ってのは、コマンドライン引数を受け取るコマンドなんだ。 sys.argv: https://docs.python.org/ja/3.13/library/sys.html#sys.argv 端末上で Pythonプログラム名 引数 で実行する。この場合の引数はsample.txtになる。 基本的に、どのプログラムも、ある意味最終的には「端末上」(あるいはDOS窓/PowerShell上)で動くように持って行く、んだ。 これを「コマンドラインインターフェース」(CLI)のプログラム、と言う。GUIと違って「昔ながらの」プログラム、だね。1980年代前半までのプログラムの書き方、ではあるけど(笑)。 ただ、それが基本なんだよ。今でもね。 だから、最終的にCLIのプログラムになる、ように調節していく練習をしていけばいいと思う。
cametan

2025/08/13 03:07

リファレンスあんがと・・・・・・正直読んでて、かなりメンドいって気がした。 一つ目が、「batファイルを作成する」方針になってる事。 これは「かつてのPython」だと正しかったんだ。 ただし、今だと必ずしもそうじゃない・・・・・・。 プログラミング言語でのプログラミングでは「スクリプティング目的」と言うものがある。端末上で指令を出すと、何からの処理をしてそのまま閉じる、と。 僕が書いたような方式のプログラムだな。 これはOSを問わず、目的は「作業の自動化」なんだ。根底のアイディアではそういう事となる。 で、だ。 Windowsで使えるスクリプトと言えば代表的なのが.batファイルだよな。これは、ファイルにMS-DOSコマンドを並べて、「作業の自動化」をするわけだ。 一方、UNIX系OS(LinuxやMac OS X)だと「様々な言語でスクリプティングが可能」なように設計されている。 これは僕が書いたプログラムの冒頭、 #!/usr/bin/env python3 で可能となる。これをシェバング(Shebang)と呼ぶ。 これは「このファイルをプログラムとして呼び出す際に、まずはPython3を呼び出せ」って意味なんだ。 例えば貴方が書いたプログラムファイルをfoo.pyだとしよう。UNIX系OS上で、仮にこのシェバングが無い場合、foo.pyを端末上で動かしたい場合、 python3 -m foo.py として起動しないとならない。一々Python3 -mって毎回書かないとならないんだ。 これはメンド臭い。 要は、シェバングの役目は Python3 -mと端末上で打つ代わりにいきなり foo.py で実行出来るようにするシステム、なんだな。これなら他のCLIのアプリと変わらない「コマンド呼び出し」になる。 ただし、上にも書いたけど、Windows(と言うかMS-DOS)の「流儀」とUNIX系OSの流儀は違う。Windowsの場合はどうしても.batファイルが基本となり、シェバングは使えない。 結果、スクリプトを書く、って言う意味だとUNIX流流儀とMS-DOS流儀はかち合い、「この部分に於いては」ソースコードの可搬性が無い、って事になるわけだ。UNIXで作られたPythonファイルはWindowsで動かすには「ソースコードを修正」しないといけないし、逆もまた真なり、って事になる。 たった一行にせよ、「手間がかかる」ってのがフツーなわけ。 ところが、それこそ2018年前後かな。うろ覚えだけど。 Pythonの開発者陣はアタマが良かった。シェバングをWindowsで書かれたPythonファイルでも「動くように」設計しなおしたんだ。それにより、スクリプトのUNIX系OS <-> Windows間移動も問題なく行えるようになったわけ。 念をおしておくけど、これは「Pythonに於いてのみ」だ。他のプログラミング言語だと相変わらずbat記述とshebangには全然互換性がないんで、「書き換える必要がある」んだけど、Pythonはその辺「上手くやって」UNIX流ShebangをWindowsでも動かせるようにしちまったわけ。 従って、まず、現在のPythonではbatファイル作成の必要がない。まぁ、作ってもいいんだけど、必然性は全然落ちたよな、ってのがホントのトコだ。 いずれにせよ、「Shebangを書け」ってのが現在のWindows版PythonでもHow toにはなる。 問題は、Notepad++が「書いてるプログラムのパス」を実は全然考慮してない辺り、なんだ。今「どこのフォルダ内を対象にして作業してるのか」、ファイルを開いてる割には全然感知していない。 通常、例えばPython備え付けのIDLEなんかもそうなんだけど、コマンドライン引数を受け取るプログラムとか、確かに「動かせない」んだ。 一方、Notepad++の【ファイル名を指定して実行】は確かにパワフルだ。なんとコマンドライン引数を受け取る事が出来る。ちょっと僕の知ってる範疇だと、「軽量なテキストエディタ」でこういう機能を持ってるヤツは他には知らない。多分直接DOS窓なりPowerShellなりを暗黙に呼び出して情報を手渡す仕組みになってんだろう。恐れ入った。 一方、Notepad++は上にも書いたけど、「今開いてるファイルのアドレス」を全く感知してない。してない、って事は裏で動いているDOS窓なりPowerShellに「今ここにいますよ~♪」って情報を全く渡せないんだ。 結果、F5キーで起動して【実行するファイル】で指定する中身は プログラムへの絶対パス コマンドライン引数で与えられた絶対パスで記述されたファイル名 にせんとあかん、っちゅう・・・・・・これはかなりめんどくさいぞ(笑)。 例えばコマンドライン引数でファイル名を取るfoo.pyがある場合、F5で起動したポップアップに記述すべきコマンドは、 C:\なんたらかんたら長いパス\foo.py C:\なんたらかんたら長いパス\ファイル名 と記述せなアカンと言う・・・・・・。 ちょっとこれはめんどいね(笑)。ちとこれは困ったちゃんだ、って話になる。 便利な機能アリ、なんだけど「ツメが甘い」っつーか・・・・・・(笑)。 まぁ、それが個人的感想かな。
dodox86

2025/08/13 06:57

横からすみません。本コメント欄でやり取りされている内容は恐らく質問のおおもとの主旨とは少し異なるように思ったので話を広げるつもりは無いのですが、以下のコメントが気になったのでこれらの点だけコメントさせていただきます。 yyicpさんのコメント: > 調べてみると、notepad++では第二引数を指定できないみたいです。 cametanさんのコメント: > 一方、Notepad++は上にも書いたけど、「今開いてるファイルのアドレス」を全く感知してない。してない、って事は裏で動いているDOS窓なりPowerShellに「今ここにいますよ~♪」って情報を全く渡せないんだ。 実はそんなことは無くて、notepad++の外部プログラム実行では2個以上の引数も指定できますし、現在開いているファイルのPATHや実行時のカレントディレクトリの情報をFULL_CURRENT_PATHやCURRENT_DIRECTORY変数で渡すことができます。 [Variables for Run Commands] https://npp-user-manual.org/docs/config-files/#variables-for-run-commands 確認しました。例として、C:\_work\t1.cmdと言う以下の内容のバッチファイルを用意します。 echo "t1.cmd" echo "ARG1: %1" echo "ARG2: %2" echo "ARG3: %3" pause C:\_work\sample.txtを開いている状態で、「実行するファイル」の入力欄に以下のように3つの引数を指定して実行すると C:\_work\t1.cmd arg1 "$(FULL_CURRENT_PATH)" arg3 以下の結果を得られます。 ここから>>> C:\Program Files\Notepad++>echo "t1.cmd" "t1.cmd" C:\Program Files\Notepad++>echo "ARG1: arg1" "ARG1: arg1" C:\Program Files\Notepad++>echo "ARG2: "C:\_work\sample.txt"" "ARG2: "C:\_work\sample.txt"" C:\Program Files\Notepad++>echo "ARG3: arg3" "ARG3: arg3" C:\Program Files\Notepad++>pause 続行するには何かキーを押してください . . . <<<ここまで 渡した複数の引数も、PATHの情報も展開されていることが分かります。渡したところで用途によっては文字列加工が必要かもしれませんが、後で読んだ方が誤解をするかもしれませんので、フォローのつもりのコメントです。 確認したのはNotepad++ 8.8.4 です。
cametan

2025/08/13 08:15

> dodox86 氏 補足あんがと、です。 実の事言えば、Notepad++って使った事なくって、急遽インストールして調べてみた、ってのがホントのトコです。 多分それこそBatで設定すれば何とかなるんだろうな、とは予想はしてたんだけど、「機能の基本としては」って程度で調べるのを止めちゃってました。 いずれにせよ、補足Thanxです。
yyicp

2025/08/18 02:32

>dodox86様 補足情報、どうもありがとうございました。
guest

0

ベストアンサー

もっと自然なコードがあれば教えてください。(「自然」をどう考えるかが難しいですが・・・)

確かに「自然なコード」という表現は解釈に困るところですが、例えば Numpy を利用すると以下の様に書くことができます。

numpy.loadtxt() のデフォルト設定では # をコメント文字列の開始と見なして読み飛ばします
numpy.loadtxt — NumPy v2.3 Manual

comments: str or sequence of str or None, optional
The characters or list of characters used to indicate the start of a comment. None implies no comments. For backwards compatibility, byte strings will be decoded as ‘latin1’. The default is ‘#’.

python

1import numpy as np 2 3a = np.zeros(4) 4num, *a[1:3], ns = np.loadtxt('sample.txt') 5num, ns = num.astype(int), ns.astype(int) 6 7print(num) #0 8print(a[1]) #1.5 9print(a[2]) #2.0 10print(ns) #3

投稿2025/08/12 03:17

編集2025/08/12 06:40
melian

総合スコア21391

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

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

yyicp

2025/08/12 04:05

できました。 どうもありがとうございました。
yyicp

2025/08/12 04:34

numとnsはint型、a[1]とa[2]はfloat型で代入したくて、試しに 4行目を num, *a[1:3], ns = np.loadtxt('sample.txt', dtype = int) にすると実現できます。 0 1.0 2.0 3 intを指定しているのにa[1]とa[2]がfloatt型で入っているのは、正しく動作していると判断しても良いでしょうか。
melian

2025/08/12 04:45 編集

a = np.zeros(4) として宣言していますので a の dtype はデフォルトの float になっています。(a = np.zeros(4, dtype=float) と同義) なので、sample.txt で a[0] の行に浮動小数点数(例えば1.5)などが入っている場合、loadtxt(..., dtype = int) で読み込むと 1.0 に丸められてしまいますのでご注意ください。
yyicp

2025/08/12 05:34 編集

14:30、返事を書き直しました。 sample.txtの中身が 0 #num 1.5 #a[1] 2 #a[2] 3 #ns であったときに、 num, *a[1:3], ns = np.loadtxt('sample.txt', dtype = float) にすると 0.0 1.5 2.0 3.0 になり、 num, *a[1:3], ns = np.loadtxt('sample.txt', dtype = int) にすると、 0 1.0 2.0 3 になりますが、 出力を 0(int) 1.5(float) 2(float) 3(int) にするにはどのようにすれば良いでしょうか。 floatで読み込んで、a[1]とa[2]だけintにキャストするのでしょうか。
melian

2025/08/12 06:41

> floatで読み込んで、a[1]とa[2]だけintにキャストするのでしょうか。 はい、そうなります。回答を修正しましたのでご確認ください。
cametan

2025/08/12 06:50

Teratailバグってる? 別にこの回答にBadを押した記憶はないんだが・・・・・・。
yyicp

2025/08/12 07:01

ご回答ありがとうございました。 改めて、できました。
guest

0

そもそもとして、コメントと値が対応しているのであれば私なら以下のように定義しますね。。。

txt

1num1=0 2a[1]=1 3a[2]=2 4ns=3

投稿2025/08/15 12:58

u2025

総合スコア68

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

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

yyicp

2025/08/18 01:56 編集

ご回答ありがとうございます。 説明不足で申し訳ありませんが、以下のようなファイルが別プログラムで出力される状況を考えています。 0 #num 1 #a[1] 2 #a[2] 3 #ns
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問