You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Python字符串模板替换定制:仅允许唯一合法输出的技术问询

Ensuring All Placeholders Are Replaced & No Extra Keys Allowed

To make sure only the first print statement produces a valid output (and the other two fail), we need two key checks:

  1. Every placeholder in the template has a corresponding value in the substitution dict (already handled by substitute via KeyError for missing keys).
  2. The substitution dict doesn't contain any extra keys that aren't present as placeholders in the template (this is the missing check in your current code).

Here's the adjusted MyTemplate implementation that adds these safeguards:

import string
import re

class MyTemplate(string.Template):
    delimiter = '$'
    # Fixed the braced placeholder pattern to properly match ${name}$ (optional but correct)
    pattern = r'''
        \$(?:
          (?P<escaped>\$)|                # Matches $$ (escaped $)
          (?P<named>[_a-z][_a-z0-9]*)\$|  # Matches $name$ (named placeholder)
          (?P<braced>\{[_a-z][_a-z0-9]*\})\$|  # Matches ${name}$ (braced placeholder)
          (?P<invalid>)                   # Catches invalid $ usage
        )
    '''
    
    def substitute(self, mapping=None, **kwds):
        # Merge mapping and keyword arguments into a single dictionary
        if mapping is None:
            mapping = {}
        full_mapping = dict(mapping, **kwds)
        
        # Extract all valid placeholders from the template
        placeholders = set()
        for match in re.finditer(self.pattern, self.template, re.VERBOSE):
            groups = match.groupdict()
            # Add named placeholders
            if groups['named']:
                placeholders.add(groups['named'])
            # Add braced placeholders (strip braces to get the name)
            if groups['braced']:
                placeholders.add(groups['braced'].strip('{}'))
        
        # Check for extra keys in the substitution dict
        extra_keys = set(full_mapping.keys()) - placeholders
        if extra_keys:
            raise ValueError(f"Extra unused keys provided: {', '.join(extra_keys)}")
        
        # Let the parent class handle missing placeholders (raises KeyError)
        return super().substitute(full_mapping)

# Test cases
data1 = "max=$max$ min=$min$"
data2 = "max=$max$ "

# 1. Valid case: all placeholders present, no extra keys
try:
    print(MyTemplate(data1).substitute({"max":"10","min":"1"}))  # Output: max=10 min=1
except Exception as e:
    print(f"Error: {e}")

# 2. Invalid case: extra key 'min' provided
try:
    print(MyTemplate(data2).substitute({"max":"10","min":"1"}))
except Exception as e:
    print(f"Error: {e}")  # Output: Error: Extra unused keys provided: min

# 3. Invalid case: missing key 'min'
try:
    print(MyTemplate(data1).substitute({"max":"10"}))
except Exception as e:
    print(f"Error: {e}")  # Output: Error: 'min'

Key Changes Explained:

  • Fixed Braced Placeholder Pattern: The original pattern incorrectly treated braced placeholders the same as named ones. Now it properly matches ${name}$ if you need braced syntax.
  • Custom substitute Method:
    • Merges input mapping and keyword arguments into one dict for consistency.
    • Uses the template's regex pattern to extract all valid placeholders from the template string.
    • Checks if the substitution dict has any keys that aren't in the placeholder set, raising a ValueError if so.
    • Calls the parent substitute method, which automatically raises a KeyError if any placeholder is missing from the mapping.

This ensures only the first test case succeeds, while the other two fail with clear errors—exactly the single valid output scenario you want.

内容的提问来源于stack exchange,提问作者Gianni

火山引擎 最新活动