字符串类String

1 字符串类的初步设计

1.1 历史遗留问题

  • C语言不支持真正意义上的字符串。
  • C语言用字符数组和一组函数实现字符串操作。
  • C语言不支持自定义类型,因此无法获得字符串类型。
  • 从C到C++的进化过程中引入了自定义类型,在C++中可以通过类完成字符串类型的定义。

1.2 字符串类的初步设计

在这里插入图片描述
类的声明如下:
在这里插入图片描述
实现时的注意事项:

  • 无缝实现String对象与char*字符串的互操作。
  • 操作符重载函数需要考虑是否支持const操作。
  • 通过C语言中的字符串函数实现String的成员函数。

1.3 代码实现

String.h:

#ifndef LSTRING_H
#define LSTRING_H

#include "Object.h"
#include "Exception.h"

namespace LemonLib {

#define STR(str) (str ? str : "")

class String : public Object
{
protected:
    char* m_str;
    int m_length;

    void init(const char* str);
public:
    String();
    String(const char* str);
    String(char c);
    String(const String& s);

    String& operator = (const char* str);
    String& operator = (const String& s);
    String& operator = (char c);

    bool operator == (const char* str) const;
    bool operator == (const String& s) const;
    bool operator != (const char* str) const;
    bool operator != (const String& s) const;
    bool operator > (const char* str) const;
    bool operator > (const String& s) const;
    bool operator >= (const char* str) const;
    bool operator >= (const String& s) const;
    bool operator < (const char* str) const;
    bool operator < (const String& s) const;
    bool operator <= (const char* str) const;
    bool operator <= (const String& s) const;

    String operator + (const char* str) const;
    String operator + (const String& s) const;
    String& operator += (const char* str);
    String& operator += (const String& s);

    int length() const;
    const char* str() const;

    ~String();
};
}


#endif // STRING_H

String.cpp:

#include "LString.h"
#include <cstring>
#include <cstdlib>

using namespace std;

namespace LemonLib {
void String::init(const char* str)
{
    m_str = strdup(STR(str));

    if (m_str != NULL)
    {
        m_length = strlen(m_str);
    }
    else
    {
        THROW_EXCEPTION(NoEnoughMemoryException, "string init error, no enough memory");
    }
}

String::String()
{
    init("");
}

String::String(const char* str)
{
    init(str);
}

String::String(char c)
{
    char str[] = {c, '\0'};
    init(str);
}

String::String(const String& s)
{
    init(s.m_str);
}

String& String::operator = (char c)
{
    char str[] = {c, '\0'};
    return (*this = str);
}

String& String::operator = (const char* str)
{
    if (m_str != str)
    {
        free(m_str);

        init(str);
    }

    return *this;
}

String& String::operator = (const String& s)
{
    return (*this = s.m_str);
}

int String::length() const
{
    return m_length;
}

const char* String::str() const
{
    return m_str;
}

bool String::operator == (const char* str) const
{
    return strcmp(m_str, str) == 0;
}

bool String::operator == (const String& s) const
{
    return (*this == s.m_str);
}

bool String::operator != (const char* str) const
{
    return !(*this == str);
}

bool String::operator != (const String& s) const
{
    return !(*this == s);
}

bool String::operator > (const char* str) const
{
    return strcmp(m_str, STR(str)) > 0;
}

bool String::operator > (const String& s) const
{
    return (*this > s.m_str);
}

bool String::operator >= (const char* str) const
{
    return strcmp(m_str, STR(str)) >= 0;
}

bool String::operator >= (const String& s) const
{
    return (*this >= s.m_str);
}

bool String::operator < (const char* str) const
{
    return strcmp(m_str, str) < 0;
}

bool String::operator < (const String& s) const
{
    return (*this < s.m_str);
}

bool String::operator <= (const char* str) const
{
    return strcmp(m_str, STR(str)) <= 0;
}

bool String::operator <= (const String& s) const
{
    return (*this <= s.m_str);
}

String String::operator + (const char* str) const
{
    int len = m_length + strlen(STR(str));
    String ret;

    char* p = reinterpret_cast<char*>(malloc(len + 1));

    if (p != NULL)
    {
        strcpy(p, m_str);
        strcat(p, STR(str));

        free(ret.m_str);

        ret.m_str = p;
        ret.m_length = len;

        return ret;
    }
    else
    {
        THROW_EXCEPTION(NoEnoughMemoryException, "string operator + error, no enough memory");
    }
}

String String::operator + (const String& s) const
{
    return (*this + s.m_str);
}

String& String::operator += (const char* str)
{
    return (*this = *this + str);
}

String& String::operator += (const String& s)
{
    return (*this += s.m_str);
}

String::~String()
{
    free(m_str);
}
}


2 字符串类功能的进一步实现

接下来主要实现如下函数:
在这里插入图片描述

2.1 重载数组访问操作符[]

函数声明:

char& operator [] (int i);
char operator [] (int i) const;

注意事项:

  • 当i的取值不合法时,抛出异常:
    • 合法范围:(0 <= i) && (i < m_length)

代码实现如下:

char& String::operator [] (int i)
{
    if ((0 <= i) && (i < m_length))
    {
        return m_str[i];
    }
    else
    {
        THROW_EXCEPTION(IndexOutOfBoundsException, "string operator [] error, out index");
    }
}

char String::operator [] (int i) const
{
    return (const_cast<String&>(*this))[i];
}

2.2 判断是否以指定字符串开始或结束

函数声明:

bool startWith(const char* s) const;
bool startWith(const String& s) const;
bool endOf(const char* s) const;
bool endOf(const String& s) const;

示意图:
在这里插入图片描述
代码实现:

bool String::is_equal(const char* str1, const char* str2, int len) const
{
    bool ret = true;

    for (int i=0; i<len; i++)
    {
        if (str1[i] != str2[i])
        {
            ret = false;
            break;
        }
    }

    return ret;
}

bool String::startWith(const char* s) const
{
    bool ret = (s != NULL);

    if (ret)
    {
        int len = strlen(s);

        ret = (len < m_length) && is_equal(m_str, s, len);
    }

    return ret;
}

bool String::startWith(const String& s) const
{
    return startWith(s.m_str);
}

bool String::endOf(const char* s) const
{
    bool ret = (s != NULL);

    if (ret)
    {
        int len = strlen(s);

        ret = (len < m_length) && is_equal(m_str + m_length - len, s, len);
     }

    return ret;
}

bool String::endOf(const String& s) const
{
    return endOf(s.m_str);
}

2.3 在指定位置处插入字符串

函数声明:

String& insert(int i, const char* s);
String& insert(int i, const String& s);

示意图:

在这里插入图片描述
代码实现:

String& String::insert(int i, const char* s)
{
    bool ret = (s != NULL);

    if (ret)
    {
        if ((0 <= i) && (i <= m_length))
        {
            int len = strlen(s);
            char* str = reinterpret_cast<char*>(malloc(m_length + len + 1));

            if (str != NULL)
            {
                strncpy(str, m_str, i);
                strncpy(str+i, s, len);
                strncpy(str+i+len, m_str+i, m_length-i);
                str[m_length+len] = '\0';

                free(m_str);

                m_str = str;
                m_length = m_length + len + 1;
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "string insert error, no enough memory");
            }
        }
    }

    return *this;
}

String& String::insert(int i, const String& s)
{
    return insert(i, s.m_str);
}

2.4 去掉字符串两端的空白字符

函数声明:

String& trim();

示意图:
在这里插入图片描述
代码实现:

String& String::trim()
{
    if (m_length > 0)
    {
        int begin = 0, end = m_length - 1;

        while (m_str[begin] == ' ') begin++;
        while (m_str[end] == ' ') end--;

        if (begin == 0)
        {
            m_str[end + 1] = '\0';
            m_length = end + 1;
        }
        else
        {
            for (int i=0, j=begin; j<=end; i++, j++)
            {
                m_str[i] = m_str[j];
            }

            m_str[end - begin + 1] = '\0';
            m_length = end - begin + 1;
        }
    }

    return *this;
}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页