Repository: Unidata/MetPy

Issue:
Metar doesn't parse correctly
### What went wrong?

Metar


DEN
1/24/17 16:00
KDEN 241600Z 02010KT 1/16SM R35L/1000V1200FT FZFG VV001 M01/M02 A2954 RMK AO2 SFC VIS M1/4 T10111022

isn't parsed correctly. output dataframe (pasted below) doesn't have visibility,  weather condition 'FZFG' and has a cloud coverage of 10


station_id | latitude | longitude | elevation | date_time | wind_direction | wind_speed | wind_gust | visibility | current_wx1 | current_wx2 | current_wx3 | low_cloud_type | low_cloud_level | medium_cloud_type | medium_cloud_level | high_cloud_type | high_cloud_level | highest_cloud_type | highest_cloud_level | cloud_coverage 
-- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --

KDEN | 39.85 | -104.65 | 1640 | 2022-11-24 16:00:00 | 20 | 10.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 10

<img width="1136" alt="Screen Shot 2022-11-29 at 9 37 56 AM" src="https://user-images.githubusercontent.com/20389089/204602095-172e8fb7-c1cc-485d-bc08-fc3365867c73.png">




### Operating System

MacOS

### Version

1.3

### Python Version

3.9.12

### Code to Reproduce

```python
from metpy import io

df = io.parse_metar_to_dataframe('KDEN 241600Z 02010KT 1/16SM R35L/1000V1200FT FZFG VV001 M01/M02 A2954 RMK AO2 SFC VIS M1/4 T10111022')

df.head()
```


### Errors, Traceback, and Logs

_No response_

Discussion:

Patch:
diff --git a/src/metpy/io/_metar_parser/metar_parser.peg b/src/metpy/io/_metar_parser/metar_parser.peg
index de6d6a566f..7ad325f9ba 100644
--- a/src/metpy/io/_metar_parser/metar_parser.peg
+++ b/src/metpy/io/_metar_parser/metar_parser.peg
@@ -10,7 +10,7 @@ wind_dir <- (([\d] [\d] [\d]) / 'VAR' / 'VRB' / "///")?
 wind_spd <- (([\d] [\d] [\d]?) / "//")?
 gust     <- ("G" [\d]+)?
 varwind  <- sep [\d] [\d] [\d] "V" [\d] [\d] [\d]
-vis      <- ((sep ( ([\d] [\d] [\d] [\d] ("NDV")?) / ([\d] ([\d] / ((" " [\d])? "/" [\d]))? "SM") / ("M" [\d] "/" [\d] "SM") / "CAVOK" / "////") varvis?))?
+vis      <- ((sep ( ([\d] [\d] [\d] [\d] ("NDV")?) / ([\d] ([\d] / ((" " [\d])? "/" [\d] [\d]?))? "SM") / ("M" [\d] "/" [\d] "SM") / "CAVOK" / "////") varvis?))?
 varvis   <- sep [\d] [\d] [\d] [\d] [NSEW]? [NSEW]?
 run      <- ((sep "R" [LRC]? [\d] [\d] [LRC]? "/" ([\d] [\d] [\d] [\d] "V")? ["M" / "P"]? [\d] [\d] [\d] [\d] "FT"? ("/"? [UDN])?))*
 curwx    <- (((sep "//") / (sep "NSW") / (sep (wx))*))?
diff --git a/src/metpy/io/_metar_parser/metar_parser.py b/src/metpy/io/_metar_parser/metar_parser.py
index 26aee7f9e7..fd17e25e8d 100644
--- a/src/metpy/io/_metar_parser/metar_parser.py
+++ b/src/metpy/io/_metar_parser/metar_parser.py
@@ -148,35 +148,36 @@ class Grammar(object):
     REGEX_30 = re.compile('^[\\d]')
     REGEX_31 = re.compile('^[\\d]')
     REGEX_32 = re.compile('^[\\d]')
-    REGEX_33 = re.compile('^[NSEW]')
+    REGEX_33 = re.compile('^[\\d]')
     REGEX_34 = re.compile('^[NSEW]')
-    REGEX_35 = re.compile('^[LRC]')
-    REGEX_36 = re.compile('^[\\d]')
+    REGEX_35 = re.compile('^[NSEW]')
+    REGEX_36 = re.compile('^[LRC]')
     REGEX_37 = re.compile('^[\\d]')
-    REGEX_38 = re.compile('^[LRC]')
-    REGEX_39 = re.compile('^[\\d]')
+    REGEX_38 = re.compile('^[\\d]')
+    REGEX_39 = re.compile('^[LRC]')
     REGEX_40 = re.compile('^[\\d]')
     REGEX_41 = re.compile('^[\\d]')
     REGEX_42 = re.compile('^[\\d]')
-    REGEX_43 = re.compile('^["M" / "P"]')
-    REGEX_44 = re.compile('^[\\d]')
+    REGEX_43 = re.compile('^[\\d]')
+    REGEX_44 = re.compile('^["M" / "P"]')
     REGEX_45 = re.compile('^[\\d]')
     REGEX_46 = re.compile('^[\\d]')
     REGEX_47 = re.compile('^[\\d]')
-    REGEX_48 = re.compile('^[UDN]')
-    REGEX_49 = re.compile('^[-+]')
-    REGEX_50 = re.compile('^[\\d]')
-    REGEX_51 = re.compile('^[M]')
-    REGEX_52 = re.compile('^[\\d]')
+    REGEX_48 = re.compile('^[\\d]')
+    REGEX_49 = re.compile('^[UDN]')
+    REGEX_50 = re.compile('^[-+]')
+    REGEX_51 = re.compile('^[\\d]')
+    REGEX_52 = re.compile('^[M]')
     REGEX_53 = re.compile('^[\\d]')
-    REGEX_54 = re.compile('^[M]')
-    REGEX_55 = re.compile('^[\\d]')
+    REGEX_54 = re.compile('^[\\d]')
+    REGEX_55 = re.compile('^[M]')
     REGEX_56 = re.compile('^[\\d]')
-    REGEX_57 = re.compile('^["Q" / "A"]')
-    REGEX_58 = re.compile('^[\\d]')
+    REGEX_57 = re.compile('^[\\d]')
+    REGEX_58 = re.compile('^["Q" / "A"]')
     REGEX_59 = re.compile('^[\\d]')
     REGEX_60 = re.compile('^[\\d]')
     REGEX_61 = re.compile('^[\\d]')
+    REGEX_62 = re.compile('^[\\d]')
 
     def _read_ob(self):
         address0, index0 = FAILURE, self._offset
@@ -1438,6 +1439,29 @@ class Grammar(object):
                                         self._expected.append(('METAR::vis', '[\\d]'))
                                 if address14 is not FAILURE:
                                     elements3.append(address14)
+                                    address15 = FAILURE
+                                    index12 = self._offset
+                                    chunk11, max11 = None, self._offset + 1
+                                    if max11 <= self._input_size:
+                                        chunk11 = self._input[self._offset:max11]
+                                    if chunk11 is not None and Grammar.REGEX_27.search(chunk11):
+                                        address15 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
+                                        self._offset = self._offset + 1
+                                    else:
+                                        address15 = FAILURE
+                                        if self._offset > self._failure:
+                                            self._failure = self._offset
+                                            self._expected = []
+                                        if self._offset == self._failure:
+                                            self._expected.append(('METAR::vis', '[\\d]'))
+                                    if address15 is FAILURE:
+                                        address15 = TreeNode(self._input[index12:index12], index12, [])
+                                        self._offset = index12
+                                    if address15 is not FAILURE:
+                                        elements3.append(address15)
+                                    else:
+                                        elements3 = None
+                                        self._offset = index9
                                 else:
                                     elements3 = None
                                     self._offset = index9
@@ -1459,22 +1483,22 @@ class Grammar(object):
                         self._offset = index7
                     if address9 is not FAILURE:
                         elements2.append(address9)
-                        address15 = FAILURE
-                        chunk11, max11 = None, self._offset + 2
-                        if max11 <= self._input_size:
-                            chunk11 = self._input[self._offset:max11]
-                        if chunk11 == 'SM':
-                            address15 = TreeNode(self._input[self._offset:self._offset + 2], self._offset, [])
+                        address16 = FAILURE
+                        chunk12, max12 = None, self._offset + 2
+                        if max12 <= self._input_size:
+                            chunk12 = self._input[self._offset:max12]
+                        if chunk12 == 'SM':
+                            address16 = TreeNode(self._input[self._offset:self._offset + 2], self._offset, [])
                             self._offset = self._offset + 2
                         else:
-                            address15 = FAILURE
+                            address16 = FAILURE
                             if self._offset > self._failure:
                                 self._failure = self._offset
                                 self._expected = []
                             if self._offset == self._failure:
                                 self._expected.append(('METAR::vis', '"SM"'))
-                        if address15 is not FAILURE:
-                            elements2.append(address15)
+                        if address16 is not FAILURE:
+                            elements2.append(address16)
                         else:
                             elements2 = None
                             self._offset = index6
@@ -1491,113 +1515,113 @@ class Grammar(object):
                     self._offset = self._offset
                 if address2 is FAILURE:
                     self._offset = index3
-                    index12, elements5 = self._offset, []
-                    address16 = FAILURE
-                    chunk12, max12 = None, self._offset + 1
-                    if max12 <= self._input_size:
-                        chunk12 = self._input[self._offset:max12]
-                    if chunk12 == 'M':
-                        address16 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
+                    index13, elements5 = self._offset, []
+                    address17 = FAILURE
+                    chunk13, max13 = None, self._offset + 1
+                    if max13 <= self._input_size:
+                        chunk13 = self._input[self._offset:max13]
+                    if chunk13 == 'M':
+                        address17 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                         self._offset = self._offset + 1
                     else:
-                        address16 = FAILURE
+                        address17 = FAILURE
                         if self._offset > self._failure:
                             self._failure = self._offset
                             self._expected = []
                         if self._offset == self._failure:
                             self._expected.append(('METAR::vis', '"M"'))
-                    if address16 is not FAILURE:
-                        elements5.append(address16)
-                        address17 = FAILURE
-                        chunk13, max13 = None, self._offset + 1
-                        if max13 <= self._input_size:
-                            chunk13 = self._input[self._offset:max13]
-                        if chunk13 is not None and Grammar.REGEX_27.search(chunk13):
-                            address17 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
+                    if address17 is not FAILURE:
+                        elements5.append(address17)
+                        address18 = FAILURE
+                        chunk14, max14 = None, self._offset + 1
+                        if max14 <= self._input_size:
+                            chunk14 = self._input[self._offset:max14]
+                        if chunk14 is not None and Grammar.REGEX_28.search(chunk14):
+                            address18 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                             self._offset = self._offset + 1
                         else:
-                            address17 = FAILURE
+                            address18 = FAILURE
                             if self._offset > self._failure:
                                 self._failure = self._offset
                                 self._expected = []
                             if self._offset == self._failure:
                                 self._expected.append(('METAR::vis', '[\\d]'))
-                        if address17 is not FAILURE:
-                            elements5.append(address17)
-                            address18 = FAILURE
-                            chunk14, max14 = None, self._offset + 1
-                            if max14 <= self._input_size:
-                                chunk14 = self._input[self._offset:max14]
-                            if chunk14 == '/':
-                                address18 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
+                        if address18 is not FAILURE:
+                            elements5.append(address18)
+                            address19 = FAILURE
+                            chunk15, max15 = None, self._offset + 1
+                            if max15 <= self._input_size:
+                                chunk15 = self._input[self._offset:max15]
+                            if chunk15 == '/':
+                                address19 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                 self._offset = self._offset + 1
                             else:
-                                address18 = FAILURE
+                                address19 = FAILURE
                                 if self._offset > self._failure:
                                     self._failure = self._offset
                                     self._expected = []
                                 if self._offset == self._failure:
                                     self._expected.append(('METAR::vis', '"/"'))
-                            if address18 is not FAILURE:
-                                elements5.append(address18)
-                                address19 = FAILURE
-                                chunk15, max15 = None, self._offset + 1
-                                if max15 <= self._input_size:
-                                    chunk15 = self._input[self._offset:max15]
-                                if chunk15 is not None and Grammar.REGEX_28.search(chunk15):
-                                    address19 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
+                            if address19 is not FAILURE:
+                                elements5.append(address19)
+                                address20 = FAILURE
+                                chunk16, max16 = None, self._offset + 1
+                                if max16 <= self._input_size:
+                                    chunk16 = self._input[self._offset:max16]
+                                if chunk16 is not None and Grammar.REGEX_29.search(chunk16):
+                                    address20 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                     self._offset = self._offset + 1
                                 else:
-                                    address19 = FAILURE
+                                    address20 = FAILURE
                                     if self._offset > self._failure:
                                         self._failure = self._offset
                                         self._expected = []
                                     if self._offset == self._failure:
                                         self._expected.append(('METAR::vis', '[\\d]'))
-                                if address19 is not FAILURE:
-                                    elements5.append(address19)
-                                    address20 = FAILURE
-                                    chunk16, max16 = None, self._offset + 2
-                                    if max16 <= self._input_size:
-                                        chunk16 = self._input[self._offset:max16]
-                                    if chunk16 == 'SM':
-                                        address20 = TreeNode(self._input[self._offset:self._offset + 2], self._offset, [])
+                                if address20 is not FAILURE:
+                                    elements5.append(address20)
+                                    address21 = FAILURE
+                                    chunk17, max17 = None, self._offset + 2
+                                    if max17 <= self._input_size:
+                                        chunk17 = self._input[self._offset:max17]
+                                    if chunk17 == 'SM':
+                                        address21 = TreeNode(self._input[self._offset:self._offset + 2], self._offset, [])
                                         self._offset = self._offset + 2
                                     else:
-                                        address20 = FAILURE
+                                        address21 = FAILURE
                                         if self._offset > self._failure:
                                             self._failure = self._offset
                                             self._expected = []
                                         if self._offset == self._failure:
                                             self._expected.append(('METAR::vis', '"SM"'))
-                                    if address20 is not FAILURE:
-                                        elements5.append(address20)
+                                    if address21 is not FAILURE:
+                                        elements5.append(address21)
                                     else:
                                         elements5 = None
-                                        self._offset = index12
+                                        self._offset = index13
                                 else:
                                     elements5 = None
-                                    self._offset = index12
+                                    self._offset = index13
                             else:
                                 elements5 = None
-                                self._offset = index12
+                                self._offset = index13
                         else:
                             elements5 = None
-                            self._offset = index12
+                            self._offset = index13
                     else:
                         elements5 = None
-                        self._offset = index12
+                        self._offset = index13
                     if elements5 is None:
                         address2 = FAILURE
                     else:
-                        address2 = TreeNode(self._input[index12:self._offset], index12, elements5)
+                        address2 = TreeNode(self._input[index13:self._offset], index13, elements5)
                         self._offset = self._offset
                     if address2 is FAILURE:
                         self._offset = index3
-                        chunk17, max17 = None, self._offset + 5
-                        if max17 <= self._input_size:
-                            chunk17 = self._input[self._offset:max17]
-                        if chunk17 == 'CAVOK':
+                        chunk18, max18 = None, self._offset + 5
+                        if max18 <= self._input_size:
+                            chunk18 = self._input[self._offset:max18]
+                        if chunk18 == 'CAVOK':
                             address2 = TreeNode(self._input[self._offset:self._offset + 5], self._offset, [])
                             self._offset = self._offset + 5
                         else:
@@ -1609,10 +1633,10 @@ class Grammar(object):
                                 self._expected.append(('METAR::vis', '"CAVOK"'))
                         if address2 is FAILURE:
                             self._offset = index3
-                            chunk18, max18 = None, self._offset + 4
-                            if max18 <= self._input_size:
-                                chunk18 = self._input[self._offset:max18]
-                            if chunk18 == '////':
+                            chunk19, max19 = None, self._offset + 4
+                            if max19 <= self._input_size:
+                                chunk19 = self._input[self._offset:max19]
+                            if chunk19 == '////':
                                 address2 = TreeNode(self._input[self._offset:self._offset + 4], self._offset, [])
                                 self._offset = self._offset + 4
                             else:
@@ -1626,14 +1650,14 @@ class Grammar(object):
                                 self._offset = index3
             if address2 is not FAILURE:
                 elements0.append(address2)
-                address21 = FAILURE
-                index13 = self._offset
-                address21 = self._read_varvis()
-                if address21 is FAILURE:
-                    address21 = TreeNode(self._input[index13:index13], index13, [])
-                    self._offset = index13
-                if address21 is not FAILURE:
-                    elements0.append(address21)
+                address22 = FAILURE
+                index14 = self._offset
+                address22 = self._read_varvis()
+                if address22 is FAILURE:
+                    address22 = TreeNode(self._input[index14:index14], index14, [])
+                    self._offset = index14
+                if address22 is not FAILURE:
+                    elements0.append(address22)
                 else:
                     elements0 = None
                     self._offset = index2
@@ -1669,7 +1693,7 @@ class Grammar(object):
             chunk0, max0 = None, self._offset + 1
             if max0 <= self._input_size:
                 chunk0 = self._input[self._offset:max0]
-            if chunk0 is not None and Grammar.REGEX_29.search(chunk0):
+            if chunk0 is not None and Grammar.REGEX_30.search(chunk0):
                 address2 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                 self._offset = self._offset + 1
             else:
@@ -1685,7 +1709,7 @@ class Grammar(object):
                 chunk1, max1 = None, self._offset + 1
                 if max1 <= self._input_size:
                     chunk1 = self._input[self._offset:max1]
-                if chunk1 is not None and Grammar.REGEX_30.search(chunk1):
+                if chunk1 is not None and Grammar.REGEX_31.search(chunk1):
                     address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                     self._offset = self._offset + 1
                 else:
@@ -1701,7 +1725,7 @@ class Grammar(object):
                     chunk2, max2 = None, self._offset + 1
                     if max2 <= self._input_size:
                         chunk2 = self._input[self._offset:max2]
-                    if chunk2 is not None and Grammar.REGEX_31.search(chunk2):
+                    if chunk2 is not None and Grammar.REGEX_32.search(chunk2):
                         address4 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                         self._offset = self._offset + 1
                     else:
@@ -1717,7 +1741,7 @@ class Grammar(object):
                         chunk3, max3 = None, self._offset + 1
                         if max3 <= self._input_size:
                             chunk3 = self._input[self._offset:max3]
-                        if chunk3 is not None and Grammar.REGEX_32.search(chunk3):
+                        if chunk3 is not None and Grammar.REGEX_33.search(chunk3):
                             address5 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                             self._offset = self._offset + 1
                         else:
@@ -1734,7 +1758,7 @@ class Grammar(object):
                             chunk4, max4 = None, self._offset + 1
                             if max4 <= self._input_size:
                                 chunk4 = self._input[self._offset:max4]
-                            if chunk4 is not None and Grammar.REGEX_33.search(chunk4):
+                            if chunk4 is not None and Grammar.REGEX_34.search(chunk4):
                                 address6 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                 self._offset = self._offset + 1
                             else:
@@ -1754,7 +1778,7 @@ class Grammar(object):
                                 chunk5, max5 = None, self._offset + 1
                                 if max5 <= self._input_size:
                                     chunk5 = self._input[self._offset:max5]
-                                if chunk5 is not None and Grammar.REGEX_34.search(chunk5):
+                                if chunk5 is not None and Grammar.REGEX_35.search(chunk5):
                                     address7 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                     self._offset = self._offset + 1
                                 else:
@@ -1832,7 +1856,7 @@ class Grammar(object):
                     chunk1, max1 = None, self._offset + 1
                     if max1 <= self._input_size:
                         chunk1 = self._input[self._offset:max1]
-                    if chunk1 is not None and Grammar.REGEX_35.search(chunk1):
+                    if chunk1 is not None and Grammar.REGEX_36.search(chunk1):
                         address4 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                         self._offset = self._offset + 1
                     else:
@@ -1851,7 +1875,7 @@ class Grammar(object):
                         chunk2, max2 = None, self._offset + 1
                         if max2 <= self._input_size:
                             chunk2 = self._input[self._offset:max2]
-                        if chunk2 is not None and Grammar.REGEX_36.search(chunk2):
+                        if chunk2 is not None and Grammar.REGEX_37.search(chunk2):
                             address5 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                             self._offset = self._offset + 1
                         else:
@@ -1867,7 +1891,7 @@ class Grammar(object):
                             chunk3, max3 = None, self._offset + 1
                             if max3 <= self._input_size:
                                 chunk3 = self._input[self._offset:max3]
-                            if chunk3 is not None and Grammar.REGEX_37.search(chunk3):
+                            if chunk3 is not None and Grammar.REGEX_38.search(chunk3):
                                 address6 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                 self._offset = self._offset + 1
                             else:
@@ -1884,7 +1908,7 @@ class Grammar(object):
                                 chunk4, max4 = None, self._offset + 1
                                 if max4 <= self._input_size:
                                     chunk4 = self._input[self._offset:max4]
-                                if chunk4 is not None and Grammar.REGEX_38.search(chunk4):
+                                if chunk4 is not None and Grammar.REGEX_39.search(chunk4):
                                     address7 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                     self._offset = self._offset + 1
                                 else:
@@ -1922,7 +1946,7 @@ class Grammar(object):
                                         chunk6, max6 = None, self._offset + 1
                                         if max6 <= self._input_size:
                                             chunk6 = self._input[self._offset:max6]
-                                        if chunk6 is not None and Grammar.REGEX_39.search(chunk6):
+                                        if chunk6 is not None and Grammar.REGEX_40.search(chunk6):
                                             address10 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                             self._offset = self._offset + 1
                                         else:
@@ -1938,7 +1962,7 @@ class Grammar(object):
                                             chunk7, max7 = None, self._offset + 1
                                             if max7 <= self._input_size:
                                                 chunk7 = self._input[self._offset:max7]
-                                            if chunk7 is not None and Grammar.REGEX_40.search(chunk7):
+                                            if chunk7 is not None and Grammar.REGEX_41.search(chunk7):
                                                 address11 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                 self._offset = self._offset + 1
                                             else:
@@ -1954,7 +1978,7 @@ class Grammar(object):
                                                 chunk8, max8 = None, self._offset + 1
                                                 if max8 <= self._input_size:
                                                     chunk8 = self._input[self._offset:max8]
-                                                if chunk8 is not None and Grammar.REGEX_41.search(chunk8):
+                                                if chunk8 is not None and Grammar.REGEX_42.search(chunk8):
                                                     address12 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                     self._offset = self._offset + 1
                                                 else:
@@ -1970,7 +1994,7 @@ class Grammar(object):
                                                     chunk9, max9 = None, self._offset + 1
                                                     if max9 <= self._input_size:
                                                         chunk9 = self._input[self._offset:max9]
-                                                    if chunk9 is not None and Grammar.REGEX_42.search(chunk9):
+                                                    if chunk9 is not None and Grammar.REGEX_43.search(chunk9):
                                                         address13 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                         self._offset = self._offset + 1
                                                     else:
@@ -2028,7 +2052,7 @@ class Grammar(object):
                                             chunk11, max11 = None, self._offset + 1
                                             if max11 <= self._input_size:
                                                 chunk11 = self._input[self._offset:max11]
-                                            if chunk11 is not None and Grammar.REGEX_43.search(chunk11):
+                                            if chunk11 is not None and Grammar.REGEX_44.search(chunk11):
                                                 address15 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                 self._offset = self._offset + 1
                                             else:
@@ -2047,7 +2071,7 @@ class Grammar(object):
                                                 chunk12, max12 = None, self._offset + 1
                                                 if max12 <= self._input_size:
                                                     chunk12 = self._input[self._offset:max12]
-                                                if chunk12 is not None and Grammar.REGEX_44.search(chunk12):
+                                                if chunk12 is not None and Grammar.REGEX_45.search(chunk12):
                                                     address16 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                     self._offset = self._offset + 1
                                                 else:
@@ -2063,7 +2087,7 @@ class Grammar(object):
                                                     chunk13, max13 = None, self._offset + 1
                                                     if max13 <= self._input_size:
                                                         chunk13 = self._input[self._offset:max13]
-                                                    if chunk13 is not None and Grammar.REGEX_45.search(chunk13):
+                                                    if chunk13 is not None and Grammar.REGEX_46.search(chunk13):
                                                         address17 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                         self._offset = self._offset + 1
                                                     else:
@@ -2079,7 +2103,7 @@ class Grammar(object):
                                                         chunk14, max14 = None, self._offset + 1
                                                         if max14 <= self._input_size:
                                                             chunk14 = self._input[self._offset:max14]
-                                                        if chunk14 is not None and Grammar.REGEX_46.search(chunk14):
+                                                        if chunk14 is not None and Grammar.REGEX_47.search(chunk14):
                                                             address18 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                             self._offset = self._offset + 1
                                                         else:
@@ -2095,7 +2119,7 @@ class Grammar(object):
                                                             chunk15, max15 = None, self._offset + 1
                                                             if max15 <= self._input_size:
                                                                 chunk15 = self._input[self._offset:max15]
-                                                            if chunk15 is not None and Grammar.REGEX_47.search(chunk15):
+                                                            if chunk15 is not None and Grammar.REGEX_48.search(chunk15):
                                                                 address19 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                                 self._offset = self._offset + 1
                                                             else:
@@ -2154,7 +2178,7 @@ class Grammar(object):
                                                                         chunk18, max18 = None, self._offset + 1
                                                                         if max18 <= self._input_size:
                                                                             chunk18 = self._input[self._offset:max18]
-                                                                        if chunk18 is not None and Grammar.REGEX_48.search(chunk18):
+                                                                        if chunk18 is not None and Grammar.REGEX_49.search(chunk18):
                                                                             address23 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                                                             self._offset = self._offset + 1
                                                                         else:
@@ -2373,7 +2397,7 @@ class Grammar(object):
         chunk0, max0 = None, self._offset + 1
         if max0 <= self._input_size:
             chunk0 = self._input[self._offset:max0]
-        if chunk0 is not None and Grammar.REGEX_49.search(chunk0):
+        if chunk0 is not None and Grammar.REGEX_50.search(chunk0):
             address2 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
             self._offset = self._offset + 1
         else:
@@ -3076,7 +3100,7 @@ class Grammar(object):
                 chunk6, max6 = None, self._offset + 1
                 if max6 <= self._input_size:
                     chunk6 = self._input[self._offset:max6]
-                if chunk6 is not None and Grammar.REGEX_50.search(chunk6):
+                if chunk6 is not None and Grammar.REGEX_51.search(chunk6):
                     address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                     self._offset = self._offset + 1
                 else:
@@ -3405,7 +3429,7 @@ class Grammar(object):
         chunk0, max0 = None, self._offset + 1
         if max0 <= self._input_size:
             chunk0 = self._input[self._offset:max0]
-        if chunk0 is not None and Grammar.REGEX_51.search(chunk0):
+        if chunk0 is not None and Grammar.REGEX_52.search(chunk0):
             address1 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
             self._offset = self._offset + 1
         else:
@@ -3425,7 +3449,7 @@ class Grammar(object):
             chunk1, max1 = None, self._offset + 1
             if max1 <= self._input_size:
                 chunk1 = self._input[self._offset:max1]
-            if chunk1 is not None and Grammar.REGEX_52.search(chunk1):
+            if chunk1 is not None and Grammar.REGEX_53.search(chunk1):
                 address2 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                 self._offset = self._offset + 1
             else:
@@ -3445,7 +3469,7 @@ class Grammar(object):
                 chunk2, max2 = None, self._offset + 1
                 if max2 <= self._input_size:
                     chunk2 = self._input[self._offset:max2]
-                if chunk2 is not None and Grammar.REGEX_53.search(chunk2):
+                if chunk2 is not None and Grammar.REGEX_54.search(chunk2):
                     address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                     self._offset = self._offset + 1
                 else:
@@ -3489,7 +3513,7 @@ class Grammar(object):
         chunk0, max0 = None, self._offset + 1
         if max0 <= self._input_size:
             chunk0 = self._input[self._offset:max0]
-        if chunk0 is not None and Grammar.REGEX_54.search(chunk0):
+        if chunk0 is not None and Grammar.REGEX_55.search(chunk0):
             address1 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
             self._offset = self._offset + 1
         else:
@@ -3509,7 +3533,7 @@ class Grammar(object):
             chunk1, max1 = None, self._offset + 1
             if max1 <= self._input_size:
                 chunk1 = self._input[self._offset:max1]
-            if chunk1 is not None and Grammar.REGEX_55.search(chunk1):
+            if chunk1 is not None and Grammar.REGEX_56.search(chunk1):
                 address2 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                 self._offset = self._offset + 1
             else:
@@ -3529,7 +3553,7 @@ class Grammar(object):
                 chunk2, max2 = None, self._offset + 1
                 if max2 <= self._input_size:
                     chunk2 = self._input[self._offset:max2]
-                if chunk2 is not None and Grammar.REGEX_56.search(chunk2):
+                if chunk2 is not None and Grammar.REGEX_57.search(chunk2):
                     address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                     self._offset = self._offset + 1
                 else:
@@ -3581,7 +3605,7 @@ class Grammar(object):
             chunk0, max0 = None, self._offset + 1
             if max0 <= self._input_size:
                 chunk0 = self._input[self._offset:max0]
-            if chunk0 is not None and Grammar.REGEX_57.search(chunk0):
+            if chunk0 is not None and Grammar.REGEX_58.search(chunk0):
                 address2 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                 self._offset = self._offset + 1
             else:
@@ -3597,7 +3621,7 @@ class Grammar(object):
                 chunk1, max1 = None, self._offset + 1
                 if max1 <= self._input_size:
                     chunk1 = self._input[self._offset:max1]
-                if chunk1 is not None and Grammar.REGEX_58.search(chunk1):
+                if chunk1 is not None and Grammar.REGEX_59.search(chunk1):
                     address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                     self._offset = self._offset + 1
                 else:
@@ -3613,7 +3637,7 @@ class Grammar(object):
                     chunk2, max2 = None, self._offset + 1
                     if max2 <= self._input_size:
                         chunk2 = self._input[self._offset:max2]
-                    if chunk2 is not None and Grammar.REGEX_59.search(chunk2):
+                    if chunk2 is not None and Grammar.REGEX_60.search(chunk2):
                         address4 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                         self._offset = self._offset + 1
                     else:
@@ -3629,7 +3653,7 @@ class Grammar(object):
                         chunk3, max3 = None, self._offset + 1
                         if max3 <= self._input_size:
                             chunk3 = self._input[self._offset:max3]
-                        if chunk3 is not None and Grammar.REGEX_60.search(chunk3):
+                        if chunk3 is not None and Grammar.REGEX_61.search(chunk3):
                             address5 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                             self._offset = self._offset + 1
                         else:
@@ -3645,7 +3669,7 @@ class Grammar(object):
                             chunk4, max4 = None, self._offset + 1
                             if max4 <= self._input_size:
                                 chunk4 = self._input[self._offset:max4]
-                            if chunk4 is not None and Grammar.REGEX_61.search(chunk4):
+                            if chunk4 is not None and Grammar.REGEX_62.search(chunk4):
                                 address6 = TreeNode(self._input[self._offset:self._offset + 1], self._offset, [])
                                 self._offset = self._offset + 1
                             else:


Test patch:
diff --git a/tests/io/test_metar.py b/tests/io/test_metar.py
index 341fb27e76..55f2a290d1 100644
--- a/tests/io/test_metar.py
+++ b/tests/io/test_metar.py
@@ -189,13 +189,20 @@ from metpy.units import is_quantity, units
      Metar('KGYR', 33.42, -112.37, 295, datetime(2017, 5, 7, 21, 47), 120, 6.0, np.nan,
            np.nan, np.nan, np.nan, np.nan, 'FEW', 10000, 'SCT', 25000, np.nan, np.nan,
            np.nan, np.nan, 4, 41, 14, 29.92, 0, 0, 0,
-           ''))],
+           '')),
+    # Manual visibility can be [1,3,5]/16SM Unidata/Metpy#2807
+    ('KDEN 241600Z 02010KT 1/16SM R35L/1000V1200FT FZFG VV001 M01/M02 A2954 RMK AO2 SFC VIS '
+     'M1/4 T10111022',
+     Metar('KDEN', 39.85, -104.65, 1640, datetime(2017, 5, 24, 16, 00), 20, 10.0, np.nan,
+           units.Quantity(1 / 16, 'mi').m_as('m'), 'FZFG', np.nan, np.nan, 'VV', 100,
+           np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 8, -1, -2, 29.54, 49, 0, 0,
+           'AO2 SFC VIS M1/4 T10111022'))],
     ids=['missing station', 'BKN', 'FEW', 'current weather', 'smoke', 'CAVOK', 'vis fraction',
          'missing temps', 'missing data', 'vertical vis', 'missing vertical vis', 'BCFG',
          '-DZ', 'sky cover CB', '5 sky levels', '-FZUP', 'VV group', 'COR placement',
          'M1/4SM vis', 'variable vis', 'runway vis', 'odd COR', 'IC', 'NSW',
          'variable vis no dir', 'swapped wind and vis', 'space in wx code', 'truncated VV',
-         'vis div zero'])
+         'vis div zero', 'vis 1/16'])
 def test_metar_parser(metar, truth):
     """Test parsing individual METARs."""
     assert parse_metar(metar, 2017, 5) == truth