KCoreAddons

kstringhandler.cpp
1/*
2 This file is part of the KDE libraries
3
4 SPDX-FileCopyrightText: 1999 Ian Zepp <icszepp@islc.net>
5 SPDX-FileCopyrightText: 2006 Dominic Battre <dominic@battre.de>
6 SPDX-FileCopyrightText: 2006 Martin Pool <mbp@canonical.com>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "kstringhandler.h"
12
13#include <stdlib.h> // random()
14
15#include <QList>
16#include <QRegularExpression>
17
18//
19// Capitalization routines
20//
22{
23 if (text.isEmpty()) {
24 return text;
25 }
26
27 const QString strippedText = text.trimmed();
28 const QString space = QString(QLatin1Char(' '));
29 const QStringList words = capwords(strippedText.split(space));
30
31 QString result = text;
32 result.replace(strippedText, words.join(space));
33 return result;
34}
35
37{
38 QStringList tmp = list;
39 for (auto &str : tmp) {
40 str[0] = str.at(0).toUpper();
41 }
42 return tmp;
43}
44
45QString KStringHandler::lsqueeze(const QString &str, const int maxlen)
46{
47 if (str.length() > maxlen) {
48 const int part = maxlen - 3;
49 return QLatin1String("...") + QStringView(str).right(part);
50 } else {
51 return str;
52 }
53}
54
55QString KStringHandler::csqueeze(const QString &str, const int maxlen)
56{
57 if (str.length() > maxlen && maxlen > 3) {
58 const int part = (maxlen - 3) / 2;
59 const QStringView strView{str};
60 return strView.left(part) + QLatin1String("...") + strView.right(part);
61 } else {
62 return str;
63 }
64}
65
66QString KStringHandler::rsqueeze(const QString &str, const int maxlen)
67{
68 if (str.length() > maxlen) {
69 const int part = maxlen - 3;
70 return QStringView(str).left(part) + QLatin1String("...");
71 } else {
72 return str;
73 }
74}
75
77{
78 const bool ignoreMax = max == 0;
79
80 const int sepLength = sep.size();
81
82 QStringList list;
83 int searchStart = 0;
84 int sepIndex = str.indexOf(sep, searchStart);
85
86 while (sepIndex != -1 && (ignoreMax || list.count() < max - 1)) {
87 const auto chunk = str.mid(searchStart, sepIndex - searchStart);
88 if (!chunk.isEmpty()) {
89 list.append(chunk.toString());
90 }
91
92 searchStart = sepIndex + sepLength;
93 sepIndex = str.indexOf(sep, searchStart);
94 }
95
96 const auto lastChunk = str.mid(searchStart, str.length() - searchStart);
97 if (!lastChunk.isEmpty()) {
98 list.append(lastChunk.toString());
99 }
100
101 return list;
102}
103
105{
106 return perlSplit(QStringView(sep), QStringView(s), max);
107}
108
109QStringList KStringHandler::perlSplit(const QChar &sep, const QString &str, int max)
110{
111 return perlSplit(QStringView(&sep, 1), QStringView(str), max);
112}
113
115{
116 // nothing to split
117 if (str.isEmpty()) {
118 return QStringList();
119 }
120
121 const bool ignoreMax = max == 0;
122
123 QStringList list;
124
125 int start = 0;
126
127 const QStringView strView(str);
128
129 QRegularExpression separator(sep);
131
132 QRegularExpressionMatchIterator iter = separator.globalMatchView(strView);
134 while (iter.hasNext() && (ignoreMax || list.count() < max - 1)) {
135 match = iter.next();
136 const QStringView chunk = strView.mid(start, match.capturedStart() - start);
137 if (!chunk.isEmpty()) {
138 list.append(chunk.toString());
139 }
140
141 start = match.capturedEnd();
142 }
143
144 // catch the remainder
145 const QStringView lastChunk = strView.mid(start, strView.size() - start);
146 if (!lastChunk.isEmpty()) {
147 list.append(lastChunk.toString());
148 }
149
150 return list;
151}
152
154{
155 QString richText(text);
156
157 static const QRegularExpression urlEx(QStringLiteral(R"((www\.(?!\.)|(fish|ftp|http|https)://[\d\w./,:_~?=&;#@\-+%$()]+))"),
159 // The reference \1 is going to be replaced by the matched url
160 richText.replace(urlEx, QStringLiteral("<a href=\"\\1\">\\1</a>"));
161 return richText;
162}
163
165{
166 QString result;
167 for (const QChar ch : str) {
168 // yes, no typo. can't encode ' ' or '!' because
169 // they're the unicode BOM. stupid scrambling. stupid.
170 const ushort uc = ch.unicode();
171 result += (uc <= 0x21) ? ch : QChar(0x1001F - uc);
172 }
173
174 return result;
175}
176
177static inline bool containsSpaces(const QString &text)
178{
179 for (int i = 0; i < text.length(); i++) {
180 const QChar c = text[i];
181 if (c.isSpace()) {
182 return true;
183 }
184 }
185 return false;
186}
187
189{
190 const QChar zwsp(0x200b);
191
192 QString result;
193 result.reserve(text.length());
194
195 const bool containsSpaces = ::containsSpaces(text);
196
197 for (int i = 0; i < text.length(); i++) {
198 const QChar c = text[i];
199
200 const bool openingParens = (c == QLatin1Char('(') || c == QLatin1Char('{') || c == QLatin1Char('['));
201 const bool singleQuote = (c == QLatin1Char('\''));
202 const bool closingParens = (c == QLatin1Char(')') || c == QLatin1Char('}') || c == QLatin1Char(']'));
203 const bool breakAfter = (closingParens || c.isPunct() || c.isSymbol());
204 const bool isLastChar = i == (text.length() - 1);
205 const bool isLower = c.isLower();
206 const bool nextIsUpper = !isLastChar && text[i + 1].isUpper(); // false by default
207 const bool nextIsSpace = isLastChar || text[i + 1].isSpace(); // true by default
208 const bool prevIsSpace = (i == 0 || text[i - 1].isSpace() || result[result.length() - 1] == zwsp);
209
210 // Provide a breaking opportunity before opening parenthesis
211 if (openingParens && !prevIsSpace) {
212 result += zwsp;
213 }
214
215 // Provide a word joiner before the single quote
216 if (singleQuote && !prevIsSpace) {
217 result += QChar(0x2060);
218 }
219
220 result += c;
221
222 // Provide a breaking opportunity between camelCase and PascalCase sub-words;
223 // but if source string contains whitespaces, then it should be sufficiently wrappable on its own
224 const bool isCamelCase = !containsSpaces && isLower && nextIsUpper;
225
226 if (isCamelCase || (breakAfter && !openingParens && !nextIsSpace && !singleQuote)) {
227 result += zwsp;
228 }
229 }
230
231 return result;
232}
233
235{
236 int length = 0;
237 const auto chrs = text.toUcs4();
238 for (const auto chr : chrs) {
239 const auto script = QChar::script(chr);
240 /* clang-format off */
241 if (script == QChar::Script_Han
242 || script == QChar::Script_Hangul
243 || script == QChar::Script_Hiragana
244 || script == QChar::Script_Katakana
245 || script == QChar::Script_Yi
246 || QChar::isHighSurrogate(chr)) { /* clang-format on */
247 length += 2;
248 } else {
249 length += 1;
250 }
251 }
252 return length;
253}
Q_SCRIPTABLE Q_NOREPLY void start()
KCOREADDONS_EXPORT QString tagUrls(const QString &text)
This method auto-detects URLs in strings, and adds HTML markup to them so that richtext or HTML-enabl...
KCOREADDONS_EXPORT QString preProcessWrap(const QString &text)
Preprocesses the given string in order to provide additional line breaking opportunities for QTextLay...
KCOREADDONS_EXPORT QString lsqueeze(const QString &str, int maxlen=40)
Substitute characters at the beginning of a string by "...".
KCOREADDONS_EXPORT QStringList perlSplit(const QStringView sep, const QStringView str, int max)
Split a string into a QStringList in a similar fashion to the static QStringList function in Qt,...
KCOREADDONS_EXPORT int logicalLength(const QString &text)
Returns the length that reflects the density of information in the text.
KCOREADDONS_EXPORT QString rsqueeze(const QString &str, int maxlen=40)
Substitute characters at the end of a string by "...".
KCOREADDONS_EXPORT QString csqueeze(const QString &str, int maxlen=40)
Substitute characters at the middle of a string by "...".
KCOREADDONS_EXPORT QString capwords(const QString &text)
Capitalizes each word in the string "hello there" becomes "Hello There" (string)
KCOREADDONS_EXPORT QString obscure(const QString &str)
Obscure string by using a simple symmetric encryption.
bool isHighSurrogate() const const
bool isLower(char32_t ucs4)
bool isPunct(char32_t ucs4)
bool isSpace(char32_t ucs4)
bool isSymbol(char32_t ucs4)
Script script() const const
void append(QList< T > &&value)
qsizetype count() const const
QRegularExpressionMatchIterator globalMatchView(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
void setPatternOptions(PatternOptions options)
QRegularExpressionMatch next()
bool isEmpty() const const
bool isUpper() const const
qsizetype length() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void reserve(qsizetype size)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QList< uint > toUcs4() const const
QString trimmed() const const
QString join(QChar separator) const const
QStringView left(qsizetype length) const const
QStringView mid(qsizetype start, qsizetype length) const const
QStringView right(qsizetype length) const const
qsizetype indexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
qsizetype size() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:24 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.