Skip to content

Commit a761c62

Browse files
akarivclaude
andcommitted
preprocess: strip bidi control chars from values; map a revised welfare header
Found via CI's first real run against freshly-downloaded data: - fix_value() flagged a batch of legitimate decimals as "BAD FLOATS" because Excel wraps numbers in invisible RTL-embedding/pop-directional- formatting Unicode control characters in Hebrew sheets - float() can't parse a string containing them even though the digits are fine. Also folded in a stray '. .' null-sentinel found in the same set. - CBS revised a source file between my local download and CI's fresh one, surfacing a new raw header variant for the income-security- recipients metric with different sheet-prefix/end-of-year phrasing. Reviewed against the canonical's other 6 orig variants (which already cover the same prefix/phrasing pattern for the "during the year" counterpart) and confirmed it's the same metric, not a new one. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent ba281d4 commit a761c62

3 files changed

Lines changed: 46 additions & 1 deletion

File tree

Lamas/data/header_mapping.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,7 @@ headers:
35843584
- מקבלי הבטחת הכנסה (נפשות, סוף שנה)
35853585
- רווחה/מקבלי גמלת הבטחת הכנסה (נפשות, בסוף השנה)
35863586
- שכר ורווחה/מקבלי גמלת הבטחת הכנסה (נפשות, במשך השנה)
3587+
- שכר ורווחה/מקבלי גמלת הבטחת הכנסה (נפשות, סוף שנה)
35873588
שכר ורווחה - מקבלי הכשרה מקצועית (סה"כ):
35883589
orig:
35893590
- מקבלי הכשרה מקצועית - סה"כ

Lamas/lamas/preprocess.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
]
2121
SPACES = re.compile(r'\s+')
2222
LETTERS = re.compile('[א-ת]')
23+
# Excel embeds invisible Unicode bidi control characters (RIGHT-TO-LEFT EMBEDDING U+202B, POP
24+
# DIRECTIONAL FORMATTING U+202C, and similar) around numbers in RTL Hebrew sheets to force correct
25+
# visual rendering direction - found for real, flagged as "BAD FLOATS" because float() can't
26+
# parse a string with invisible control characters in it even though the visible digits are fine.
27+
BIDI_CONTROL_CHARS = re.compile('[‎‏‪-‮⁦-⁩]')
2328
MAGICS = [re.compile(x) for x in MAGICS_RAW]
2429
MIN_SIZE = 30
2530
HEADER_SIZE = 5
@@ -67,7 +72,9 @@ def get_safe(data, r, c):
6772

6873

6974
def fix_value(v, bad_floats):
70-
if v in ('-', '..', '', '.', None):
75+
if v is not None:
76+
v = BIDI_CONTROL_CHARS.sub('', v).strip()
77+
if v in ('-', '..', '', '.', '. .', None):
7178
return None
7279
if 'http' in v:
7380
return None

Lamas/tests/test_preprocess.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from lamas.preprocess import fix_value
2+
3+
4+
def test_strips_bidi_control_characters_around_numbers():
5+
# Excel wraps numbers in invisible RTL-embedding/pop-directional-formatting control
6+
# characters in Hebrew (RTL) sheets - found for real, flagged as "BAD FLOATS" because
7+
# float() can't parse a string containing them even though the visible digits are fine.
8+
bad_floats = set()
9+
assert fix_value('‫22.9‬', bad_floats) == '22.9'
10+
assert fix_value('‫5.5 ‬', bad_floats) == '5.5'
11+
assert bad_floats == set()
12+
13+
14+
def test_dot_space_dot_treated_as_null():
15+
# A stray malformed null-sentinel found in the raw data (likely meant to be '..').
16+
bad_floats = set()
17+
assert fix_value('. .', bad_floats) is None
18+
assert bad_floats == set()
19+
20+
21+
def test_ordinary_sentinels_still_null():
22+
bad_floats = set()
23+
for v in ('-', '..', '', '.', None):
24+
assert fix_value(v, bad_floats) is None
25+
assert bad_floats == set()
26+
27+
28+
def test_genuinely_unparseable_value_still_flagged():
29+
bad_floats = set()
30+
fix_value('=Q94/R94100', bad_floats)
31+
assert '=Q94/R94100' in bad_floats
32+
33+
34+
def test_hebrew_text_value_passed_through_unchanged():
35+
bad_floats = set()
36+
assert fix_value('טקסט כלשהו', bad_floats) == 'טקסט כלשהו'
37+
assert bad_floats == set()

0 commit comments

Comments
 (0)