Doxygen 源码分析: QCString类

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 方式实现的成员函数
      • 5.1 格式化字符串
      • 5.2 查找字符
      • 5.3. 查找字符串
      • 5.4 反向查找
      • 5.4 检查是否存在字符
      • 5.5 检查是否存在字符串子串
      • 5.6 简化空格
      • 5.7 替换子串
      • 5.8 转为数字

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.hutf8.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 方式实现的成员函数

5.1 格式化字符串

QCString &sprintf( const char *format, ... );

QCString &QCString::sprintf( const char *format, ... )
{
  va_list ap;
  va_start( ap, format );
  const int minlen=256;
  int l = length();
  if (l<minlen) { resize(minlen); l=minlen; }
  int n=vsnprintf( rawData(), l, format, ap);
  if (n<0) n=l;
  resize(n+1);
  va_end( ap );
  return *this;
}

5.2 查找字符

c 表示需要找的字符, index 表示起始索引, cs 表示是否 case sensitive.

int	find( char c, int index=0, bool cs=TRUE ) const;

int QCString::find( char c, int index, bool cs ) const
{
  if (index<0 || index>=static_cast<int>(length())) return -1; // index outside string
  const char *pos;
  if (cs)
  {
    pos = strchr(data()+index,c);
  }
  else
  {
    pos = data()+index;
    c = toLowerChar(c);
    while (*pos && toLowerChar(*pos)!=c) pos++;
    if (!*pos && c) pos=0; // not found
  }
  return pos ? static_cast<int>(pos - data()) : -1;
}

如果没找到, 则给 pos 指针赋值为0。用 nullptr 会有更好的可读性。

5.3. 查找字符串

使用了 qstrnicmpstrstr 函数来处理大小写不敏感、大小写敏感的两种情况。

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 QCString::find( const char *str, int index, bool cs ) const
{
  int l = length();
  if (index<0 || index>=l) return -1; // index outside string
  if (!str)  return -1;               // no string to search for
  if (!*str) return index;           // empty string matching at index
  const char *pos;
  if (cs) // case sensitive
  {
    pos = strstr(data()+index,str);
  }
  else // case insensitive
  {
    pos = data();
    int len = qstrlen(str);
    while (*pos)
    {
      if (qstrnicmp(pos,str,len)==0) break;
      pos++;
    }
    if (!*pos) pos = 0; // not found
  }
  return pos ? static_cast<int>(pos - data()) : -1;
}

int QCString::find( const QCString &str, int index, bool cs ) const
{
  return find(str.data(),index,cs);
}

没找到结果时, 给 pos 指针赋值为0, 改为 nullptr 更合理。

5.4 反向查找

strrchr() 是C语言标准库里的函数:https://en.cppreference.com/w/c/string/byte/strrchr

  • 反向查找第一个出现的给定字符
  • 支持查找 \0 字符, \0 被当做字符串的一部分使用

QString::findRev() 基于 strrstr() 进行查找, 用于大小写不敏感的情况。
此外, QString::findRev() 还支持 index 为负数。

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 QCString::findRev( char c, int index, bool cs) const
{
  const char *b = data();
  const char *pos;
  int len = length();
  if (len==0) return -1; // empty string
  if (index<0) // start from end
  {
    if (cs)
    {
      pos = strrchr(b,c);
      return pos ? static_cast<int>(pos - b) : -1;
    }
    index=len;
  }
  else if (index>len) // bad index
  {
    return -1;
  }
  pos = b+index;
  if (cs)
  {
    while ( pos>=b && *pos!=c) pos--;
  }
  else
  {
    c = toLowerChar(c);
    while ( pos>=b && toLowerChar(*pos)!=c) pos--;
  }
  return pos>=b ? static_cast<int>(pos - b) : -1;
}

int QCString::findRev( const char *str, int index, bool cs) const
{
  int slen = qstrlen(str);
  int len = length();
  if (index<0) index = len-slen; // start from end
  else if (index>len) return -1; // bad index
  else if (index+slen>len) index=len-slen; // str would be too long
  if (index<0) return -1; // no match possible
  const char *pos = data()+index;
  if (cs) // case sensitive
  {
    for (int i=index; i>=0; i--) if (qstrncmp(pos--,str,slen)==0) return i;
  }
  else // case insensitive
  {
    for (int i=index; i>=0; i--) if (qstrnicmp(pos,str,slen)==0) return i;
  }
  return -1;
}

5.4 检查是否存在字符

  • 支持大小写敏感的参数设定
  • 如果字符串长度为0, 返回0
  • 如果字符串长度不为0, 则返回找到给定字符 c 的出现次数
int	contains( char c, bool cs=TRUE ) const;

int QCString::contains( char c, bool cs ) const
{
  if (length()==0) return 0;
  int count=0;
  const char *pos = data();
  if (cs)
  {
    while (*pos) if (*pos++ == c) count++;
  }
  else
  {
    c = toLowerChar(c);
    while (*pos)
    {
      if (toLowerChar(*pos)==c) count++;
      pos++;
    }
  }
  return count;
}

5.5 检查是否存在字符串子串

基于先前实现的 C 函数 qstrncmp()qstrnicmp() 实现。

int	contains( const char *str, bool cs=TRUE ) const;
//int contains( const QRegExp &rx ) const;

int QCString::contains( const char *str, bool cs ) const
{
  if (str==0 || length()==0) return 0;
  int count=0;
  const char *pos = data();
  int len = qstrlen(str);
  while (*pos)
  {
    if (cs)
    {
      if (qstrncmp(pos,str,len)==0) count++;
    }
    else
    {
      if (qstrnicmp(pos,str,len)==0) count++;
    }
    pos++;
  }
  return count;
}

5.6 简化空格

简化有两方面:

  • 去掉了前导的所有空格
  • 去掉了结尾的所有空格
  • 对于剩余部分的字符串
    • 如果不是空格,则原样拷贝
    • 如果是空格, 连续的空格仅拷贝一个, 其他跳过
/// 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 QCString::simplifyWhiteSpace() const
{
  if ( isEmpty() )                            // nothing to do
    return *this;

  QCString result( length()+1 );
  const char *from  = data();
  char *to    = result.rawData();
  char *first = to;
  while ( TRUE )
  {
    while ( *from && qisspace(*from) )
      from++;
    while ( *from && !qisspace(*from) )
      *to++ = *from++;
    if ( *from )
      *to++ = 0x20;                       // ' '
    else
      break;
  }
  if ( to > first && *(to-1) == 0x20 )
    to--;
  *to = '\0';
  result.resize( static_cast<int>(to - result.data()) + 1 );
  return result;
}

作为验证:

    QCString s = "  Hello  World    ";
    std::cout << "[" << s.simplifyWhiteSpace() << "]" << std::endl;

输出内容如下:

Hello, World!
[Hello World]

5.7 替换子串

这里的实现比较偷懒, 感觉效率也不会很高。
首先调用了 remove, 而 remove 其实是调用 m_rep.erase, 会生成新的字符串。
然后调用了 insert, insert 的位置决定了基本上是要新创建字符串的。

也就是说需要两次创建字符串, 其实可以只创建一次。。

QCString &replace( size_t index, size_t len, const char *s);
//QCString &replace( const QRegExp &rx, const char *str );

QCString &QCString::replace( size_t index, size_t len, const char *s)
{
  remove( index, len );
  insert( index, s );
  return *this;
}

5.8 转为数字

这一部分代码略多, 其实可以考虑用 C++11 转换函数进行替代:

  • std::stoi() 替代 toInt()
  • std::stol() 替代 toLong()
  • std::stoll() 替代 toInt64()
  • std::stoul() 替代 toULong()
    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;


short QCString::toShort(bool *ok, int base) const
{
  long v = toLong( ok, base );
  if ( ok && *ok && (v < -32768 || v > 32767) ) {
    *ok = FALSE;
    v = 0;
  }
  return static_cast<short>(v);
}

uint16_t QCString::toUShort(bool *ok,int base) const
{
  unsigned long v = toULong( ok, base );
  if ( ok && *ok && (v > 65535) ) {
    *ok = FALSE;
    v = 0;
  }
  return static_cast<uint16_t>(v);
}

int QCString::toInt(bool *ok, int base) const
{
  return static_cast<int>(toLong( ok, base ));
}

uint32_t QCString::toUInt(bool *ok,int base) const
{
  return static_cast<uint32_t>(toULong( ok, base ));
}


long QCString::toLong(bool *ok,int base) const
{
  const char *p = data();
  long val=0;
  int l = length();
  const long max_mult = INT_MAX / base;
  bool is_ok = FALSE;
  int neg = 0;
  if ( !p )
    goto bye;
  while ( l && qisspace(*p) )			// skip leading space
    l--,p++;
  if ( l && *p == '-' ) {
    l--;
    p++;
    neg = 1;
  } else if ( *p == '+' ) {
    l--;
    p++;
  }

  // NOTE: toULong() code is similar
  if ( !l || !ok_in_base(*p,base) )
    goto bye;
  while ( l && ok_in_base(*p,base) ) {
    l--;
    int dv;
    if ( *p>='0' && *p<='9' ) {
      dv = *p-'0';
    } else {
      if ( *p >= 'a' && *p <= 'z' )
        dv = *p - 'a' + 10;
      else
        dv = *p - 'A' + 10;
    }
    if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )
      goto bye;
    val = base*val + dv;
    p++;
  }
  if ( neg )
    val = -val;
  while ( l && qisspace(*p) )			// skip trailing space
    l--,p++;
  if ( !l )
    is_ok = TRUE;
bye:
  if ( ok )
    *ok = is_ok;
  return is_ok ? val : 0;
}

unsigned long QCString::toULong(bool *ok,int base) const
{
  const char *p = data();
  unsigned long val=0;
  int l = length();
  const unsigned long max_mult = 429496729;		// UINT_MAX/10, rounded down
  bool is_ok = FALSE;
  if ( !p )
    goto bye;
  while ( l && qisspace(*p) )			// skip leading space
    l--,p++;
  if ( *p == '+' )
    l--,p++;

  // NOTE: toLong() code is similar
  if ( !l || !ok_in_base(*p,base) )
    goto bye;
  while ( l && ok_in_base(*p,base) ) {
    l--;
    uint32_t dv;
    if ( *p>='0' && *p<='9' ) {
      dv = *p-'0';
    } else {
      if ( *p >= 'a' && *p <= 'z' )
        dv = *p - 'a' + 10;
      else
        dv = *p - 'A' + 10;
    }
    if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )
      goto bye;
    val = base*val + dv;
    p++;
  }

  while ( l && qisspace(*p) )			// skip trailing space
    l--,p++;
  if ( !l )
    is_ok = TRUE;
bye:
  if ( ok )
    *ok = is_ok;
  return is_ok ? val : 0;
}

uint64_t QCString::toUInt64(bool *ok,int base) const
{
  const char *p = data();
  uint64_t val=0;
  int l = length();
  const uint64_t max_mult = 1844674407370955161ULL;  // ULLONG_MAX/10, rounded down
  bool is_ok = FALSE;
  if ( !p )
    goto bye;
  while ( l && qisspace(*p) )		 	   // skip leading space
    l--,p++;
  if ( *p == '+' )
    l--,p++;

  // NOTE: toULong() code is similar
  if ( !l || !ok_in_base(*p,base) )
    goto bye;
  while ( l && ok_in_base(*p,base) ) {
    l--;
    uint32_t dv;
    if ( *p>='0' && *p<='9' ) {
      dv = *p-'0';
    } else {
      if ( *p >= 'a' && *p <= 'z' )
        dv = *p - 'a' + 10;
      else
        dv = *p - 'A' + 10;
    }
    if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) )
      goto bye;
    val = base*val + dv;
    p++;
  }

  while ( l && qisspace(*p) )			// skip trailing space
    l--,p++;
  if ( !l )
    is_ok = TRUE;
bye:
  if ( ok )
    *ok = is_ok;
  return is_ok ? val : 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22382.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQL执行过程

1. select 语句执行过程 一条 select 语句的执行过程如上图所示 1、建立连接 连接器会校验你输入的用户名和密码是否正确&#xff0c;如果错误会返回提示&#xff0c;如果正确&#xff0c;连接器会查询当前用户对于的权限。连接器的作用就是校验用户权限 2、查询缓存 MySQL…

面试字节,过关斩将直接干到 3 面,结果被吊打了?

人人都有大厂梦&#xff0c;对于软件测试员来说&#xff0c;BAT 为首的一线互联网公司肯定是自己的心仪对象&#xff0c;毕竟能到这些大厂工作&#xff0c;不仅薪资高待遇好&#xff0c;而且能力技术都能够得到提升&#xff0c;最关键的是还能够给自己镀上一层金&#xff0c;让…

【自然语言处理】 - 作业1: Word2Vec及TransE实现

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…

[CTF/网络安全] 攻防世界 view_source 解题详析

[CTF/网络安全] 攻防世界 view_source 解题详析 查看页面源代码方式归类总结 题目描述&#xff1a;X老师让小宁同学查看一个网页的源代码&#xff0c;但小宁同学发现鼠标右键好像不管用了。 查看页面源代码方式归类 单击鼠标右键&#xff0c;点击查看页面源代码&#xff1a; …

国外顶尖高校、企业分享人工智能自学课程英文原课程分享

人工智能无疑已经是当下最火热的方向&#xff0c;在很多领域已经融入我们生活&#xff0c;ChatGPT,Midjourney只是其中一个细分热点。目前这个领域&#xff0c;虽说国内也有不少课程&#xff0c;但是大部分源头还得从英文资料中找。如何学到最新最强得人工智能技能&#xff0c;…

MybatisPlus--基础入门!真滴方便

目录 一、简介 2.特性 二、入门 1.创建springboot 项目(点击查看如何创建 ) 注意&#xff1a;引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring&#xff0c;以避免因版本差异导致的问题 2.数据准备 3.配置application.yml 4.代码 BaseMapper<>…

nacos注册中心源码分析一之服务注册、服务心跳

源码分析 nacos客户端注册分析 依赖包 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>Nacos的客户端是基于SpringBoot的自动装配实现的 看下依…

Java多线程基础

目录 一、线程的基本使用 &#xff08;一&#xff09;创建线程的两种方式 &#xff08;二&#xff09;线程简单案例&#xff08;Thread&#xff09; 问题&#xff1a;main函数与开启的线程是否是阻塞的&#xff0c;即线程运行时&#xff0c;main函数等待线程运行结束&#…

DOUBLETROUBLE 1

文章目录 DOUBLETROUBLE: 1实战演练一、前期准备1、相关信息 二、信息收集1、nmap探测目标靶机端口2、扫描目标网址目录3、访问网站&#xff0c;发现secret下有个图片4、将图片下载5、查看图片所含内容6、破解密码并查看7、登陆邮箱8、创建反弹shell9、上传反弹shell10、监听11…

失业五个月,终于有offer了!但这家公司的风评惨不忍睹,要接吗?

往年&#xff0c;程序员们找工作可以说是不怎么费力的&#xff0c;不少求职者还会比对几家offer&#xff0c;看薪酬、看加不加班、看通勤时间等等等等&#xff0c;最后选择自己最满意的那一家过去。 但是今年&#xff0c;情况确实完全不一样&#xff0c;用网友的话形容就是“往…

不同厂家对讲机耳塞耳挂/领夹型988对讲机如何写频改频点/频率能互相通信

988型号都是很多厂家代工出来的,代工出来默认的频点都不一样,有可能买回来的2个不同厂家生产的对讲机,这样它们要能通讯,必须要同频点才能互通,它一般出厂设定16个频道,长按+和-键来切换频道。 需要用到typeC 的写频线,其实是用CH430芯片的usb写频线,可以找厂家要写频线…

文件上传之,waf绕过(24)

上传参数名解析&#xff1a;明确哪些东西可以修改 content-disposition:一般可更改 表单的数据 name:表单参数值&#xff0c;不能更改 表单提交的值 filename&#xff1a;文件名&#xff0c;可以修改 上传的文件名 content-type&#xff1a;文件mime&#xff0c;…

数据库索引结构(1)概念

常见的索引 主键和二级索引 MySQL学习笔记-主键索引和二级索引_mysql中主键索引和二级索引的区别_爱因诗贤的博客-CSDN博客 MYSQL-主键索引与二级索引_mysql二级索引存在哪个文件_青苔小榭的博客-CSDN博客 采用主键索引的好处&#xff1a;如果元素的位置发生修改&#xff0c;那…

【随笔记】全志 T507 PF4 引脚无法被正常设置为中断模式的问题分析

相关信息 硬件平台&#xff1a;全志T507 系统版本&#xff1a;Android 10 / Linux 4.9.170 问题描述&#xff1a;PF4 无法通过标准接口设置为中断模式&#xff0c;而 PF1、PF2、PF3、PF5 正常可用。 分析过程 一开始以为是引脚被其它驱动占用引起&#xff0c;或者该引脚不具…

Mybatis中处理特殊SQL处理逻辑

文章目录 0、前言1、模糊查询2、动态表名3、获取自增的组件4、批量删除 0、前言 在MyBatis中可能会有一些特殊的SQL需要去执行&#xff0c;一般就是模糊查询、批量删除、动态设置表名、添加功能获取自增的主键这几种&#xff0c;现在分别来进行说明。 为了方便演示 &#xff0…

OA管理痛点解决:从“硬编码”到“低代码”

低代码开发平台是一种逐渐流行起来的软件开发方式&#xff0c;它可以以快速且简单的方式构建各种应用程序&#xff0c;从而帮助企业快速响应市场变化和满足不断变化的业务需求。在企业的日常管理工作中&#xff0c;OA系统是一种非常常见的应用程序&#xff0c;它可以帮助企业管…

C++每日一练:饿龙咆哮-逃离城堡(避坑指南)非负整数求和

文章目录 前言一、题目二、解题代码及思路1、思路2、代码 三、非负整数求和总结 前言 饿龙这一题要说难度嘛&#xff0c;还真是挺简单的&#xff0c;但要满分也是有坑的&#xff01;本文就记录了笔者解题过程&#xff0c;希望能对读者使用C编程有所启发。至于非负整数求和代码…

redis高级篇三(分片集群)

一)进行测试Sentinel池: 集群的定义:所谓的集群&#xff0c;就是通过增加服务器的数量&#xff0c;提供相同的服务&#xff0c;从而让服务器达到一个稳定、高效的状态 之前的哨兵模式是存在着一些问题的&#xff0c;因为如果主节点挂了&#xff0c;那么sentinel集群会选举新的s…

斯坦福、Nautilus Chain等联合主办的 Hackathon 活动,现已接受报名

由 Stanford Blockchain Accelerator、Zebec Protocol、 Nautilus Chain、Rootz Lab 共同主办的黑客松活动&#xff0c;现已接受优秀项目提交参赛申请。 在加密行业发展早期&#xff0c;密码极客们就始终在对区块链世界基础设施&#xff0c;在发展方向的无限可能性进行探索。而…

如何用Python进行屏幕录制?

文章目录 引言gpt3.5给出的代码更换截图函数——ImageGrab.grab禁用imshow解决递归现象摄像头录制代码后期需求 引言 关于屏幕录制这个功能需求&#xff0c;之前用过基于ffmpeg的Capture录屏软件&#xff0c;但是fps拉高以后会变得很卡&#xff0c;声音也同样出现卡顿。也自己…