zoukankan      html  css  js  c++  java
  • D语言中字符串的操作

           字符串的操作在软件开发中是特别重要的一个事情,因为基本上的编程都会使用到字符串,字符串操作的好坏决定着一个语言的好与差。在我做过的一个项目中曾经就出现过字符串操作性能问题。     

           D语言字符串有 string,wstring,dstring三种类型,在D语言中字符串是使用字符数组定义的,三种类型分别对应char,wchar,dchar。char只有一个字节,wchar为双字节,dchar为三字节。对字符串的操作也相当于是对数组的操作,这跟其它语言不一样,C++中字符串是以string类来进行封装,它的操作是就string类提供的函数来完成,C#中也是一样。而D中的字符更像是c语言中的字符串。

          在D语言要数组是做了很大的改进,这也使得D语言的string比其它语言的string的操作在性能上表现得更好。先来个例程看看:

    import std.stdio;
    
    int main(string[] argv)
    {
        auto tmp = "Hello Honan!";
        int n = 8;
        auto sub1 = tmp[0..$];
        auto sub2 = tmp[0..5];
        auto sub3 = tmp[0..n];
        writeln(sub1);
        writeln(sub2);
        writeln(sub3);
        readln();
        return 0;
    }

    运行输出image 
          看上面程序,auto sub1 = tmp[0..$]中,$表示数组的最大长度,这句也就是取整个字符串。

        

          这一个取子字符串的操作,这样的取字符串写法简单,而且把数组的操作直接应用到字符串操作中来,不需要另外写个subString函数来完成。在编译器层面把字符串的操作进行要处理和优化,这也可以大大提高字符串操作的性能。

          有人可能就会说,除了编译器可能会做一定优化,又能提高多少性能呢?哈哈,如果你这样想不错了,来看看下面一个例子:

    import std.stdio;
    int main(string[] argv)
    {
        auto tmp = "Hello Honan!";
        auto sub2 = tmp[0..5];
        (cast(char[])(sub2))[3] = 'K';
    
        writeln(tmp);
        writeln(sub2);
    
        readln();
        return 0;
    }

    运行输出

    image      看看这个运行结果,看见没有,原字符串和子字符串第3个字符都是K,这是个神奇的地方,因为这说明sub2这个子字符串没有产生实际的内存拷贝。这在字符串操作的时候将大大提高运行性能。这是一个很了不起的改进。

          看官在看到这句(cast(char[])(sub2))[3] = 'K'; 时可能会说,赋值一个字符都要字得这么复杂。哈哈,先不要看他复杂,这是很有用的,这种方式叫做强类型语言特征,这样做可以使得你编译时(而不是运行程序的时候)就会发现问题,不会轻易的操作字符串里面的内容,因为一般很少会直接修改字符串的内容。操作大部分都使用第三方函数来完成。

          又有人会想,那如果我的子字符串需要拷贝怎么办,这很简单,使用dup函数就可以完成:

    import std.stdio;
    int main(string[] argv)
    {
        auto tmp = "Hello Honan!";
        auto sub2 = tmp[0..5].dup;
        (cast(char[])(sub2))[3] = 'K';
    
        writeln(tmp);
        writeln(sub2);
    
        readln();
        return 0;
    }

    image auto sub2 = tmp[0..5].dup; 这一句中的dup函数就可以让字符串进行拷贝。

            让我们再来看看字符的连接操作:

    import std.stdio;
    import std.string;
    
    int main(string[] argv)
    {
        auto tmp = "Hello Honan!";
        auto tmp2 = tmp ~ " end";
    
        writeln(tmp);
        writeln(tmp2);
    
        readln();
        return 0;
    }

    image         方便吧,直接使用~运算符就可以进行。

             这几个功能远远不能字符串操作的全部功能,需要更多字符串操作功能需要导入std.string包,在这个包里包含的函数有:indexOf,lastIndexOf,lastIndexOfAny,representation,capitalize,splitLines,strip,stripLeft,stripRight,

    chomp,chompPrefix,chop,equal,leftJustify,rightJustify,center,detab,entab,translate,

    format,sformat,xformat,xsformat,inPattern,countchars,removechars,squeeze,munch,succ,tr,

    isNumeric,soundex,abbrev,column,wrap,outdent。

            这么多的字符串操作,实在是太丰富了,真是牛B人的作品呀,这么多不可能一个一个地介绍,这此函数的作在string.d里有unittest例程,看看就能明白,这里只做几个重点的函数介绍:

    image

          上图是一个string.d中的单元测试 这就是unittest语法的力量,不仅能在编程里进行测试,还能把测试代码放在程序一起,让后来的使用者很清楚地知道函数是如何使用的,真是一个牛B的发明。再去看看Go语言,真的只不过是一个玩具,到使用D语言的struct的时候,让那些使用Go的人明白D语言在那方面的表现一点也不差。这才是真正值得学习的语言,能简出,更能深入。

          还是先来看看字符串的几个重要操作吧。

         format函数

          在处理字符串时,我们经常需要使用format函数来对字符进行格式化。

    import std.stdio;
    import std.string;
    int main(string[] argv)
    {
        int age = 28;
        auto name = "Honan";
        auto str = format("Name:%s Age:%d",name,age);
    
        str.writeln();
        readln();
        return 0;
    }

    运行结果 image

    嗯,很方便,格式也和c语言中的格式一样。

         来看看format原码:

    string format(Char, Args...)(in Char[] fmt, Args args)
    {
        auto w = appender!string();
        auto n = formattedWrite(w, fmt, args);
        version (all)
        {
            // In the future, this check will be removed to increase consistency
            // with formattedWrite
            enforce(n == args.length, new FormatException(
                text("Orphan format arguments: args[", n, "..", args.length, "]")));
        }
        return w.data;
    }

          这个format函数是有一个问题的,在D语言中有三种字符串,string,wstring,dstring,format函数只支持string格式,这是很不科学的,需要改进。这样子的设计会使得非英文语系程序员很不愿意使用,因为字符串是个很关键的问题。

          值得大家注意的是,这不是编译器的问题,这是标准库的问题,也就是说标准库提供format函数时不够完善。因为对于非英文语系国家,在使用字符串时主要还是使用wstring或dstring。我将对中文字符串做详细测试。

         indexOf函数

          查找一个字节,或是一个子字符串出现的第一个位置。

    import std.stdio;
    import std.string;
    int main(string[] argv)
    {
        auto tmp = "Hello Honan! ";
        auto idx1 = tmp.indexOf('n');
        auto idx2 = tmp.indexOf("on");
    
        auto str = format("n index:%d on index:%d 
    ", idx1, idx2);
        str.writeln();
        readln();
        return 0;
    }

    image

        toLower函数:将字母转化为小字

    import std.stdio;
    import std.string;
    int main(string[] argv)
    {
        auto name = "Hello Honan! ";
        auto str = name.toLower();
        str.writeln();
        readln();
        return 0;
    }

    运行结果:

    image

    import std.stdio;
    import std.string;
    import excode;
    int main(string[] argv)
    {
        wstring name = "HELLO honan! HELLO ";
        auto str = name.toLower();
        str.UNI2GBK().writeln();
        readln();
        return 0;
    }

    image 使用全角的HELLO,也能转化为小写。

         toUpper函数:将小写转化为大写,和toLower函数一样,没什么将的了。

         count函数:数子字符串的数量

    import std.stdio;
    import std.string;
    int main(string[] argv)
    {
        auto name = "HELLO honan!";
        auto n1 = name.count('n');
        auto n2 = name.count("na");
    
        writeln(n1,",",n2);
        readln();
        return 0;
    }

    image       count与length是不是一样?有人可能会问这个问题,答案是当然不一样,count是以字符为单,比例一个汉字有在uft8格式里有3个字节,使用count的值是1,而使用length的值为3,为什么length的长度为3呢,那是因为length只是数组的长度。

    import std.stdio;
    import std.string;
    import std.conv;
    import excode;
    int main(string[] argv)
    {
        auto str = "你好!Hello!";
        auto wstr = str.to!wstring();
    
        writeln(format("str   length:%d count:%d", str.length,  str.count()));
        writeln(format("wstr  length:%d count:%d",wstr.length, wstr.count()));
        readln();
        return 0;
    }

    imageimage        因此,在我们经常需要使用中文字符串时,使用wstring的需求远远要大于使用string,因为string是uft8格式的,而uft8是变长编码,即英文字母只有一个字节,而中文汉字则有3个字节,本来string为uft8是比较好的,因为不只能使用中文,还可以使用多国文字,但这也使得string在foreach的时候不方便,没办法按字符来循环。

           而在wstring中使用的是Unicode编码,在Unicode中,length和count的值是一样的,dstring中更是一样了。

           这个count函数并不在string.h包中,这是因为D语言中具有类型函数扩展功能。这是一个很了不起的功能。

           例如:写一个函数

    int findIndex(string str,string findstr)
    {
          return indexOf(str);
    }

          那么类型string的对象就多了一个函数findIndex,使用时可以这样使用:

    auto str = "Hello Honan";
    auto idx = str.findIndex("Ho");

         这就是相当于findIndex的第一个参数的类型就是它的类型,这可以使得你在任何地方都可以给任何类型进行扩展。

         to转换函数:用于string,wstring,dstring的转换

    import std.stdio;
    import std.string;
    import std.conv;
    import excode;
    
    int main(string[] argv)
    {
        auto str = "你好!Hello!";
        auto wstr = str.to!wstring();
    
        writeln(UNI2GBK(wstr));
        readln();
        return 0;
    }

    image

    writeln函数在Windows中使用的是GBK格式,而默认auto str = “abc”的字符串是UTF8格式,如果直接使用writeln输出string和wstring是会出现乱码的,所以个人认为writeln函数做得不怎么好。只说在linux下正常,那么应该就是在windows中的编码处理得不对了,这可能跟windows默认字体的关吧,需要看看writeln函数的源代码。

            小结一下

            string :    utf8格式

            wstring : Unicode格式,即utf16

            dstring  : 四字节格式,即utf32

            这三种类型的编译,直接可以使用to函数转换。

            小问题:bug,writeln在windows下兼容性做得不好,是一个小小的bug,需要修正。

      string,wstring,dstring的静态字符串

    -------------------------------------------------------------------

            附加: 使用string,wstring,dstring的字符串初始化

           auto str = “hello”;  //string

           auto str = “hello”w;  //wstring

           auto str = “hello”d;  //dstring

    多行字符串的使用

    --------------------------------------------------------------------

    在使用字符串时,我们经常需要使用多行字符串,也可以叫文本。在C#中可以使用@””,而在D语言中也提供了比较方便的方法:

  • 相关阅读:
    python-函数进阶
    SHELL wordpress.sh
    XFS: possible memory allocation deadlock in kmem_alloc (mode:0x2d0)
    Puppet install with nginx unicorn
    CentOS 6内核编译问题整理
    Openstack 本地yum源配置
    Openstack 本地yum源配置
    hpsa 0000:0a:00.0: out of memory
    openstack VNC安全问题
    CentOS下crash分析内核kdump文件方法
  • 原文地址:https://www.cnblogs.com/wanhongnan/p/5720077.html
Copyright © 2011-2022 走看看