The Norway Problemについて
YAMLでは、特定の文字列が意図せず特定の型に変換されてしまうことがあります。例えば、NO
という文字列は真偽値のFalse
として解釈されます。どうやらこのような現象のことをThe Norway Problemというらしいです。ノルウェーをISO国コードで訳すと、NO
なのでそのような名前になっているそう。
norway.yaml
country: NO
load_yaml.py
import yaml
with open('norway.yaml') as file:
data = yaml.safe_load(file)
print(data)
$ python load_yaml.py
{'country': False}
これに対する解決策は簡単で、ただNO
をquoteで囲うだけです。
norway.yaml
contry: 'NO'
なんとなく今回はそのようなYAMLを検知するようなコードを考えてみました。
実際に検知するようなコードを考える
基本的にpyyamlなどは使えないので、YAMLファイルをテキストモードで読み込んで、正規表現でひっかける感じです。
check_norway_problem.py
import re
class YAMLNorwayProblemChecker:
BOOLEAN_REPRESENT_VALUES = {
"y", "Y", "yes", "Yes", "YES",
"n", "N", "no", "No", "NO",
"true", "True", "TRUE",
"false", "False", "FALSE",
"on", "On", "ON",
"off", "Off", "OFF"
}
def __init__(self, file_path):
self.file_path = file_path
self.raw_lines = self.load_raw_yaml()
def load_raw_yaml(self):
with open(self.file_path, 'r', encoding='utf-8') as f:
return f.readlines()
def check_norway_problem(self):
# 真偽値が入ることが前提のキーを除外
exclude_keys = {}
# YAMLのkey: valueパターンを定義
yaml_pattern = r'^\s*-?\s*(\S+):\s*(\S+)$'
norway_problem_detected = False
for i, line in enumerate(self.raw_lines, start=1):
# 空白削除
line = line.strip()
# 空行やコメント行はスキップ
if not line or line.startswith('#'):
continue
# 正規表現でkey: valueのペアを取得
match = re.match(yaml_pattern, line)
if match:
key, value = match.groups()
# 除外対象のキーをスキップ
if key in exclude_keys:
continue
# キーが真偽値として解釈されるかチェック
if key in self.BOOLEAN_REPRESENT_VALUES:
print(f"ノルウェー問題が検出されました。\n{i}行目: キー '{key}' を引用符で囲んでください。")
norway_problem_detected = True
# 値が真偽値として解釈されるかチェック
if value in self.BOOLEAN_REPRESENT_VALUES:
print(f"ノルウェー問題が検出されました。\n{i}行目: 値 '{value}' を引用符で囲んでください。")
norway_problem_detected = True
if not norway_problem_detected:
print("ノルウェー問題は検出されませんでした。")
if __name__ == "__main__":
yaml_file_path = "example.yaml"
checker = YAMLNorwayProblemChecker(yaml_file_path)
checker.check_norway_problem()
example.yaml
country: "NO"
switch: ON
confirm: YES
$ python check_norway_problem.py
ノルウェー問題が検出されました。
2行目: 値 'ON' を引用符で囲んでください。
ノルウェー問題が検出されました。
3行目: 値 'YES' を引用符で囲んでください。
参考