Repository: scrapinghub/price-parser

Issue:
Incorrect parsing when input doesn't contain digits before decimal point
'$ .75' is incorrectly parsed as 75

Discussion:

Patch:
diff --git a/price_parser/parser.py b/price_parser/parser.py
index 364ab2c..d1051e4 100644
--- a/price_parser/parser.py
+++ b/price_parser/parser.py
@@ -188,6 +188,8 @@ def extract_price_text(price: str) -> Optional[str]:
     >>> extract_price_text("50%")
     >>> extract_price_text("50")
     '50'
+    >>> extract_price_text("$.75")
+    '.75'
     """
     if price.count('€') == 1:
         m = re.search(r"""
@@ -198,14 +200,20 @@ def extract_price_text(price: str) -> Optional[str]:
         """, price, re.VERBOSE)
         if m:
             return m.group(0).replace(' ', '')
+
     m = re.search(r"""
-        (\d[\d\s.,]*)  # number, probably with thousand separators
-        \s*?           # skip whitespace
-        (?:[^%\d]|$)   # capture next symbol - it shouldn't be %
+        ([.]?\d[\d\s.,]*)   # number, probably with thousand separators
+        \s*?                # skip whitespace
+        (?:[^%\d]|$)        # capture next symbol - it shouldn't be %
         """, price, re.VERBOSE)
 
     if m:
-        return m.group(1).strip(',.').strip()
+        price_text = m.group(1).rstrip(',.')
+        return (
+            price_text.strip()
+            if price_text.count('.') == 1
+            else price_text.lstrip(',.').strip()
+        )
     if 'free' in price.lower():
         return '0'
     return None
@@ -213,7 +221,7 @@ def extract_price_text(price: str) -> Optional[str]:
 
 # NOTE: Keep supported separators in sync with parse_number()
 _search_decimal_sep = re.compile(r"""
-\d           # at least one digit (there can be more before it)
+\d*          # null or more digits (there can be more before it)
 ([.,€])      # decimal separator
 (?:          # 1,2 or 4+ digits. 3 digits is likely to be a thousand separator.
    \d{1,2}?|
@@ -237,6 +245,8 @@ def get_decimal_separator(price: str) -> Optional[str]:
     ','
     >>> get_decimal_separator("1,235€99")
     '€'
+    >>> get_decimal_separator(".75")
+    '.'
     """
     m = _search_decimal_sep(price)
     if m:


Test patch:
diff --git a/tests/test_price_parsing.py b/tests/test_price_parsing.py
index 4aee1cc..8ef2b11 100644
--- a/tests/test_price_parsing.py
+++ b/tests/test_price_parsing.py
@@ -429,6 +429,16 @@ PRICE_PARSING_EXAMPLES = [
             '€', '11,76', 11.76),
     Example('$99.99', '$99.99',
             '$', '99.99', 99.99),
+    Example(None, '.75 €',
+            '€', '.75', 0.75),
+    Example('$.75', '$.75',
+            '$', '.75', 0.75),
+    Example('$..75', '$..75',
+            '$', '.75', 0.75),
+    Example('$.75,333', '$.75,333',
+            '$', '.75,333', 75333),
+    Example('$.750.30', '$.750.30',
+            '$', '750.30', 750.30),
     Example('i', 'i',
             None, None, None),
 ]
@@ -1977,6 +1987,18 @@ PRICE_PARSING_DECIMAL_SEPARATOR_EXAMPLES = [
             '€', '1250€60', 1250.60, "€"),
     Example(None, '1250€600',
             '€', '1250€600', 1250.600, "€"),
+    Example(None, '.75 €',
+            '€', '.75', 0.75, '.'),
+    Example('$.75', '$.75',
+            '$', '.75', 0.75, '.'),
+    Example('$..75', '$..75',
+            '$', '.75', 0.75, '.'),
+    Example('$..75,333', '$..75,333',
+            '$', '.75,333', 0.75333, '.'),
+    Example('$..75,333', '$..75,333',
+            '$', '.75,333', 75.333, ','),
+    Example('$.750.30', '$.750.30',
+            '$', '750.30', 750.30, '.')
 ]