Repository: r1chardj0n3s/parse

Issue:
parse with hyphen inside the Bracket format cant be recognized 
```
rp = parse.parse("RHEL-{rhel-version}-OSE-{ose-version}", pv)
rb = parse.parse("rhaos-{ose-version}-rhel-{rhel-version}", branch)

rp['rhel-version']  == None
```
but when I change to
```
rp = parse.parse("RHEL-{rhel}-OSE-{ose}", pv)
rb = parse.parse("rhaos-{ose}-rhel-{rhel}", branch)
```

it works

Discussion:

Patch:
diff --git a/README.rst b/README.rst
index 5da36c1..6e5712d 100644
--- a/README.rst
+++ b/README.rst
@@ -441,6 +441,7 @@ To run the tests locally:
 Changelog
 ---------
 
+- 1.20.2 Template field names can now contain - character i.e. HYPHEN-MINUS, chr(0x2d)
 - 1.20.1 The `%f` directive accepts 1-6 digits, like strptime (thanks @bbertincourt)
 - 1.20.0 Added support for strptime codes (thanks @bendichter)
 - 1.19.1 Added support for sign specifiers in number formats (thanks @anntzer)
diff --git a/parse.py b/parse.py
index 422a27d..51a6953 100644
--- a/parse.py
+++ b/parse.py
@@ -11,7 +11,7 @@ from decimal import Decimal
 from functools import partial
 
 
-__version__ = "1.20.1"
+__version__ = "1.20.2"
 __all__ = ["parse", "search", "findall", "with_pattern"]
 
 log = logging.getLogger(__name__)
@@ -398,7 +398,7 @@ def extract_format(format, extra_types):
     return locals()
 
 
-PARSE_RE = re.compile(r"({{|}}|{\w*(?:\.\w+|\[[^]]+])*(?::[^}]+)?})")
+PARSE_RE = re.compile(r"({{|}}|{[\w-]*(?:\.[\w-]+|\[[^]]+])*(?::[^}]+)?})")
 
 
 class Parser(object):
@@ -476,11 +476,11 @@ class Parser(object):
 
     @property
     def named_fields(self):
-        return self._named_fields.copy()
+        return self._named_fields[:]
 
     @property
     def fixed_fields(self):
-        return self._fixed_fields.copy()
+        return self._fixed_fields[:]
 
     @property
     def format(self):
@@ -619,7 +619,7 @@ class Parser(object):
     def _to_group_name(self, field):
         # return a version of field which can be used as capture group, even
         # though it might contain '.'
-        group = field.replace(".", "_").replace("[", "_").replace("]", "_")
+        group = field.replace(".", "_").replace("[", "_").replace("]", "_").replace("-", "_")
 
         # make sure we don't collide ("a.b" colliding with "a_b")
         n = 1
@@ -629,6 +629,8 @@ class Parser(object):
                 group = field.replace(".", "_" * n)
             elif "_" in field:
                 group = field.replace("_", "_" * n)
+            elif "-" in field:
+                group = field.replace("-", "_" * n)
             else:
                 raise KeyError("duplicated group name %r" % (field,))
 


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 85b92ca..885baea 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,10 +10,10 @@ jobs:
   run-test:
     runs-on: ${{ matrix.os }}
     strategy:
+      fail-fast: false
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
         python-version:
-        - "3.7"
         - "3.8"
         - "3.9"
         - "3.10"
@@ -35,6 +35,22 @@ jobs:
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
 
+  tests-37:
+    name: Python 3.7 on ubuntu-20.04
+    runs-on: ubuntu-20.04
+    container:
+      image: python:3.7
+    steps:
+      - uses: actions/checkout@v3
+      - name: Run tests
+        run: |
+          pip install -r tests/requirements.txt
+          python -m pytest
+      - name: Upload coverage to Codecov
+        uses: codecov/codecov-action@v3
+        with:
+          token: ${{ secrets.CODECOV_TOKEN }}
+
   tests-27:
     name: Python 2.7 on ubuntu-20.04
     runs-on: ubuntu-20.04
diff --git a/tests/test_parse.py b/tests/test_parse.py
index a538c73..d2ed073 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -763,3 +763,23 @@ def test_parser_format():
     assert parser.format.format("world") == "hello world"
     with pytest.raises(AttributeError):
         parser.format = "hi {}"
+
+
+def test_hyphen_inside_field_name():
+    # https://github.com/r1chardj0n3s/parse/issues/86
+    # https://github.com/python-openapi/openapi-core/issues/672
+    template = "/local/sub/{user-id}/duration"
+    assert parse.Parser(template).named_fields == ["user_id"]
+    string = "https://dummy_server.com/local/sub/1647222638/duration"
+    result = parse.search(template, string)
+    assert result["user-id"] == "1647222638"
+
+
+def test_hyphen_inside_field_name_collision_handling():
+    template = "/foo/{user-id}/{user_id}/{user.id}/bar/"
+    assert parse.Parser(template).named_fields == ["user_id", "user__id", "user___id"]
+    string = "/foo/1/2/3/bar/"
+    result = parse.search(template, string)
+    assert result["user-id"] == "1"
+    assert result["user_id"] == "2"
+    assert result["user.id"] == "3"