Newer
Older
libj / include / j / lang / string.hpp
/**
 * @file string.hpp
 * @brief J Library String ヘッダファイル。
 * @copyright  2001 - 2024  Nomura Kei
 * @depends
 *   j/lang/object.hpp
 */
#ifndef J_LANG_STRING_HPP
#define J_LANG_STRING_HPP

#include <memory>
#include <ostream>
#include <istream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>

#include <j/lang/object.hpp>

namespace j
{
    namespace lang
    {

        class String final : public Object, public std::string
        {
        public:
            using std::string::string; // 継承コンストラクタ

            // コンストラクタ
            String();

            // コンストラクタ (const char* より構築)
            String(const char *str);

            // コンストラクタ (std::string より構築)
            String(const std::string &str) noexcept;

            // コンストラクタ
            String(String::const_iterator it1, String::const_iterator it2);

            // コピーコンストラクタ
            String(const String &str) noexcept;

            // ムーブコンストラクタ
            String(String &&str) noexcept;

            // デストラクタ
            ~String() noexcept;

            // コピー代入演算子
            String &operator=(const String &str) noexcept;

            // ムーブ代入演算子
            String &operator=(String &&str) noexcept;

            // 文字列結合用
            // String &operator+=(const String &str) noexcept;

            // 比較演算子
            // bool operator==(const String &str) const noexcept;

            // 比較演算子
            // bool operator!=(const String &str) const noexcept;

            // 配列でのアクセス
            // char &operator[](int index);

            // 配列でのアクセス
            // const char &operator[](int index) const;

            // C言語文字列表現
            operator const char *() const;

            // std::string
            // const std::string &String::str() const;

            // 指定された位置の文字を返す。
            char charAt(int index) const;

            // 部分文字列を返す。
            String substring(int beginIndex, int endIndex) const;

            // 指定文字列が含まれるかい否かを返す。
            bool contains(const String &str) const noexcept;

            // 文字置換
            String replace(char oldChar, char newChar) const noexcept;

            // 文字列置換
            String replace(const String &regex, const String &replacement) const;

            // 文字列置換
            String replaceAll(const String &regex, const String &replacement) const;

            // 分割
            std::vector<String> split(const String &regex) const noexcept;

            // 先頭の文字列が一致するか
            bool startsWith(const String &prefix, int offset = 0) const noexcept;

            // 末尾の文字列が一致するか
            bool endsWith(const String &suffix) const noexcept;

            // 小文字変換
            String toLowerCase() const noexcept;

            // 大文字変換
            String toUpperCase() const noexcept;

            // trim
            String trim() const noexcept;

            // 検索
            int indexOf(int ch, int fromIndex = 0) const noexcept;
            int indexOf(const String &str, int fromIndex = 0) const noexcept;
            int lastIndexOf(int ch, int fromIndex) const noexcept;
            int lastIndexOf(const String &str, int fromIndex) const noexcept;

            // 文字列表現取得
            String toString() const noexcept override;

            // 比較
            bool equals(const Object &obj) const noexcept override;

            // ハッシュコード
            int hashCode() const noexcept override;

            // 文字列結合用
            friend String operator+(const String &str1, const String &str2) noexcept;

            // 出力用
            friend std::ostream &operator<<(std::ostream &os, const String &str);

            // 入力用
            friend std::istream &operator>>(std::istream &is, String &str);

            ////////////////////////////////////////////////////////////////////
            //
            // template
            //

            // 数値型との結合
            template <typename T>
            String operator+(T number) const
            {
                std::ostringstream oss;
                oss << *this << number;
                return String(oss.str());
            }

            // 数値型との結合(数値が左辺)
            template <typename T>
            friend String operator+(T number, const String &str) noexcept
            {
                std::ostringstream oss;
                oss << number << str;
                return String(oss.str());
            }

            ////////////////////////////////////////////////////////////////////
            //
            // inline
            //

            /**
             * この文字列の文字列長を返します。
             *
             * @return 文字列長
             */
            inline int length() const noexcept { return static_cast<int>(size()); };

            /**
             * この文字列内で、指定された文字が最後に出現する位置のインデックスを返します。
             * 見つからない場合 -1 を返します。
             *
             * @param ch 検索する文字
             * @return 見つかった位置
             */
            inline int lastIndexOf(int ch) const noexcept { return lastIndexOf(ch, length()); }

            /**
             * 指定された部分文字列を返します。
             *
             * @param beginIndex 開始位置
             * @return 部分文字列
             */
            inline String substring(int beginIndex) const { return substring(beginIndex, length()); }

            /**
             * この文字列内で、指定された部分文字列が最後に出現する位置のインデックスを返します。
             * 空の文字列「」が最後に出現する位置は、length() とみなされます。
             * 見つからない場合 -1 を返します。
             *
             * @param str 検索する文字列
             * @return 見つかった位置
             */
            inline int lastIndexOf(const String &str) const noexcept { return lastIndexOf(str, length()); }

        protected:
            // クローン
            std::unique_ptr<Object> clone() const noexcept override;
        };

    } // namespace lang
} // namespace j

namespace std
{
    // For j::util::HashMap (std::unordered_map)

    // j::lang::Object も特殊化は実施しているため、
    // HashMap<Object, ...> のように Key の型を Object とすれば、
    // 継承したクラスは利用可能であるが、String (HashMap<String, ...> はよく使うと思うので。。。
    template <>
    struct hash<j::lang::String>
    {
        std::size_t operator()(const j::lang::String &str) const
        {
            return static_cast<std::size_t>(str.hashCode());
        }
    };
}

#endif // J_LANG_STRING_HPP