2023-05-20 23:41:56
ChrisZZ imzhuo@foxmailcom
Hompage https://github.com/zchrissirhcz
文章目录
- 1. Doxygen 版本
- 2. QCString 类概览
- 3. QCString 特殊成员函数
- 3.1 `=default` 方式的构造函数
- 3.2 单个参数和两个参数的构造函数
- 4. inline方式实现的成员函数
- 4.1 operator= 函数
- 4.2 判断是否为空
- 4.3 判断长度
- 4.4 获取裸数据
- 4.5 调整字符串大小
- 4.6 用相同字符填充字符串
- 4.7 删除前缀
- 4.8 获取子串
- 4.9 大小写转换
- 4.10 删除前导和尾部的空格
- 4.11 引用字符串(quoted string)
- 4.12 删除全部空白字符
- 4.13 自我重复n次
- 4.14 插入字符串
- 4.15 尾部追加字符
- 4.16 首部插入字符
- 4.17 删除若干连续字符
- 4.18 数字转字符串
- 4.19 判断是否以某个字符串开头、结尾
- 4.20 获取裸数据
- 4.21 字符串拼接:operator+= 操作符函数
- 4.22 获取字符
- 5. 非 inline 方式实现的成员函数(WIP)
1. Doxygen 版本
本次使用的 doxygen 版本如下, 是 1.9.8 正式发布版本对应的 commit
$ git log
commit 5fded4215d4f9271fe92c940fc4532d4704f5be1 (HEAD -> master, upstream/master)
Author: Dimitri van Heesch <doxygen@gmail.com>
Date: Thu May 18 22:14:30 2023 +0200
bump version to 1.9.8 for development
2. QCString 类概览
通过前文 Doxygen源码分析:构建过程简介,并生成doxygen自身的C++文档 生成的 Doxygen C++ 文档, 可以查询得到 QCString 类的文档网页:
相关文件:
- qcstring.h
- qcstring.cpp
- utf8.h
- utf8.cpp
3. QCString 特殊成员函数
这里用“特殊成员函数”表示“没有返回值的成员函数”, 基本上是构造函数。
3.1 =default
方式的构造函数
首先是使用了 C++11 中增加 =default
用法的几个:
QCString() = default;
~QCString() = default;
QCString( const QCString &s ) = default;
QCString &operator=( const QCString &s ) = default;
QCString( QCString &&s ) = default;
QCString &operator=( QCString &&s ) = default;
3.2 单个参数和两个参数的构造函数
其次是传入单个参数, 赋值给到 m_rep
成员的:
explicit QCString( const std::string &s ) : m_rep(s) {}
QCString( std::string &&s) : m_rep(std::move(s)) {}
其中 m_rep
的定义如下:
private:
std::string m_rep;
构造函数也可以传入 size, 如果 size 大于0则让 m_rep 执行 resize 到 size-1 的大小, 否则大小置为0:
/** creates a string with room for size characters
* @param[in] size the number of character to allocate (also counting the 0-terminator!)
*/
explicit QCString( size_t size ) { m_rep.resize(size>0 ? size-1 : 0); }
其中 std::string
类的 resize 方法,可以在 https://en.cppreference.com/w/cpp/string/basic_string/resize 找到解释:
void resize( size_type count )
- 如果 m_rep 当前长度小于 count, 则继续填充
CharT()
字符, 对于 std::string 而言就是\0
字符,直到到达 count 个字符 - 如果 m_rep 当前长度超过 count, 则砍掉多余的字符
也可以从 C 字符串初始化 m_rep
:
/** creates a string from a plain C string.
* @param[in] str A zero terminated C string. When 0 an empty string is created.
*/
QCString( const char *str ) : m_rep(str?str:"") {}
还可以指定 str 和 maxlen 两个参数, 从 str 的前 maxlen 个字符执行拷贝来初始化 m_rep
:
/** creates a string from \a str and copies over the first \a maxlen characters. */
QCString( const char *str, size_t maxlen ) : m_rep(str?str:"") { m_rep.resize(maxlen); }
4. inline方式实现的成员函数
在 QCString 的 class body 内直接定义(实现)的函数。 比较短小。
4.1 operator= 函数
传入一个 C 字符串指针 或 std::string 对象, 用来替代 m_rep 的值:
/** replaces the contents by that of C string \a str. */
QCString &operator=( const char *str) { m_rep = str?str:""; return *this; }
QCString &operator=( const std::string &s) { m_rep = s; return *this; }
4.2 判断是否为空
/** Returns TRUE iff the string is empty. Equivalent to isEmpty(). */
bool isNull() const { return m_rep.empty(); }
/** Returns TRUE iff the string is empty */
bool isEmpty() const { return m_rep.empty(); }
4.3 判断长度
/** Returns the length of the string, not counting the 0-terminator. Equivalent to size(). */
uint32_t length() const { return static_cast<uint32_t>(m_rep.size()); }
/** Returns the length of the string, not counting the 0-terminator. */
uint32_t size() const { return static_cast<uint32_t>(m_rep.size()); }
4.4 获取裸数据
/** Returns a pointer to the contents of the string in the form of a 0-terminated C string */
const char *data() const { return m_rep.c_str(); }
/** Returns a writable pointer to the data.
*/
char *rawData() { return &m_rep[0]; }
4.5 调整字符串大小
resize: 增加字符串尺寸, 或减小尺寸
/** Resizes the string to hold \a newlen characters
* (this value should also count the 0-terminator).
* If the string is enlarged the contents will
* be left unmodified.
*/
bool resize( size_t newlen ) { m_rep.resize( newlen>0 ? newlen-1 : 0 ); return TRUE; }
truncate: 英文本意是截断, 这里其实允许 pos 大于现有长度, 于是是将字符串长度增大:
/** Truncates the string at position \a pos. */
bool truncate( size_t pos ) { return resize( pos + 1 ); }
reserve: 修改预留空间大小, 也就是改变 capacity, 但不改变 size
/** Reserve space for \a size bytes without changing the string contents */
void reserve( size_t size ) { m_rep.reserve(size); }
4.6 用相同字符填充字符串
会覆盖替换原有内容:
/** Fills a string with a predefined character
* @param[in] c the character used to fill the string with.
* @param[in] len the number of character to fill. Use -1 to fill the whole string.
* @note the string will be resized to contain \a len characters. The contents of the
* string will be lost.
*/
bool fill( char c, int len = -1 )
{
int l = len==-1 ? static_cast<int>(m_rep.size()) : len;
m_rep = std::string(l,c);
return TRUE;
}
4.7 删除前缀
如果 m_rep 的前面 n 个长度的子串等于 prefix, 那就删除它们, 返回 true; 其他情况返回 false:
bool stripPrefix(const QCString &prefix)
{
if (prefix.isEmpty() || m_rep.empty()) return FALSE;
if (m_rep.rfind(prefix.data(),0)==0) // string starts with prefix
{
m_rep.erase(0,prefix.length());
return TRUE;
}
return FALSE;
}
bool stripPrefix(const char *prefix)
{
return stripPrefix(QCString(prefix));
}
4.8 获取子串
获取左子串: 给定长度 len, 获取 m_rep 的左边 len 个字符组成的 QCString:
QCString left( size_t len ) const
{
return m_rep.empty() ? QCString() : QCString(m_rep.substr(0,len));
}
获取右子串: 类似于左子串:
QCString right( size_t len ) const
{
return m_rep.empty() ? QCString() :
len<m_rep.size() ? QCString(m_rep.substr(m_rep.size()-len,len)) :
*this;
}
获取中间子串: 需要给出起始索引位置 index, 从 index 开始的 len 个字符作为构成结果字符串的元素:
QCString mid( size_t index, size_t len=static_cast<size_t>(-1)) const
{
size_t slen = m_rep.size();
if (len==static_cast<uint32_t>(-1)) len = slen-index;
return m_rep.empty() || index>slen || len==0 ? QCString() :
QCString(m_rep.substr(index,len));
}
4.9 大小写转换
字符串转小写, 依赖了 utf8.h
和 utf8.cpp
中的函数:
QCString lower() const
{
return QCString(convertUTF8ToLower(m_rep));
}
QCString upper() const
{
return QCString(convertUTF8ToUpper(m_rep));
}
utf8.cpp 中的代码略复杂, 本篇不做分析:
std::string convertUTF8ToLower(const std::string &input)
{
return caseConvert(input,asciiToLower,convertUnicodeToLower);
}
std::string convertUTF8ToUpper(const std::string &input)
{
return caseConvert(input,asciiToUpper,convertUnicodeToUpper);
}
4.10 删除前导和尾部的空格
使用到了前一篇 Doxygen源码分析: QCString类依赖的qstr系列C函数浅析 分析过的 qisspace()
函数, 主要思路是双指针, 也即:判断前导空格结束的位置记录为 start, 从后往前判断空格得到尾部连续空格得第一个位置的前面一个索引位置 end。 然后用 substr 方法获取结果。
/// returns a copy of this string with leading and trailing whitespace removed
QCString stripWhiteSpace() const
{
size_t sl = m_rep.size();
if (sl==0 || (!qisspace(m_rep[0]) && !qisspace(m_rep[sl-1]))) return *this;
size_t start=0,end=sl-1;
while (start<sl && qisspace(m_rep[start])) start++;
if (start==sl) return QCString(); // only whitespace
while (end>start && qisspace(m_rep[end])) end--;
return QCString(m_rep.substr(start,1+end-start));
}
4.11 引用字符串(quoted string)
将 QCString 转为引用方式的字符串:
- 去掉前导和尾部的空格(好奇为什么不通过调用StripWiteSpace实现);
- 扫描剩余的字符, 如果存在
-
字符, 或者存在空格, 则判定为需要引号 - 如果需要引号, 就在去掉了前后空格后的字符串的开头、结尾增加引号
// Returns a quoted copy of this string, unless it is already quoted.
// Note that trailing and leading whitespace is removed.
QCString quoted() const
{
size_t start=0, sl=m_rep.size(), end=sl-1;
while (start<sl && qisspace(m_rep[start])) start++; // skip over leading whitespace
if (start==sl) return QCString(); // only whitespace
while (end>start && qisspace(m_rep[end])) end--; // skip over trailing whitespace
bool needsQuotes=false;
size_t i=start;
if (i<end && m_rep[i]!='"') // stripped string has at least non-whitespace unquoted character
{
while (i<end && !needsQuotes) // check if the to be quoted part has at least one whitespace character
{
needsQuotes = m_rep[i] =='-';
needsQuotes |= qisspace(m_rep[i++]);
}
}
QCString result(m_rep.substr(start,1+end-start));
if (needsQuotes)
{
result.prepend("\"");
result.append("\"");
}
return result;
}
可以简单验证下:
printf("Hello, World!\n");
QCString s = "Hello World";
std::cout << s.quoted() << std::endl;
QCString t = "Hello-World";
std::cout << t.quoted() << std::endl;
将输出:
“Hello World”
“Hello-World”
4.12 删除全部空白字符
对原有字符串逐个判断, 不是空格,则执行拷贝,空格则跳过。
对于拷贝动作来说, 没有新创建字符串, 是在原字符串上就地执行的, 因而节省了内存。
具体实现如下:
/// returns a copy of this string with all whitespace removed
QCString removeWhiteSpace() const
{
size_t sl = m_rep.size();
if (sl==0) return *this;
std::string result = m_rep;
size_t src=0,dst=0;
while (src<sl)
{
if (!qisspace(m_rep[src])) result[dst++]=m_rep[src];
src++;
}
if (dst<m_rep.size()) result.resize(dst);
return QCString(result);
}
4.13 自我重复n次
将原有字符串内容重复n次,复制到新的字符串中并返回:
// Returns a copy of this string repeated n times
QCString repeat(unsigned int n) const
{
QCString result(n * size() + 1);
size_t offset = 0;
for (offset = 0; offset < n * size(); offset += size())
{
memcpy(result.rawData() + offset, data(), size());
}
return result;
}
4.14 插入字符串
QCString &insert( size_t index, const QCString &s )
{
if (s.length()>0)
{
size_t ol = m_rep.size();
if (index>ol) // insert beyond end of string and fill gap with spaces
{
m_rep.resize(index+s.length());
std::memset(&m_rep[ol],' ',index-ol);
std::memcpy(&m_rep[index],s.data(),s.length()+1);
}
else // insert inside the string
{
m_rep.insert(index,s.str());
}
}
return *this;
}
QCString &insert( size_t index, const char *s )
{
size_t len = s ? qstrlen(s) : 0;
if (len>0)
{
size_t ol = m_rep.size();
if (index>ol) // insert beyond end of string and fill gap with spaces
{
m_rep.resize(index+len);
std::memset(&m_rep[ol],' ',index-ol);
std::memcpy(&m_rep[index],s,len+1);
}
else // insert inside the string
{
m_rep.insert(index,s);
}
}
return *this;
}
QCString &insert( size_t index, char c)
{
char s[2] = { c, '\0' };
return insert(index,s);
}
4.15 尾部追加字符
QCString &append( char c)
{
m_rep+=c;
return *this;
}
QCString &append( const char *s )
{
return operator+=(s);
}
QCString &append( const QCString &s )
{
return operator+=(s);
}
QCString &append( const std::string &s )
{
return operator+=(s);
}
QCString &prepend( const char *s )
{
return insert(0,s);
}
4.16 首部插入字符
QCString &prepend( const QCString &s )
{
return insert(0,s.data());
}
QCString &prepend( const std::string &s )
{
return insert(0,s.c_str());
}
4.17 删除若干连续字符
QCString &remove( size_t index, size_t len )
{
size_t ol = m_rep.size();
if (index<ol && len>0) m_rep.erase(index,index+len>=ol ? std::string::npos : len);
return *this;
}
4.18 数字转字符串
使用C++11的 std::to_string() 实现的:
QCString &setNum(short n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(uint16_t n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(int n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(uint32_t n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(long n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(long long n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(unsigned long long n)
{
m_rep = std::to_string(n);
return *this;
}
QCString &setNum(unsigned long n)
{
m_rep = std::to_string(n);
return *this;
}
4.19 判断是否以某个字符串开头、结尾
Python 用户一定很熟悉这个 API。 使用 std::string 的 rfind 和 compare 实现的:
bool startsWith( const char *s ) const
{
if (m_rep.empty() || s==0) return s==0;
return m_rep.rfind(s,0)==0; // looking "backward" starting and ending at index 0
}
bool startsWith( const QCString &s ) const
{
if (m_rep.empty() || s.isEmpty()) return s.isEmpty();
return m_rep.rfind(s.str(),0)==0; // looking "backward" starting and ending at index 0
}
bool endsWith(const char *s) const
{
if (m_rep.empty() || s==0) return s==0;
size_t l = strlen(s);
return m_rep.length()>=l && m_rep.compare(m_rep.length()-l, l, s, l)==0;
}
bool endsWith(const QCString &s) const
{
size_t l = s.length();
return m_rep.length()>=l && m_rep.compare(m_rep.length()-l, l, s.str())==0;
}
4.20 获取裸数据
#define HAS_IMPLICIT_CAST_TO_PLAIN_C_STRING 0
#if HAS_IMPLICIT_CAST_TO_PLAIN_C_STRING
/** Converts the string to a plain C string */
operator const char *() const
{
return data();
}
#endif
const std::string &str() const
{
return m_rep;
}
4.21 字符串拼接:operator+= 操作符函数
直接调用 std::string 的 += 实现的:
QCString &operator+=( const QCString &s)
{
m_rep+=s.str();
return *this;
}
QCString &operator+=( const std::string &s)
{
m_rep+=s;
return *this;
}
/** Appends string \a str to this string and returns a reference to the result. */
QCString &operator+=( const char *s )
{
if (s) m_rep+=s;
return *this;
}
#define HAS_CHARACTER_APPEND_OPERATOR 1
#if HAS_CHARACTER_APPEND_OPERATOR
/** Appends character \a c to this string and returns a reference to the result. */
QCString &operator+=( char c )
{
m_rep+=c;
return *this;
}
#endif
4.22 获取字符
不执行索引是否非法的安全检查。提供 at()
和 operator[]
两类函数, 每类函数提供 const 和 非const 的版本:
/** Returns a reference to the character at index \a i. */
char &at( size_t i)
{
return m_rep[i];
}
const char &at( size_t i) const
{
return m_rep[i];
}
/** Indexing operator. Equivalent to at(). */
char &operator[]( int i )
{
return m_rep[i];
}
const char &operator[]( int i ) const
{
return m_rep[i];
}
5. 非 inline 方式实现的成员函数(WIP)
QCString &sprintf( const char *format, ... );
int find( char c, int index=0, bool cs=TRUE ) const;
int find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const QCString &str, int index=0, bool cs=TRUE ) const;
//int find( const QRegExp &rx, int index=0 ) const;
int findRev( char c, int index=-1, bool cs=TRUE) const;
int findRev( const char *str, int index=-1, bool cs=TRUE) const;
//int findRev( const QRegExp &rx, int index=-1 ) const;
int contains( char c, bool cs=TRUE ) const;
int contains( const char *str, bool cs=TRUE ) const;
//int contains( const QRegExp &rx ) const;
/// return a copy of this string with leading and trailing whitespace removed and multiple
/// whitespace characters replaced by a single space
QCString simplifyWhiteSpace() const;
QCString &replace( size_t index, size_t len, const char *s);
//QCString &replace( const QRegExp &rx, const char *str );
short toShort( bool *ok=0, int base=10 ) const;
uint16_t toUShort( bool *ok=0, int base=10 ) const;
int toInt( bool *ok=0, int base=10 ) const;
uint32_t toUInt( bool *ok=0, int base=10 ) const;
long toLong( bool *ok=0, int base=10 ) const;
unsigned long toULong( bool *ok=0, int base=10 ) const;
uint64_t toUInt64( bool *ok=0, int base=10 ) const;