Repository: mne-tools/mne-python

Issue:
automatically combining split files with dashes in the filename fails
Hi, 

I am not 100% this is a bug, or rather a feature request. For now, i could find a work-around, but if it is a bug, it might be relevant to more users in the future. 

####  Describe the bug
it seems that split MEG files (automatically split by the acquisition software) cannot be automatically rejoined when the filenames contains dashes (`-`). At least, when I tried to read a BIDS-formatted file, the combination of split files failed. 


#### Steps to reproduce
run `mne.io.read_raw_fif(infiles,preload=False)` on a file with dashes in it, e.g `sub-<sub_no>_ses-<ses_no>_task-<task_id>_raw.fif`

If necessary, I can upload two files as a MWE, but I suppose it will happen with any files as long as there is a dash in the filename. 

#### Expected results
I expected both file parts, so `...raw.fif` and `...raw-1.fif` to be automatically detected and read. 

#### Actual results
Only, the first part was read, the second one was ignored. 


#### Additional information
I think I located the problem to  `_get_next_fname` in `https://github.com/mne-tools/mne-python/blob/master/mne/io/open.py`. In this function, in line 83, MNE tries to check whether this is the first file or one of the subsequent parts, by locating the dashes in the filename. If `idx2 = -1`, then there are not dashes and the filename is the first part (`_raw.fif`), if `idx2 != -1, but the part of the filename between idx2 and idx is a number, then this is already a subsequent file (`...raw-[n].fif`), and a potential next filename (`..._raw-[n+1].fif`) is generated. 
However, when the filename contains dashes any other place (like it is common for BIDS files), this procedure fails, because when the filename of first part is analysed, dashes will be detected, and the next_file_name will be set to None. 

As a quick fix, to check whether I understood the problem, I used a different character for split files detection (`#` instead of `-`), and then dashes in the filename don't cause problems. 

Therefore, the solution would entail making the procedure robust against arbitrary dashes in the filename. I propose a fix as a pull request, not sure whether it is sufficiently robust. 

 



Discussion:

Resolving patch:
diff --git a/mne/io/open.py b/mne/io/open.py
--- a/mne/io/open.py
+++ b/mne/io/open.py
@@ -80,15 +80,17 @@ def _get_next_fname(fid, fname, tree):
                 path, base = op.split(fname)
                 idx = base.find('.')
                 idx2 = base.rfind('-')
+                num_str = base[idx2 + 1:idx]
+                if not num_str.isdigit():
+                    idx2 = -1
+
                 if idx2 < 0 and next_num == 1:
                     # this is the first file, which may not be numbered
                     next_fname = op.join(
                         path, '%s-%d.%s' % (base[:idx], next_num,
                                             base[idx + 1:]))
                     continue
-                num_str = base[idx2 + 1:idx]
-                if not num_str.isdigit():
-                    continue
+
                 next_fname = op.join(path, '%s-%d.%s'
                                      % (base[:idx2], next_num, base[idx + 1:]))
         if next_fname is not None:


Test patch:
diff --git a/mne/io/fiff/tests/test_raw_fiff.py b/mne/io/fiff/tests/test_raw_fiff.py
--- a/mne/io/fiff/tests/test_raw_fiff.py
+++ b/mne/io/fiff/tests/test_raw_fiff.py
@@ -20,7 +20,7 @@
 from mne.datasets import testing
 from mne.filter import filter_data
 from mne.io.constants import FIFF
-from mne.io import RawArray, concatenate_raws, read_raw_fif
+from mne.io import RawArray, concatenate_raws, read_raw_fif, base
 from mne.io.tag import _read_tag_header
 from mne.io.tests.test_raw import _test_concat, _test_raw_reader
 from mne import (concatenate_events, find_events, equalize_channels,
@@ -454,6 +454,27 @@ def test_split_files(tmpdir):
     assert_allclose(raw_crop[:][0], raw_read[:][0])
 
 
+def _no_write_file_name(fid, kind, data):
+    assert kind == FIFF.FIFF_REF_FILE_NAME  # the only string we actually write
+    return
+
+
+def test_split_numbers(tmpdir, monkeypatch):
+    """Test handling of split files using numbers instead of names."""
+    monkeypatch.setattr(base, 'write_string', _no_write_file_name)
+    raw = read_raw_fif(test_fif_fname).pick('eeg')
+    # gh-8339
+    dashes_fname = tmpdir.join('sub-1_ses-2_task-3_raw.fif')
+    raw.save(dashes_fname, split_size='5MB',
+             buffer_size_sec=1.)
+    assert op.isfile(dashes_fname)
+    next_fname = str(dashes_fname)[:-4] + '-1.fif'
+    assert op.isfile(next_fname)
+    raw_read = read_raw_fif(dashes_fname)
+    assert_allclose(raw.times, raw_read.times)
+    assert_allclose(raw.get_data(), raw_read.get_data(), atol=1e-16)
+
+
 def test_load_bad_channels(tmpdir):
     """Test reading/writing of bad channels."""
     # Load correctly marked file (manually done in mne_process_raw)