Pythonで改行を含む文字列を操作する方法:出力・連結・分割・削除・置換完全版

 

改行を含む文字列の出力

基本的な改行文字の出力

# \nを使った改行
text = "行1\n行2\n行3"
print(text)

# printの複数引数
print("行1", "行2", "行3", sep="\n")

# f文字列での改行
name = "Python"
message = f"こんにちは\n{name}の世界へ\nようこそ"
print(message)

トリプルクォートによる複数行文字列

multiline = """これは
複数行の
文字列です"""
print(multiline)

# インデントを含む場合
code_sample = """
def hello():
    print("Hello, World!")
    return True
"""
print(code_sample)

repr()とprint()の違い

text = "行1\n行2\n行3"
print("print()での出力:")
print(text)

print("\nrepr()での出力:")
print(repr(text))  # '行1\n行2\n行3'

# エスケープシーケンスを確認
print("\n各種改行文字:")
print(repr("Unix: \n"))
print(repr("Windows: \r\n"))
print(repr("旧Mac: \r"))

textwrapを使った高度な整形出力

import textwrap

long_text = "これは非常に長いテキストで、複数行に分割して表示したい内容です。適切な幅で改行されるように調整します。自動的に単語境界で改行されます。"

# 基本的な折り返し
wrapped = textwrap.fill(long_text, width=30)
print("基本的な折り返し:")
print(wrapped)

# インデント付きの出力
indented = textwrap.indent(wrapped, "  ")
print("\nインデント付き:")
print(indented)

# 最初の行だけ異なるインデント
hanging_indent = textwrap.fill(long_text, width=40, 
                              initial_indent="■ ", 
                              subsequent_indent="   ")
print("\nハンギングインデント:")
print(hanging_indent)

# 既存のインデントを削除
dedented = textwrap.dedent("""
    これは
        インデントされた
    テキストです
""")
print("\n既存インデント削除:")
print(dedented)

表形式での出力

def print_table(data, headers):
    """データを表形式で出力"""
    # 各列の最大幅を計算
    col_widths = [len(header) for header in headers]
    for row in data:
        for i, cell in enumerate(row):
            col_widths[i] = max(col_widths[i], len(str(cell)))
    
    # ヘッダー出力
    header_row = " | ".join(header.ljust(col_widths[i]) 
                           for i, header in enumerate(headers))
    print(header_row)
    print("-" * len(header_row))
    
    # データ行出力
    for row in data:
        data_row = " | ".join(str(cell).ljust(col_widths[i]) 
                             for i, cell in enumerate(row))
        print(data_row)

# 使用例
headers = ["名前", "年齢", "職業"]
data = [
    ["田中太郎", "30", "エンジニア"],
    ["佐藤花子", "25", "デザイナー"],
    ["鈴木次郎", "35", "マネージャー"]
]

print_table(data, headers)

改行を含む文字列の連結

join()を使った効率的な連結

lines = ["行1", "行2", "行3"]
text = "\n".join(lines)
print(text)

# 異なる改行文字での連結
windows_text = "\r\n".join(lines)
print(repr(windows_text))  # '行1\r\n行2\r\n行3'

# 空行を挟んだ連結
sections = ["セクション1", "セクション2", "セクション3"]
document = "\n\n".join(sections)
print(document)

複数行文字列の連結

header = """ヘッダー情報
タイトル: データ分析
日付: 2024-08-06"""

body = """本文:
データ分析の結果を
以下に示します。"""

footer = """フッター:
以上です。"""

# 改行で連結
full_document = "\n\n".join([header, body, footer])
print(full_document)

複雑な連結パターン

# 条件付き連結
def join_non_empty_lines(lines, separator="\n"):
    """空でない行のみを連結"""
    return separator.join(line for line in lines if line.strip())

mixed_lines = ["行1", "", "行2", "   ", "行3"]
clean_text = join_non_empty_lines(mixed_lines)
print(repr(clean_text))

# 番号付きリストとしての連結
items = ["項目A", "項目B", "項目C"]
numbered_list = "\n".join(f"{i+1}. {item}" for i, item in enumerate(items))
print(numbered_list)

# インデント付きの階層構造
def create_hierarchical_text(data, indent_size=2):
    """階層データを改行とインデントで表現"""
    result = []
    
    def process_item(item, level=0):
        indent = " " * (level * indent_size)
        if isinstance(item, dict):
            for key, value in item.items():
                result.append(f"{indent}{key}:")
                if isinstance(value, (dict, list)):
                    process_item(value, level + 1)
                else:
                    result.append(f"{indent}  {value}")
        elif isinstance(item, list):
            for subitem in item:
                process_item(subitem, level)
        else:
            result.append(f"{indent}{item}")
    
    process_item(data)
    return "\n".join(result)

data = {
    "プロジェクト": {
        "名前": "Python学習",
        "タスク": ["基礎文法", "応用", "実践"]
    }
}
hierarchical = create_hierarchical_text(data)
print(hierarchical)

# CSVデータの構造化連結
def format_csv_data(data, headers=None):
    """データを整形されたCSV形式で連結"""
    lines = []
    
    if headers:
        lines.append(",".join(headers))
    
    for row in data:
        formatted_row = ",".join(f'"{str(cell)}"' if ',' in str(cell) or '\n' in str(cell) else str(cell) 
                                for cell in row)
        lines.append(formatted_row)
    
    return "\n".join(lines)

csv_data = [
    ["田中", "30", "エンジニア"],
    ["佐藤", "25", "デザイナー, UI/UX"],
    ["鈴木", "35", "マネージャー"]
]
headers = ["名前", "年齢", "職業"]
formatted_csv = format_csv_data(csv_data, headers)
print(formatted_csv)

改行を含む文字列の分割

splitlines()による行分割

multiline = """行1
行2
行3"""

lines = multiline.splitlines()
print(lines)  # ['行1', '行2', '行3']

# 改行文字を保持
lines_with_breaks = multiline.splitlines(keepends=True)
print(lines_with_breaks)  # ['行1\n', '行2\n', '行3']

# 各改行文字の長さを確認
for line in lines_with_breaks:
    print(f"'{line}' 長さ: {len(line)}")

異なる改行文字への対応

# 混在する改行文字
mixed_newlines = "行1\n行2\r\n行3\r行4"
lines = mixed_newlines.splitlines()
print(lines)  # ['行1', '行2', '行3', '行4']

print("元の文字列の改行文字:")
print(repr(mixed_newlines))

# 手動で改行文字を確認
for i, char in enumerate(mixed_newlines):
    if char in '\r\n':
        print(f"位置{i}: {repr(char)}")

高度な分割パターン

import re

def advanced_split(text, keep_separators=False):
    """高度な改行分割(空行やコメント行の処理)"""
    lines = text.splitlines()
    result = {
        'all_lines': lines,
        'non_empty': [line for line in lines if line.strip()],
        'comment_lines': [line for line in lines if line.strip().startswith('#')],
        'code_lines': [line for line in lines if line.strip() and not line.strip().startswith('#')],
        'indented_lines': [line for line in lines if line.startswith(' ') or line.startswith('\t')],
        'line_numbers': [(i+1, line) for i, line in enumerate(lines)]
    }
    return result

sample_code = """# これはPythonコード
def hello():
    # コメント
    print("Hello")
    return True

# 別の関数
def goodbye():
    print("Goodbye")"""

analysis = advanced_split(sample_code)
print("全ての行:")
for num, line in analysis['line_numbers']:
    print(f"{num:2d}: {line}")

print(f"\n空でない行: {len(analysis['non_empty'])}行")
print(f"コメント行: {len(analysis['comment_lines'])}行")
print(f"コード行: {len(analysis['code_lines'])}行")

# 段落による分割
def split_paragraphs(text):
    """空行で区切られた段落に分割"""
    paragraphs = re.split(r'\n\s*\n', text.strip())
    return [p.strip() for p in paragraphs if p.strip()]

document = """これは最初の段落です。
複数行にわたります。

これは二番目の段落です。


これは三番目の段落で、
やはり複数行です。"""

paragraphs = split_paragraphs(document)
for i, paragraph in enumerate(paragraphs, 1):
    print(f"段落{i}:")
    print(paragraph)
    print()

条件付き分割

def conditional_split(text, condition_func=None, max_length=None):
    """条件に基づいた行分割"""
    lines = text.splitlines()
    
    if condition_func:
        lines = [line for line in lines if condition_func(line)]
    
    if max_length:
        # 長すぎる行を分割
        result = []
        for line in lines:
            if len(line) <= max_length:
                result.append(line)
            else:
                # 指定文字数で分割
                for i in range(0, len(line), max_length):
                    result.append(line[i:i+max_length])
        lines = result
    
    return lines

# テストデータ
long_text = """これは短い行
これは非常に長い行でテキストが続いていて最大文字数を超えています
普通の長さの行
もう一つの非常に長い行でこちらも最大文字数を大幅に超えている内容です"""

# 30文字以上の行のみ抽出し、50文字で分割
filtered = conditional_split(long_text, 
                           condition_func=lambda x: len(x) >= 30,
                           max_length=50)
for line in filtered:
    print(f"({len(line)}文字) {line}")

改行文字の削除

strip系メソッドによる削除

# 各行から改行を削除
lines_with_newlines = ["行1\n", "行2\r\n", "行3\r"]
clean_lines = [line.rstrip('\r\n') for line in lines_with_newlines]
print(clean_lines)  # ['行1', '行2', '行3']

# 文字列全体から改行を削除
multiline = "行1\n行2\n行3"
no_newlines = multiline.replace('\n', '')
print(no_newlines)  # 行1行2行3

# スペースで置換
spaced = multiline.replace('\n', ' ')
print(spaced)  # 行1 行2 行3

正規表現による改行削除

import re

text = "行1\r\n行2\n行3\r行4"

# すべての改行を削除
no_breaks = re.sub(r'\r?\n|\r', '', text)
print(no_breaks)  # 行1行2行3行4

# 改行をスペースに置換
spaced = re.sub(r'\r?\n|\r', ' ', text)
print(spaced)  # 行1 行2 行3 行4

# 連続する改行を1つに統一
multiple_breaks = "行1\n\n\n行2\r\n\r\n行3"
single_breaks = re.sub(r'(\r?\n){2,}', '\n', multiple_breaks)
print(repr(single_breaks))

条件付きの改行削除

def smart_newline_removal(text, preserve_paragraphs=True):
    """スマートな改行削除"""
    if preserve_paragraphs:
        # 段落境界(2つ以上の改行)は保持
        paragraphs = re.split(r'\n\s*\n', text)
        processed_paragraphs = []
        
        for paragraph in paragraphs:
            # 段落内の改行は削除してスペースに
            cleaned = re.sub(r'\s*\n\s*', ' ', paragraph.strip())
            if cleaned:
                processed_paragraphs.append(cleaned)
        
        return '\n\n'.join(processed_paragraphs)
    else:
        # 全ての改行を削除
        return re.sub(r'\s*\n\s*', ' ', text.strip())

sample_text = """これは最初の段落です。
この段落は複数行に
わたっています。

これは二番目の段落です。
こちらも複数行です。

これは最後の段落です。"""

print("段落保持:")
print(smart_newline_removal(sample_text, preserve_paragraphs=True))
print("\n全て削除:")
print(smart_newline_removal(sample_text, preserve_paragraphs=False))

# ファイル読み込み時の改行処理
def clean_file_lines(lines):
    """ファイルから読み込んだ行をクリーンアップ"""
    cleaned = []
    for line in lines:
        # 行末の改行文字と余分な空白を削除
        cleaned_line = line.rstrip('\r\n\t ')
        # 空行でない場合のみ追加
        if cleaned_line:
            cleaned.append(cleaned_line)
    return cleaned

# テスト用データ
file_like_data = ["行1\n", "  \n", "行2\r\n", "\t\n", "行3"]
cleaned_data = clean_file_lines(file_like_data)
print("クリーンアップ後:", cleaned_data)

改行文字の置換

replace()による基本的な置換

# \nを<br>に置換(HTML用)
text = "行1\n行2\n行3"
html_text = text.replace('\n', '<br>')
print(html_text)  # 行1<br>行2<br>行3

# Windows形式からUnix形式への変換
windows_text = "行1\r\n行2\r\n行3"
unix_text = windows_text.replace('\r\n', '\n')
print(repr(unix_text))  # '行1\n行2\n行3'

複数の改行文字を統一

import re

def normalize_newlines(text, target='\n'):
    """すべての改行文字を指定文字に統一"""
    # まず\r\nを処理(\rと\nの個別処理より先に)
    normalized = re.sub(r'\r\n', target, text)
    # 残りの\rを処理
    normalized = re.sub(r'\r', target, normalized)
    return normalized

mixed_text = "行1\r\n行2\n行3\r行4"
normalized = normalize_newlines(mixed_text)
print(repr(normalized))  # '行1\n行2\n行3\n行4'

# HTML改行に変換
html_normalized = normalize_newlines(mixed_text, '<br>\n')
print(html_normalized)

高度な改行置換

def advanced_newline_replacement(text, replacement_map=None):
    """高度な改行置換パターン"""
    if replacement_map is None:
        replacement_map = {
            'single': '\n',      # 単一改行
            'double': '\n\n',    # 段落区切り
            'html': '<br>',      # HTML改行
            'space': ' ',        # スペース
            'markdown': '  \n'   # Markdown改行
        }
    
    patterns = {
        'consecutive_newlines': r'\n{3,}',  # 3つ以上の連続改行
        'mixed_newlines': r'\r\n|\r',       # Windows/Mac改行
        'single_newline': r'\n',            # 単一改行
        'whitespace_newline': r'\s*\n\s*'   # 前後空白付き改行
    }
    
    results = {}
    
    # 連続改行を段落区切りに
    results['paragraph'] = re.sub(patterns['consecutive_newlines'], 
                                 replacement_map['double'], text)
    
    # 混在改行を統一
    results['normalized'] = re.sub(patterns['mixed_newlines'], 
                                  replacement_map['single'], text)
    
    # HTML形式
    results['html'] = re.sub(patterns['single_newline'], 
                            replacement_map['html'], text)
    
    # 前後空白を含む改行をスペースに
    results['spaced'] = re.sub(patterns['whitespace_newline'], 
                              replacement_map['space'], text)
    
    return results

sample_text = "行1\n\n\n行2\r\n行3 \n 行4"
results = advanced_newline_replacement(sample_text)

for key, result in results.items():
    print(f"{key}: {repr(result)}")

# 特殊な置換パターン
def format_for_display(text, line_numbers=True, max_width=50):
    """表示用に改行を調整"""
    lines = text.splitlines()
    formatted_lines = []
    
    for i, line in enumerate(lines, 1):
        # 長すぎる行を折り返し
        if len(line) > max_width:
            words = line.split()
            current_line = ""
            
            for word in words:
                if len(current_line + " " + word) > max_width:
                    if current_line:
                        formatted_lines.append((i, current_line))
                        current_line = word
                    else:
                        formatted_lines.append((i, word[:max_width]))
                        current_line = word[max_width:]
                else:
                    current_line += (" " + word) if current_line else word
            
            if current_line:
                formatted_lines.append((i, current_line))
        else:
            formatted_lines.append((i, line))
    
    if line_numbers:
        return '\n'.join(f"{num:3d}: {line}" for num, line in formatted_lines)
    else:
        return '\n'.join(line for num, line in formatted_lines)

long_text = "これは非常に長い行でテキストが続いていて指定された最大幅を超えています\n短い行\n別の長い行でこちらも最大幅を超えている内容が含まれています"
formatted = format_for_display(long_text)
print("整形後:")
print(formatted)

実用的な活用例

ファイル読み込み時の改行処理

def read_file_clean(filename):
    """ファイルを読み込み、改行を適切に処理"""
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            lines = [line.rstrip('\n\r') for line in file]
            return lines
    except FileNotFoundError:
        return []

def write_multiline_file(filename, lines):
    """複数行をファイルに書き込み"""
    with open(filename, 'w', encoding='utf-8') as file:
        file.write('\n'.join(lines))

ログメッセージの整形

import datetime

def format_log_message(level, message):
    """ログメッセージを複数行で整形"""
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    # 長いメッセージを適切に改行
    if len(message) > 80:
        lines = []
        words = message.split()
        current_line = ""
        
        for word in words:
            if len(current_line + " " + word) > 80:
                lines.append(current_line)
                current_line = word
            else:
                current_line += (" " + word) if current_line else word
        
        if current_line:
            lines.append(current_line)
        
        formatted_message = f"[{timestamp}] {level}:\n" + "\n".join(f"  {line}" for line in lines)
    else:
        formatted_message = f"[{timestamp}] {level}: {message}"
    
    return formatted_message

long_message = "これは非常に長いエラーメッセージで、複数行に分割して表示したい内容です。ログの可読性を向上させるために適切に整形します。"
formatted = format_log_message("ERROR", long_message)
print(formatted)

マークダウンテキストの処理

def process_markdown_text(markdown):
    """マークダウンテキストの改行を処理"""
    lines = markdown.splitlines()
    processed_lines = []
    
    for line in lines:
        stripped = line.strip()
        
        # 空行は保持
        if not stripped:
            processed_lines.append('')
            continue
        
        # ヘッダー行
        if stripped.startswith('#'):
            processed_lines.append(stripped)
        # リスト行
        elif stripped.startswith(('- ', '* ', '+ ')) or re.match(r'^\d+\.', stripped):
            processed_lines.append(stripped)
        # 通常のテキスト行
        else:
            processed_lines.append(stripped)
    
    return '\n'.join(processed_lines)

markdown_sample = """
# タイトル

これは段落です。


- リスト項目1
- リスト項目2

別の段落です。
"""

processed = process_markdown_text(markdown_sample)
print(processed)

CSVデータの改行処理

import csv
from io import StringIO

def handle_multiline_csv(csv_content):
    """改行を含むCSVデータを処理"""
    # StringIOを使用してメモリ上でCSV処理
    csv_file = StringIO(csv_content)
    reader = csv.reader(csv_file)
    
    processed_rows = []
    for row in reader:
        # 各フィールドの改行文字を処理
        processed_row = [field.replace('\n', ' ') for field in row]
        processed_rows.append(processed_row)
    
    return processed_rows

csv_data = '''名前,説明,価格
商品A,"これは
複数行の
説明です",1000
商品B,単行説明,2000'''

processed_csv = handle_multiline_csv(csv_data)
for row in processed_csv:
    print(row)

改行文字の検出と分析

import re
from collections import Counter

def analyze_newlines(text):
    """テキスト内の改行文字を分析"""
    # 各種改行文字をカウント
    lf_count = text.count('\n')
    cr_count = text.count('\r')
    crlf_count = text.count('\r\n')
    
    # 実際のCRだけの数(CRLF分を除く)
    actual_cr = cr_count - crlf_count
    
    analysis = {
        'LF (\\n)': lf_count - crlf_count,  # CRLFのLF分を除く
        'CR (\\r)': actual_cr,
        'CRLF (\\r\\n)': crlf_count,
        'total_lines': len(text.splitlines()),
        'empty_lines': len([line for line in text.splitlines() if not line.strip()])
    }
    
    return analysis

sample_text = "行1\n行2\r\n行3\r行4\n\n行6"
analysis = analyze_newlines(sample_text)
for key, value in analysis.items():
    print(f"{key}: {value}")

パフォーマンス最適化

import time

def benchmark_multiline_operations():
    """複数行文字列操作のパフォーマンス比較"""
    lines = ["行" + str(i) for i in range(10000)]
    
    # join()による連結
    start = time.time()
    text1 = '\n'.join(lines)
    time1 = time.time() - start
    
    # +演算子による連結(非効率)
    start = time.time()
    text2 = ""
    for line in lines[:100]:  # 小さいサンプルでテスト
        text2 += line + '\n'
    time2 = time.time() - start
    
    # splitlines()による分割
    start = time.time()
    split_lines = text1.splitlines()
    time3 = time.time() - start
    
    print(f"join()連結: {time1:.6f}秒")
    print(f"+演算子連結(100行): {time2:.6f}秒")
    print(f"splitlines()分割: {time3:.6f}秒")

benchmark_multiline_operations()

エラーハンドリング

def safe_multiline_operation(text, operation='split'):
    """改行を含む文字列操作を安全に実行"""
    if text is None:
        return []
    
    if not isinstance(text, str):
        text = str(text)
    
    try:
        if operation == 'split':
            return text.splitlines()
        elif operation == 'normalize':
            import re
            return re.sub(r'\r\n|\r', '\n', text)
        elif operation == 'remove':
            return text.replace('\n', '').replace('\r', '')
        else:
            return text
    except Exception as e:
        print(f"エラーが発生しました: {e}")
        return text if operation not in ['split'] else 

# テスト
test_cases = [None, 123, "正常な\n複数行\nテキスト"]
for test_case in test_cases:
    result = safe_multiline_operation(test_case, 'split')
    print(f"{test_case} → {result}")

複雑な改行パターンの処理

import re

def advanced_newline_processing(text):
    """複雑な改行パターンを処理"""
    # 行末のスペースを削除してから改行を正規化
    text = re.sub(r' +\n', '\n', text)
    text = re.sub(r' +\r\n', '\r\n', text)
    
    # 改行文字を統一
    text = re.sub(r'\r\n|\r', '\n', text)
    
    # 3つ以上連続する改行を2つに制限
    text = re.sub(r'\n{3,}', '\n\n', text)
    
    # 行頭・行末の無駄なスペースを削除
    lines = text.splitlines()
    cleaned_lines = [line.strip() for line in lines]
    
    # 空行の連続を制限
    final_lines = []
    prev_empty = False
    
    for line in cleaned_lines:
        if not line:  # 空行
            if not prev_empty:
                final_lines.append(line)
            prev_empty = True
        else:
            final_lines.append(line)
            prev_empty = False
    
    return '\n'.join(final_lines)

messy_text = """


  行1  

  

  行2  


  行3  


"""

cleaned = advanced_newline_processing(messy_text)
print(repr(cleaned))

まとめ

改行を含む文字列の操作では、以下の点に注意することが重要です:

  • 出力: print()、トリプルクォート、textwrapモジュール
  • 連結: join()メソッドが最も効率的
  • 分割: splitlines()で様々な改行文字に対応
  • 削除・置換: 用途に応じてstrip(), replace(), 正規表現を使い分け
  • プラットフォーム対応: Windows(CRLF)、Unix/Mac(LF)の違いを考慮

これらを適切に使い分けることで、クロスプラットフォームで動作する堅牢な文字列処理が実現できます。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座