25#include <QDirIterator>
26#include <QRegularExpression>
45 const QString& sSubject,
46 const QString& sSession,
48 const QString& sDatatype,
49 const QString& sSuffix,
50 const QString& sExtension)
52 , m_sSubject(sSubject)
53 , m_sSession(sSession)
55 , m_sDatatype(sDatatype)
57 , m_sExtension(sExtension)
64 : m_sRoot(other.m_sRoot)
65 , m_sSubject(other.m_sSubject)
66 , m_sSession(other.m_sSession)
67 , m_sTask(other.m_sTask)
68 , m_sAcquisition(other.m_sAcquisition)
69 , m_sRun(other.m_sRun)
70 , m_sProcessing(other.m_sProcessing)
71 , m_sSpace(other.m_sSpace)
72 , m_sRecording(other.m_sRecording)
73 , m_sSplit(other.m_sSplit)
74 , m_sDescription(other.m_sDescription)
75 , m_sDatatype(other.m_sDatatype)
76 , m_sSuffix(other.m_sSuffix)
77 , m_sExtension(other.m_sExtension)
134 if(!m_sSubject.isEmpty())
135 parts << QStringLiteral(
"sub-") + m_sSubject;
136 if(!m_sSession.isEmpty())
137 parts << QStringLiteral(
"ses-") + m_sSession;
138 if(!m_sTask.isEmpty())
139 parts << QStringLiteral(
"task-") + m_sTask;
140 if(!m_sAcquisition.isEmpty())
141 parts << QStringLiteral(
"acq-") + m_sAcquisition;
142 if(!m_sRun.isEmpty())
143 parts << QStringLiteral(
"run-") + m_sRun;
144 if(!m_sProcessing.isEmpty())
145 parts << QStringLiteral(
"proc-") + m_sProcessing;
146 if(!m_sSpace.isEmpty())
147 parts << QStringLiteral(
"space-") + m_sSpace;
148 if(!m_sRecording.isEmpty())
149 parts << QStringLiteral(
"rec-") + m_sRecording;
150 if(!m_sSplit.isEmpty())
151 parts << QStringLiteral(
"split-") + m_sSplit;
152 if(!m_sDescription.isEmpty())
153 parts << QStringLiteral(
"desc-") + m_sDescription;
156 if(!m_sSuffix.isEmpty())
159 QString name = parts.join(QStringLiteral(
"_"));
162 if(!m_sExtension.isEmpty())
163 name += m_sExtension;
174 if(!m_sSubject.isEmpty())
175 dir = QDir(dir.filePath(QStringLiteral(
"sub-") + m_sSubject));
177 if(!m_sSession.isEmpty())
178 dir = QDir(dir.filePath(QStringLiteral(
"ses-") + m_sSession));
180 if(!m_sDatatype.isEmpty())
181 dir = QDir(dir.filePath(m_sDatatype));
183 return dir.path() + QDir::separator();
200 result.m_sSuffix = sSuffix;
201 result.m_sExtension = sExtension;
209 return withSuffix(QStringLiteral(
"channels"), QStringLiteral(
".tsv"));
218 result.m_sTask.clear();
219 result.m_sRun.clear();
220 result.m_sSuffix = QStringLiteral(
"electrodes");
221 result.m_sExtension = QStringLiteral(
".tsv");
231 result.m_sTask.clear();
232 result.m_sRun.clear();
233 result.m_sSuffix = QStringLiteral(
"coordsystem");
234 result.m_sExtension = QStringLiteral(
".json");
242 return withSuffix(QStringLiteral(
"events"), QStringLiteral(
".tsv"));
249 return withSuffix(m_sSuffix.isEmpty() ? m_sDatatype : m_sSuffix,
250 QStringLiteral(
".json"));
257 return QFileInfo::exists(
filePath());
267 return dir.mkpath(QStringLiteral(
"."));
274 QList<BIDSPath> results;
281 QString pattern = QStringLiteral(
"sub-") + (m_sSubject.isEmpty() ? QStringLiteral(
"*") : m_sSubject);
283 if(!m_sSession.isEmpty())
284 pattern += QStringLiteral(
"_ses-") + m_sSession;
286 pattern += QStringLiteral(
"*");
288 pattern += QStringLiteral(
"*");
290 if(!m_sSuffix.isEmpty())
291 pattern += QStringLiteral(
"_") + m_sSuffix;
293 if(!m_sExtension.isEmpty())
294 pattern += m_sExtension;
296 pattern += QStringLiteral(
".*");
298 QStringList entries = dir.entryList({pattern}, QDir::Files);
301 static const QRegularExpression entityRx(QStringLiteral(
"(\\w+)-(\\w+)"));
302 for(
const QString& entry : entries) {
308 auto it = entityRx.globalMatch(entry);
309 while(it.hasNext()) {
310 auto match = it.next();
311 const QString key =
match.captured(1);
312 const QString val =
match.captured(2);
314 if(key == QStringLiteral(
"sub")) p.
setSubject(val);
315 else if(key == QStringLiteral(
"ses")) p.
setSession(val);
316 else if(key == QStringLiteral(
"task")) p.
setTask(val);
318 else if(key == QStringLiteral(
"run")) p.
setRun(val);
320 else if(key == QStringLiteral(
"space")) p.
setSpace(val);
321 else if(key == QStringLiteral(
"rec")) p.
setRecording(val);
322 else if(key == QStringLiteral(
"split")) p.
setSplit(val);
328 int dotIdx = entry.lastIndexOf(QLatin1Char(
'.'));
331 QString nameWithoutExt = entry.left(dotIdx);
332 int lastUnder = nameWithoutExt.lastIndexOf(QLatin1Char(
'_'));
334 p.
setSuffix(nameWithoutExt.mid(lastUnder + 1));
353 static const QRegularExpression forbidden(QStringLiteral(
"[\\-_/]"));
354 return !sValue.contains(forbidden);
364 m_sRoot = other.m_sRoot;
365 m_sSubject = other.m_sSubject;
366 m_sSession = other.m_sSession;
367 m_sTask = other.m_sTask;
368 m_sAcquisition = other.m_sAcquisition;
369 m_sRun = other.m_sRun;
370 m_sProcessing = other.m_sProcessing;
371 m_sSpace = other.m_sSpace;
372 m_sRecording = other.m_sRecording;
373 m_sSplit = other.m_sSplit;
374 m_sDescription = other.m_sDescription;
375 m_sDatatype = other.m_sDatatype;
376 m_sSuffix = other.m_sSuffix;
377 m_sExtension = other.m_sExtension;
406QString BIDSPath::zeroPad(
const QString& sValue)
412 int num = sValue.toInt(&ok);
414 return QStringLiteral(
"%1").arg(num, 2, 10, QLatin1Char(
'0'));
Programmatic construction and matching of BIDS-compliant directories, filenames and sidecar paths.
Centralised BIDS vocabulary: datatype / suffix / extension whitelists, FIFF↔BIDS channel-type and coo...
bool operator==(const BIDSPath &a, const BIDSPath &b)
BIDS dataset reading, writing, path construction, and sidecar metadata handling for iEEG/EEG/MEG.
void setSession(const QString &sSession)
void setSpace(const QString &sSpace)
void setRecording(const QString &sRecording)
void setSubject(const QString &sSubject)
void setDatatype(const QString &sDatatype)
QString description() const
BIDSPath electrodesTsvPath() const
void setDescription(const QString &sDescription)
void setRun(const QString &sRun)
void setAcquisition(const QString &sAcquisition)
void setSplit(const QString &sSplit)
BIDSPath channelsTsvPath() const
static bool isValidEntityValue(const QString &sValue)
QString directory() const
QString acquisition() const
void setTask(const QString &sTask)
BIDSPath & operator=(const BIDSPath &other)
QString extension() const
void setProcessing(const QString &sProcessing)
void setRoot(const QString &sRoot)
void setSuffix(const QString &sSuffix)
QString processing() const
QString recording() const
BIDSPath coordsystemJsonPath() const
QList< BIDSPath > match() const
BIDSPath withSuffix(const QString &sSuffix, const QString &sExtension) const
BIDSPath eventsTsvPath() const
void setExtension(const QString &sExtension)
BIDSPath sidecarJsonPath() const