diff --git a/README.rst b/README.rst
index f36c851..77af67e 100644
--- a/README.rst
+++ b/README.rst
@@ -236,6 +236,8 @@ Vladiate comes with a few common validators built-in:
 
   :``unique_with=[]``:
       List of field names to make the primary field unique with.
+  :``empty_ok=False``:
+      Specify whether a field which is an empty string should be ignored.
 
 *class* ``RegexValidator``
 
@@ -243,6 +245,8 @@ Vladiate comes with a few common validators built-in:
 
   :``pattern=r'di^'``:
       The regex pattern. Fails for all fields by default.
+  :``empty_ok=False``:
+      Specify whether a field which is an empty string should be ignored.
 
 *class* ``RangeValidator``
 
@@ -253,6 +257,8 @@ Vladiate comes with a few common validators built-in:
       The low value of the range.
   :``high``:
       The high value of the range.
+  :``empty_ok=False``:
+      Specify whether a field which is an empty string should be ignored.
 
 *class* ``EmptyValidator``
 
diff --git a/setup.py b/setup.py
index 62b35f8..b5c8c72 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ import sys
 from setuptools import setup, find_packages
 from setuptools.command.test import test as TestCommand
 
-__version__ = '0.0.17'
+__version__ = '0.0.18'
 
 
 class PyTest(TestCommand):
diff --git a/vladiate/validators.py b/vladiate/validators.py
index a425c2c..72dccdb 100644
--- a/vladiate/validators.py
+++ b/vladiate/validators.py
@@ -6,8 +6,9 @@ from vladiate.exceptions import ValidationException, BadValidatorException
 class Validator(object):
     ''' Generic Validator class '''
 
-    def __init__(self):
+    def __init__(self, empty_ok=False):
         self.fail_count = 0
+        self.empty_ok = empty_ok
 
     @property
     def bad(self):
@@ -22,8 +23,8 @@ class Validator(object):
 class CastValidator(Validator):
     ''' Validates that a field can be cast to a float '''
 
-    def __init__(self):
-        super(CastValidator, self).__init__()
+    def __init__(self, **kwargs):
+        super(CastValidator, self).__init__(**kwargs)
         self.invalid_set = set([])
 
     def validate(self, field, row={}):
@@ -42,29 +43,27 @@ class CastValidator(Validator):
 class FloatValidator(CastValidator):
     ''' Validates that a field can be cast to a float '''
 
-    def __init__(self, empty_ok=False):
-        super(FloatValidator, self).__init__()
-        self.empty_ok = empty_ok
+    def __init__(self, **kwargs):
+        super(FloatValidator, self).__init__(**kwargs)
         self.cast = float
 
 
 class IntValidator(CastValidator):
     ''' Validates that a field can be cast to an int '''
 
-    def __init__(self, empty_ok=False):
-        super(IntValidator, self).__init__()
-        self.empty_ok = empty_ok
+    def __init__(self, **kwargs):
+        super(IntValidator, self).__init__(**kwargs)
         self.cast = int
 
 
 class SetValidator(Validator):
     ''' Validates that a field is in the given set '''
 
-    def __init__(self, valid_set=[], empty_ok=False):
-        super(SetValidator, self).__init__()
+    def __init__(self, valid_set=[], **kwargs):
+        super(SetValidator, self).__init__(**kwargs)
         self.valid_set = set(valid_set)
         self.invalid_set = set([])
-        if empty_ok:
+        if self.empty_ok:
             self.valid_set.add('')
 
     def validate(self, field, row={}):
@@ -81,8 +80,8 @@ class SetValidator(Validator):
 class UniqueValidator(Validator):
     ''' Validates that a field is unique within the file '''
 
-    def __init__(self, unique_with=[]):
-        super(UniqueValidator, self).__init__()
+    def __init__(self, unique_with=[], **kwargs):
+        super(UniqueValidator, self).__init__(**kwargs)
         self.unique_values = set([])
         self.duplicates = set([])
         self.unique_with = unique_with
@@ -119,10 +118,9 @@ class UniqueValidator(Validator):
 class RegexValidator(Validator):
     ''' Validates that a field matches a given regex '''
 
-    def __init__(self, pattern=r'di^', empty_ok=False):
-        super(RegexValidator, self).__init__()
+    def __init__(self, pattern=r'di^', **kwargs):
+        super(RegexValidator, self).__init__(**kwargs)
         self.regex = re.compile(pattern)
-        self.empty_ok = empty_ok
         self.failures = set([])
 
     def validate(self, field, row={}):
@@ -137,13 +135,16 @@ class RegexValidator(Validator):
 
 
 class RangeValidator(Validator):
-    def __init__(self, low, high):
+    def __init__(self, low, high, **kwargs):
+        super(RangeValidator, self).__init__(**kwargs)
         self.fail_count = 0
         self.low = low
         self.high = high
         self.outside = set()
 
     def validate(self, field, row={}):
+        if field == '' and self.empty_ok:
+            return
         try:
             value = float(field)
             if not self.low <= value <= self.high:
@@ -164,8 +165,8 @@ class RangeValidator(Validator):
 class EmptyValidator(Validator):
     ''' Validates that a field is always empty '''
 
-    def __init__(self):
-        super(EmptyValidator, self).__init__()
+    def __init__(self, **kwargs):
+        super(EmptyValidator, self).__init__(**kwargs)
         self.nonempty = set([])
 
     def validate(self, field, row={}):
@@ -183,7 +184,8 @@ class EmptyValidator(Validator):
 class NotEmptyValidator(Validator):
     ''' Validates that a field is not empty '''
 
-    def __init__(self):
+    def __init__(self, **kwargs):
+        super(NotEmptyValidator, self).__init__(**kwargs)
         self.fail_count = 0
         self.failed = False
 

RangeValidator has no empty_ok parameter
RangeValidator has no option to allow empty records in a field. RangeValidator fails if the field contains an empty record "". Propose to add an empty_ok parameter to the RangeValidator class similar to other validators as shown below:

```python
class RangeValidator(Validator):
    def __init__(self, low, high, empty_ok=False):
        self.fail_count = 0
        self.low = low
        self.high = high
        self.empty_ok = empty_ok
        self.outside = set()

    def validate(self, field, row={}):
        if field == '' and self.empty_ok:
            pass
        else:
            try:
                value = float(field)
                if not self.low <= value <= self.high:
                    raise ValueError
            except ValueError:
                self.outside.add(field)
                raise ValidationException(
                    "'{}' is not in range {} to {}".format(
                        field, self.low, self.high
                    )
                )

    @property
    def bad(self):
        return self.outside
```
diff --git a/vladiate/test/test_validators.py b/vladiate/test/test_validators.py
index 7b80686..369e9a4 100644
--- a/vladiate/test/test_validators.py
+++ b/vladiate/test/test_validators.py
@@ -81,12 +81,6 @@ def test_set_validator_works(field_set, field):
     assert field in validator.valid_set
 
 
-def test_set_validator_empty_ok():
-    validator = SetValidator(['foo'], empty_ok=True)
-    validator.validate('')
-    assert '' in validator.valid_set
-
-
 @pytest.mark.parametrize('field_set, field', [
     ([], 'bar'),
     (['foo'], 'bar'),
@@ -139,10 +133,6 @@ def test_regex_validator_works(pattern, field):
     RegexValidator(pattern).validate(field)
 
 
-def test_regex_validator_allows_empty():
-    RegexValidator(r'foo.*', empty_ok=True).validate('')
-
-
 @pytest.mark.parametrize('pattern, field', [
     (r'foo.*', 'afoo'),
     (r'^$', 'foo'),
@@ -213,3 +203,16 @@ def test_base_class_raises():
 
     with pytest.raises(NotImplementedError):
         validator.validate(stub(), stub())
+
+
+@pytest.mark.parametrize('validator_class,args', [
+    (SetValidator, [['foo']]),
+    (RegexValidator, [r'foo.*']),
+    (IntValidator, []),
+    (FloatValidator, []),
+    (RangeValidator, [0, 42]),
+    (UniqueValidator, []),
+])
+def test_all_validators_support_empty_ok(validator_class, args):
+    validator = validator_class(*args, empty_ok=True)
+    validator.validate('')

pip install -e .[s3]
parse_log_pytest
requirements.txt
pretend pytest black
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
black==23.3.0
boto==2.49.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
click==8.1.8
exceptiongroup==1.2.2
importlib-metadata==6.7.0
iniconfig==2.0.0
mypy-extensions==1.0.0
packaging==24.0
pathspec==0.11.2
platformdirs==4.0.0
pluggy==1.2.0
pretend==1.0.9
pytest==7.4.4
tomli==2.0.1
typed-ast==1.5.5
typing_extensions==4.7.1
-e git+https://github.com/di/vladiate.git@81892a0a29bd668bc12c72e17b3f2f62f7ed0377#egg=vladiate
zipp==3.15.0

name: vladiate
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - black==23.3.0
      - boto==2.49.0
      - click==8.1.8
      - exceptiongroup==1.2.2
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - mypy-extensions==1.0.0
      - packaging==24.0
      - pathspec==0.11.2
      - platformdirs==4.0.0
      - pluggy==1.2.0
      - pretend==1.0.9
      - pytest==7.4.4
      - tomli==2.0.1
      - typed-ast==1.5.5
      - typing-extensions==4.7.1
      - zipp==3.15.0
prefix: /opt/conda/envs/vladiate

vladiate/test/test_validators.py::test_all_validators_support_empty_ok[RangeValidator-args4] vladiate/test/test_validators.py::test_all_validators_support_empty_ok[UniqueValidator-args5]
vladiate/test/test_validators.py::test_cast_validator vladiate/test/test_validators.py::test_float_validator_works[42] vladiate/test/test_validators.py::test_float_validator_works[42.0] vladiate/test/test_validators.py::test_float_validator_works[-42.0] vladiate/test/test_validators.py::test_float_validator_fails[foo] vladiate/test/test_validators.py::test_float_validator_fails[ vladiate/test/test_validators.py::test_float_validator_fails[7..0] vladiate/test/test_validators.py::test_float_validator_fails[4,200] vladiate/test/test_validators.py::test_int_validator_works[42] vladiate/test/test_validators.py::test_int_validator_fails[foo] vladiate/test/test_validators.py::test_int_validator_fails[ vladiate/test/test_validators.py::test_int_validator_fails[7..0] vladiate/test/test_validators.py::test_int_validator_fails[4,200] vladiate/test/test_validators.py::test_int_validator_fails[42.0] vladiate/test/test_validators.py::test_int_validator_fails[-42.0] vladiate/test/test_validators.py::test_set_validator_works[field_set0-foo] vladiate/test/test_validators.py::test_set_validator_works[field_set1-foo] vladiate/test/test_validators.py::test_set_validator_fails[field_set0-bar] vladiate/test/test_validators.py::test_set_validator_fails[field_set1-bar] vladiate/test/test_validators.py::test_set_validator_fails[field_set2-baz] vladiate/test/test_validators.py::test_unique_validator_works[fields0-row0-unique_with0] vladiate/test/test_validators.py::test_unique_validator_works[fields1-row1-unique_with1] vladiate/test/test_validators.py::test_unique_validator_works[fields2-row2-unique_with2] vladiate/test/test_validators.py::test_unique_validator_works[fields3-row3-unique_with3] vladiate/test/test_validators.py::test_unique_validator_fails[fields0-row0-unique_with0-ValidationException-bad0] vladiate/test/test_validators.py::test_unique_validator_fails[fields1-row1-unique_with1-ValidationException-bad1] vladiate/test/test_validators.py::test_unique_validator_fails[fields2-row2-unique_with2-BadValidatorException-bad2] vladiate/test/test_validators.py::test_regex_validator_works[foo.*-foo] vladiate/test/test_validators.py::test_regex_validator_works[foo.*-foobar] vladiate/test/test_validators.py::test_regex_validator_fails[foo.*-afoo] vladiate/test/test_validators.py::test_regex_validator_fails[^$-foo] vladiate/test/test_validators.py::test_range_validator_works vladiate/test/test_validators.py::test_range_validator_fails vladiate/test/test_validators.py::test_range_validator_handles_bad_values vladiate/test/test_validators.py::test_empty_validator_works vladiate/test/test_validators.py::test_empty_validator_fails vladiate/test/test_validators.py::test_non_empty_validator_works vladiate/test/test_validators.py::test_non_empty_validator_fails vladiate/test/test_validators.py::test_ignore_validator vladiate/test/test_validators.py::test_base_class_raises vladiate/test/test_validators.py::test_all_validators_support_empty_ok[SetValidator-args0] vladiate/test/test_validators.py::test_all_validators_support_empty_ok[RegexValidator-args1] vladiate/test/test_validators.py::test_all_validators_support_empty_ok[IntValidator-args2] vladiate/test/test_validators.py::test_all_validators_support_empty_ok[FloatValidator-args3]
README.rst vladiate/validators.py setup.py
README.rst vladiate/validators.py setup.py