1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qstringlist.h>
5#if QT_CONFIG(regularexpression)
6# include <qregularexpression.h>
7#endif
8#include <private/qduplicatetracker_p.h>
9#include <QtCore/qlatin1stringmatcher.h>
10
11#include <algorithm>
12QT_BEGIN_NAMESPACE
13
14/*! \typedef QStringListIterator
15 \relates QStringList
16
17 The QStringListIterator type definition provides a Java-style const
18 iterator for QStringList.
19
20 QStringList provides both \l{Java-style iterators} and
21 \l{STL-style iterators}. The Java-style const iterator is simply
22 a type definition for QListIterator<QString>.
23
24 \sa QMutableStringListIterator, QStringList::const_iterator
25*/
26
27/*! \typedef QMutableStringListIterator
28 \relates QStringList
29
30 The QStringListIterator type definition provides a Java-style
31 non-const iterator for QStringList.
32
33 QStringList provides both \l{Java-style iterators} and
34 \l{STL-style iterators}. The Java-style non-const iterator is
35 simply a type definition for QMutableListIterator<QString>.
36
37 \sa QStringListIterator, QStringList::iterator
38*/
39
40/*!
41 \class QStringList
42 \inmodule QtCore
43 \brief The QStringList class provides a list of strings.
44
45 \ingroup tools
46 \ingroup shared
47 \ingroup string-processing
48
49 \reentrant
50
51 QStringList is actually just a QList<QString>. Like QList, QStringList is
52 \l{implicitly shared}. It provides fast index-based access as well as fast
53 insertions and removals. Passing string lists as value parameters is both
54 fast and safe.
55
56 All of QList's functionality also applies to QStringList. For example, you
57 can use isEmpty() to test whether the list is empty, and you can call
58 functions like append(), prepend(), insert(), replace(), removeAll(),
59 removeAt(), removeFirst(), removeLast(), and removeOne() to modify a
60 QStringList. In addition, QStringList provides a few convenience
61 functions that make handling lists of strings easier.
62
63 \section1 Initializing
64
65 The default constructor creates an empty list. You can use the
66 initializer-list constructor to create a list with elements:
67
68 \snippet qstringlist/main.cpp 0a
69
70 \section1 Adding Strings
71
72 Strings can be added to a list using the \l
73 {QList::insert()}{insert()}, \l
74 {QList::append()}{append()}, \l
75 {QList::operator+=()}{operator+=()} and \l
76 {operator<<()} functions.
77
78 \l{operator<<()} can be used to
79 conveniently add multiple elements to a list:
80
81 \snippet qstringlist/main.cpp 0b
82
83 \section1 Iterating Over the Strings
84
85 See \l {Iterating over Containers}.
86
87 \section1 Manipulating the Strings
88
89 QStringList provides several functions allowing you to manipulate
90 the contents of a list. You can concatenate all the strings in a
91 string list into a single string (with an optional separator)
92 using the join() function. For example:
93
94 \snippet qstringlist/main.cpp 4
95
96 The argument to join can be a single character or a string.
97
98 To break up a string into a string list, use the QString::split()
99 function:
100
101 \snippet qstringlist/main.cpp 6
102
103 The argument to split can be a single character, a string or a
104 QRegularExpression.
105
106 In addition, the \l {QStringList::operator+()}{operator+()}
107 function allows you to concatenate two string lists into one. To
108 sort a string list, use the sort() function.
109
110 QString list also provides the filter() function which lets you
111 to extract a new list which contains only those strings which
112 contain a particular substring (or match a particular regular
113 expression):
114
115 \snippet qstringlist/main.cpp 7
116
117 The contains() function tells you whether the list contains a
118 given string, while the indexOf() function returns the index of
119 the first occurrence of the given string. The lastIndexOf()
120 function on the other hand, returns the index of the last
121 occurrence of the string.
122
123 Finally, the replaceInStrings() function calls QString::replace()
124 on each string in the string list in turn. For example:
125
126 \snippet qstringlist/main.cpp 8
127
128 \sa QString
129*/
130
131/*!
132 \fn QStringList::QStringList(const QString &str)
133
134 Constructs a string list that contains the given string, \a
135 str. Longer lists are easily created like this:
136
137 \snippet qstringlist/main.cpp 9
138
139 \sa append()
140*/
141
142/*!
143 \fn QStringList::QStringList(const QList<QString> &other)
144
145 Constructs a copy of \a other.
146
147 This operation takes \l{constant time}, because QStringList is
148 \l{implicitly shared}. This makes returning a QStringList from a
149 function very fast. If a shared instance is modified, it will be
150 copied (copy-on-write), and that takes \l{linear time}.
151
152 \sa operator=()
153*/
154
155/*!
156 \fn QStringList::QStringList(QList<QString> &&other)
157 \overload
158 \since 5.4
159
160 Move-constructs from QList<QString>.
161
162 After a successful construction, \a other will be empty.
163*/
164
165/*!
166 \fn QStringList &QStringList::operator=(const QList<QString> &other)
167 \since 5.4
168
169 Copy assignment operator from QList<QString>. Assigns the \a other
170 list of strings to this string list.
171
172 After the operation, \a other and \c *this will be equal.
173*/
174
175/*!
176 \fn QStringList &QStringList::operator=(QList<QString> &&other)
177 \overload
178 \since 5.4
179
180 Move assignment operator from QList<QString>. Moves the \a other
181 list of strings to this string list.
182
183 After the operation, \a other will be empty.
184*/
185
186/*!
187 \fn void QStringList::sort(Qt::CaseSensitivity cs)
188
189 Sorts the list of strings in ascending order.
190
191//! [comparison-case-sensitivity]
192 If \a cs is \l Qt::CaseSensitive (the default), the string comparison
193 is case sensitive; otherwise the comparison is case insensitive.
194//! [comparison-case-sensitivity]
195
196 Sorting is performed using the STL's std::sort() algorithm,
197 which averages \l{linear-logarithmic time}, i.e. O(\e{n} log \e{n}).
198
199 If you want to sort your strings in an arbitrary order, consider
200 using the QMap class. For example, you could use a QMap<QString,
201 QString> to create a case-insensitive ordering (e.g. with the keys
202 being lower-case versions of the strings, and the values being the
203 strings), or a QMap<int, QString> to sort the strings by some
204 integer index.
205*/
206
207void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs)
208{
209 if (cs == Qt::CaseSensitive) {
210 std::sort(first: that->begin(), last: that->end());
211 } else {
212 auto CISCompare = [](const auto &s1, const auto &s2) {
213 return s1.compare(s2, Qt::CaseInsensitive) < 0;
214 };
215 std::sort(first: that->begin(), last: that->end(), comp: CISCompare);
216 }
217}
218
219
220/*!
221 \fn QStringList QStringList::filter(const QString &str, Qt::CaseSensitivity cs) const
222
223 Returns a list of all the strings containing the substring \a str.
224
225 \include qstringlist.cpp comparison-case-sensitivity
226
227 \snippet qstringlist/main.cpp 5
228 \snippet qstringlist/main.cpp 10
229
230 This is equivalent to
231
232 \snippet qstringlist/main.cpp 11
233 \snippet qstringlist/main.cpp 12
234
235 \sa contains()
236*/
237
238template <typename String>
239static QStringList filter_helper(const QStringList &that, const String &needle, Qt::CaseSensitivity cs)
240{
241 QStringList res;
242 for (const auto &s : that) {
243 if (s.contains(needle, cs))
244 res.append(t: s);
245 }
246 return res;
247}
248
249/*!
250 \fn QStringList QStringList::filter(QStringView str, Qt::CaseSensitivity cs) const
251 \overload
252 \since 5.14
253*/
254QStringList QtPrivate::QStringList_filter(const QStringList *that, QStringView str,
255 Qt::CaseSensitivity cs)
256{
257 return filter_helper(that: *that, needle: str, cs);
258}
259
260/*!
261 \fn QStringList QStringList::filter(const QStringMatcher &matcher) const
262 \since 6.7
263 \overload
264
265 Returns a list of all the strings matched by \a matcher (i.e. for which
266 \c matcher.indexIn() returns an index >= 0).
267
268 Using a QStringMatcher may be faster when searching in large lists and/or
269 in lists with long strings (the best way to find out is benchmarking).
270
271 For example:
272 \snippet qstringlist/main.cpp 18
273
274 \sa contains(), filter(const QLatin1StringMatcher &)
275*/
276
277/*!
278 \fn QStringList QStringList::filter(const QLatin1StringMatcher &matcher) const
279 \since 6.9
280
281 Returns a list of all the strings matched by \a matcher (i.e. for which
282 \c matcher.indexIn() returns an index >= 0).
283
284 Using QLatin1StringMatcher may be faster when searching in large
285 lists and/or in lists with long strings (the best way to find out is
286 benchmarking).
287
288 For example:
289 \snippet qstringlist/main.cpp 19
290
291 \sa contains(), filter(const QStringMatcher &)
292*/
293QStringList QtPrivate::QStringList_filter(const QStringList &that, const QStringMatcher &matcher)
294{
295 QStringList res;
296 for (const auto &s : that) {
297 if (matcher.indexIn(str: s) != -1)
298 res.append(t: s);
299 }
300 return res;
301}
302
303QStringList QtPrivate::QStringList_filter(const QStringList &that, const QLatin1StringMatcher &matcher)
304{
305 QStringList res;
306 for (const auto &s : that) {
307 if (matcher.indexIn(haystack: s) != -1)
308 res.append(t: s);
309 }
310 return res;
311}
312
313/*!
314 \fn QStringList QStringList::filter(QLatin1StringView str, Qt::CaseSensitivity cs) const
315 \since 6.7
316 \overload
317*/
318
319QStringList QtPrivate::QStringList_filter(const QStringList &that, QLatin1StringView needle,
320 Qt::CaseSensitivity cs)
321{
322 return filter_helper(that, needle, cs);
323}
324
325template<typename T>
326static bool stringList_contains(const QStringList &stringList, const T &str, Qt::CaseSensitivity cs)
327{
328 for (const auto &string : stringList) {
329 if (string.size() == str.size() && string.compare(str, cs) == 0)
330 return true;
331 }
332 return false;
333}
334
335
336/*!
337 \fn bool QStringList::contains(const QString &str, Qt::CaseSensitivity cs) const
338
339 Returns \c true if the list contains the string \a str; otherwise
340 returns \c false.
341
342 \include qstringlist.cpp comparison-case-sensitivity
343
344 \sa indexOf(), lastIndexOf(), QString::contains()
345 */
346
347/*!
348 \fn bool QStringList::contains(QStringView str, Qt::CaseSensitivity cs) const
349 \overload
350 \since 5.12
351
352 Returns \c true if the list contains the string \a str; otherwise
353 returns \c false.
354
355 \include qstringlist.cpp comparison-case-sensitivity
356 */
357bool QtPrivate::QStringList_contains(const QStringList *that, QStringView str,
358 Qt::CaseSensitivity cs)
359{
360 return stringList_contains(stringList: *that, str, cs);
361}
362
363/*!
364 \fn bool QStringList::contains(QLatin1StringView str, Qt::CaseSensitivity cs) const
365 \overload
366 \since 5.10
367
368 Returns \c true if the list contains the Latin-1 string viewed by \a str; otherwise
369 returns \c false.
370
371 \include qstringlist.cpp comparison-case-sensitivity
372
373 \sa indexOf(), lastIndexOf(), QString::contains()
374 */
375bool QtPrivate::QStringList_contains(const QStringList *that, QLatin1StringView str,
376 Qt::CaseSensitivity cs)
377{
378 return stringList_contains(stringList: *that, str, cs);
379}
380
381
382#if QT_CONFIG(regularexpression)
383/*!
384 \fn QStringList QStringList::filter(const QRegularExpression &re) const
385 \overload
386 \since 5.0
387
388 Returns a list of all the strings that match the regular
389 expression \a re.
390*/
391QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegularExpression &re)
392{
393 QStringList res;
394 for (const auto &str : *that) {
395 if (str.contains(re))
396 res.append(t: str);
397 }
398 return res;
399}
400#endif // QT_CONFIG(regularexpression)
401
402/*!
403 \fn QStringList &QStringList::replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs)
404
405 Returns a string list where every string has had the \a before
406 text replaced with the \a after text wherever the \a before text
407 is found.
408
409 \note If you use an empty \a before argument, the \a after argument will be
410 inserted \e {before and after} each character of the string.
411
412 \include qstringlist.cpp comparison-case-sensitivity
413
414 For example:
415
416 \snippet qstringlist/main.cpp 5
417 \snippet qstringlist/main.cpp 13
418
419 \sa QString::replace()
420*/
421
422/*!
423 \fn QStringList &QStringList::replaceInStrings(QStringView before, const QString &after, Qt::CaseSensitivity cs)
424 \overload
425 \since 5.14
426*/
427
428/*!
429 \fn QStringList &QStringList::replaceInStrings(const QString &before, QStringView after, Qt::CaseSensitivity cs)
430 \overload
431 \since 5.14
432*/
433
434/*!
435 \fn QStringList &QStringList::replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs)
436 \overload
437 \since 5.14
438*/
439void QtPrivate::QStringList_replaceInStrings(QStringList *that, QStringView before,
440 QStringView after, Qt::CaseSensitivity cs)
441{
442 // Before potentially detaching "that" list, check if any string contains "before"
443 qsizetype i = -1;
444 for (qsizetype j = 0; j < that->size(); ++j) {
445 if (that->at(i: j).contains(s: before, cs)) {
446 i = j;
447 break;
448 }
449 }
450 if (i == -1)
451 return;
452
453 for (; i < that->size(); ++i)
454 (*that)[i].replace(before: before.data(), blen: before.size(), after: after.data(), alen: after.size(), cs);
455}
456
457#if QT_CONFIG(regularexpression)
458/*!
459 \fn QStringList &QStringList::replaceInStrings(const QRegularExpression &re, const QString &after)
460 \overload
461 \since 5.0
462
463 Replaces every occurrence of the regular expression \a re, in each of the
464 string lists's strings, with \a after. Returns a reference to the string
465 list.
466
467 For example:
468
469 \snippet qstringlist/main.cpp 5
470 \snippet qstringlist/main.cpp 16
471
472 For regular expressions that contain capturing groups,
473 occurrences of \b{\\1}, \b{\\2}, ..., in \a after are
474 replaced with the string captured by the corresponding capturing group.
475
476 For example:
477
478 \snippet qstringlist/main.cpp 5
479 \snippet qstringlist/main.cpp 17
480*/
481void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QRegularExpression &re,
482 const QString &after)
483{
484 // Before potentially detaching "that" list, check if any string contains "before"
485 qsizetype i = -1;
486 for (qsizetype j = 0; j < that->size(); ++j) {
487 if (that->at(i: j).contains(re)) {
488 i = j;
489 break;
490 }
491 }
492 if (i == -1)
493 return;
494
495 for (; i < that->size(); ++i)
496 (*that)[i].replace(re, after);
497}
498#endif // QT_CONFIG(regularexpression)
499
500static qsizetype accumulatedSize(const QStringList &list, qsizetype seplen)
501{
502 qsizetype result = 0;
503 if (!list.isEmpty()) {
504 for (const auto &e : list)
505 result += e.size() + seplen;
506 result -= seplen;
507 }
508 return result;
509}
510
511/*!
512 \fn QString QStringList::join(const QString &separator) const
513
514 Joins all the string list's strings into a single string with each
515 element separated by the given \a separator (which can be an
516 empty string).
517
518 \sa QString::split()
519*/
520
521/*!
522 \fn QString QStringList::join(QChar separator) const
523 \since 5.0
524 \overload join()
525*/
526QString QtPrivate::QStringList_join(const QStringList *that, const QChar *sep, qsizetype seplen)
527{
528 const qsizetype totalLength = accumulatedSize(list: *that, seplen);
529 const qsizetype size = that->size();
530
531 QString res;
532 if (totalLength == 0)
533 return res;
534 res.reserve(asize: totalLength);
535 for (qsizetype i = 0; i < size; ++i) {
536 if (i)
537 res.append(uc: sep, len: seplen);
538 res += that->at(i);
539 }
540 return res;
541}
542
543/*!
544 \fn QString QStringList::join(QLatin1StringView separator) const
545 \since 5.8
546 \overload join()
547*/
548QString QtPrivate::QStringList_join(const QStringList &list, QLatin1StringView sep)
549{
550 QString result;
551 if (!list.isEmpty()) {
552 result.reserve(asize: accumulatedSize(list, seplen: sep.size()));
553 const auto end = list.end();
554 auto it = list.begin();
555 result += *it;
556 while (++it != end) {
557 result += sep;
558 result += *it;
559 }
560 }
561 return result;
562}
563
564/*!
565 \fn QString QStringList::join(QStringView separator) const
566 \overload
567 \since 5.14
568*/
569QString QtPrivate::QStringList_join(const QStringList *that, QStringView sep)
570{
571 return QStringList_join(that, sep: sep.data(), seplen: sep.size());
572}
573
574/*!
575 \fn QStringList QStringList::operator+(const QStringList &other) const
576
577 Returns a string list that is the concatenation of this string
578 list with the \a other string list.
579
580 \sa append()
581*/
582
583/*!
584 \fn QStringList &QStringList::operator<<(const QString &str)
585
586 Appends the given string, \a str, to this string list and returns
587 a reference to the string list.
588
589 \sa append()
590*/
591
592/*!
593 \fn QStringList &QStringList::operator<<(const QStringList &other)
594
595 \overload
596
597 Appends the \a other string list to the string list and returns a reference to
598 the latter string list.
599*/
600
601/*!
602 \fn QStringList &QStringList::operator<<(const QList<QString> &other)
603 \since 5.4
604
605 \overload
606
607 Appends the \a other string list to the string list and returns a reference to
608 the latter string list.
609*/
610
611/*!
612 \fn qsizetype QStringList::indexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
613 \fn qsizetype QStringList::indexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
614 \fn qsizetype QStringList::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
615
616 Returns the index position of the first match of \a str in the list,
617 searching forward from index position \a from. Returns -1 if no item
618 matched.
619
620 \include qstringlist.cpp comparison-case-sensitivity
621
622//! [overloading-base-class-methods]
623 \note The \a cs parameter was added in Qt 6.7, i.e. these methods now overload
624 the methods inherited from the base class. Prior to that these methods only
625 had two parameters. This change is source compatible and existing code should
626 continue to work.
627//! [overloading-base-class-methods]
628
629 \sa lastIndexOf()
630*/
631
632template <typename String>
633qsizetype indexOf_helper(const QStringList &that, String needle, qsizetype from,
634 Qt::CaseSensitivity cs)
635{
636 if (from < 0) // Historical behavior
637 from = qMax(a: from + that.size(), b: 0);
638
639 if (from >= that.size())
640 return -1;
641
642 for (qsizetype i = from; i < that.size(); ++i) {
643 if (needle.compare(that.at(i), cs) == 0)
644 return i;
645 }
646 return -1;
647}
648
649qsizetype QtPrivate::QStringList_indexOf(const QStringList &that, QStringView needle,
650 qsizetype from, Qt::CaseSensitivity cs)
651{
652 return indexOf_helper(that, needle, from, cs);
653}
654
655qsizetype QtPrivate::QStringList_indexOf(const QStringList &that, QLatin1StringView needle,
656 qsizetype from, Qt::CaseSensitivity cs)
657{
658 return indexOf_helper(that, needle, from, cs);
659}
660
661/*!
662 \fn qsizetype QStringList::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
663 \fn qsizetype QStringList::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
664 \fn qsizetype QStringList::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
665
666 Returns the index position of the last match of \a str in the list,
667 searching backward from index position \a from. If \a from is -1 (the
668 default), the search starts at the last item. Returns -1 if no item
669 matched.
670
671 \include qstringlist.cpp comparison-case-sensitivity
672
673 \include qstringlist.cpp overloading-base-class-methods
674
675 \sa indexOf()
676*/
677
678template <typename String>
679qsizetype lastIndexof_helper(const QStringList &that, String needle, qsizetype from,
680 Qt::CaseSensitivity cs)
681{
682 if (from < 0)
683 from += that.size();
684 else if (from >= that.size())
685 from = that.size() - 1;
686
687 for (qsizetype i = from; i >= 0; --i) {
688 if (needle.compare(that.at(i), cs) == 0)
689 return i;
690 }
691
692 return -1;
693}
694
695qsizetype QtPrivate::QStringList_lastIndexOf(const QStringList &that, QLatin1StringView needle,
696 qsizetype from, Qt::CaseSensitivity cs)
697{
698 return lastIndexof_helper(that, needle, from, cs);
699}
700
701qsizetype QtPrivate::QStringList_lastIndexOf(const QStringList &that, QStringView needle,
702 qsizetype from, Qt::CaseSensitivity cs)
703{
704 return lastIndexof_helper(that, needle, from, cs);
705}
706
707#if QT_CONFIG(regularexpression)
708/*!
709 \fn qsizetype QStringList::indexOf(const QRegularExpression &re, qsizetype from) const
710 \overload
711 \since 5.0
712
713 Returns the index position of the first exact match of \a re in
714 the list, searching forward from index position \a from. Returns
715 -1 if no item matched.
716
717 \sa lastIndexOf()
718*/
719qsizetype QtPrivate::QStringList_indexOf(const QStringList *that, const QRegularExpression &re, qsizetype from)
720{
721 if (from < 0)
722 from = qMax(a: from + that->size(), b: qsizetype(0));
723
724 QString exactPattern = QRegularExpression::anchoredPattern(expression: re.pattern());
725 QRegularExpression exactRe(exactPattern, re.patternOptions());
726
727 for (qsizetype i = from; i < that->size(); ++i) {
728 QRegularExpressionMatch m = exactRe.match(subject: that->at(i));
729 if (m.hasMatch())
730 return i;
731 }
732 return -1;
733}
734
735/*!
736 \fn qsizetype QStringList::lastIndexOf(const QRegularExpression &re, qsizetype from) const
737 \overload
738 \since 5.0
739
740 Returns the index position of the last exact match of \a re in
741 the list, searching backward from index position \a from. If \a
742 from is -1 (the default), the search starts at the last item.
743 Returns -1 if no item matched.
744
745 \sa indexOf()
746*/
747qsizetype QtPrivate::QStringList_lastIndexOf(const QStringList *that, const QRegularExpression &re, qsizetype from)
748{
749 if (from < 0)
750 from += that->size();
751 else if (from >= that->size())
752 from = that->size() - 1;
753
754 QString exactPattern = QRegularExpression::anchoredPattern(expression: re.pattern());
755 QRegularExpression exactRe(exactPattern, re.patternOptions());
756
757 for (qsizetype i = from; i >= 0; --i) {
758 QRegularExpressionMatch m = exactRe.match(subject: that->at(i));
759 if (m.hasMatch())
760 return i;
761 }
762 return -1;
763}
764#endif // QT_CONFIG(regularexpression)
765
766/*!
767 \fn qsizetype QStringList::removeDuplicates()
768
769 \since 4.5
770
771 This function removes duplicate entries from a list.
772 The entries do not have to be sorted. They will retain their
773 original order.
774
775 Returns the number of removed entries.
776*/
777qsizetype QtPrivate::QStringList_removeDuplicates(QStringList *that)
778{
779 QDuplicateTracker<QString> seen(that->size());
780 return that->removeIf(pred: [&](const QString &s) { return seen.hasSeen(s); });
781}
782
783QT_END_NAMESPACE
784

source code of qtbase/src/corelib/text/qstringlist.cpp