`
shfzhzhr
  • 浏览: 69473 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

XPCOM字符串操作(一)

阅读更多

XPCOM中的字符串类可以用操作做宽字节(16bit)和窄字节字符串。

宽字节和窄字节字符串基类是分开的,但是它们提供的接口是一致的。而对于每一个宽字节的实现类,都有一个类似的窄字节实现类。


Naming convention for wide and narrow string classes
Wide Narrow
nsAString nsACString
nsString nsCString
nsAutoString nsCAutoString
etc...


抽象基类

所有的字符串类都是从nsAString/nsACString这两个抽象基类派生。nsAString/nsACString提供了一些访问和操作字符串的基本方法。这两个类的命名模仿了Mozilla对于接口的命名,(Mozilla的接口命名中使用I来表示接口,如nsISupports),A表示“Abstract”。

下面是对字符串体系中主要类的总体描述:

 

  • nsAString/nsACString: 所有字符串类的基类,定义了xpcom中字符串的基本操作,如赋值、字符存取、基本的字符操作,比较等。nsAString 可以不必是以null(\0)结尾的。nsAString is not necessarily null-terminated.)
  • nsString/nsCString: 从以上两个基类继承而来,可以保证字符串是以null结尾。这两个类允许通过get()方法获取c风格的字符串(以'\0'结尾的字符数组)。
以为所有的字符串类都是从两个基类继承而来的,因为它们共享一些基本的API接口,如一些简单的只读函数:
  • .Length() - 字符串字符数目 (对于窄字符串类字符是char对于宽字节来说是PRUnichar)。
  • .IsEmpty() - 最快的可以判断字符串为空的方法. 用这个方法来代替 string.Length == 0
  • .Equals(string) - 判定两个字符串内容相同.
一些简单的改变字符串的方法:
  • .Assign(string) - 用string的值给字符串赋值.
  • .Append(string) - 追加string到字符串.
  • .Insert(string, position) - 在给定位置(position)的字符前插入string.
  • .Truncate(length) - 将字符串缩短到length指定的长度.

只读字符串

c++的const修饰符可以指定一个字符串类是否可写。 如果一个字符串被指定为const,并且视图调用一个non-const的方法,编译器将会给出一个错误。

For example:

void nsFoo::ReverseCharacters(nsAString& str) {
      ...
     str.Assign(reversedStr); // modifies the string
}

而下面的代码将不能通过编译, 因为你为一个静态的对象进行赋值了:

void nsFoo::ReverseCharacters(const nsAString& str) {
      ...
     str.Assign(reversedStr);
}

xpcom字符串类继承结构

 

nsAString_internal-graph.png

  • nsString / nsCString- 一个以null结尾的字符串,数据在堆(heap)上分配,在对象析构的时候会把数据也给干掉。
  • nsAutoString / nsCAutoString-  拥有一个64个字符的缓冲区,缓冲区和字符串类本身位于同一存储空间。如果为之类字符串赋一个小于64个字符的值,它会使用它本身的缓冲区,如果超过64字符,它会在对上分配一个新的缓冲区。
  • nsXPIDLString / nsXPIDLCString- 这类字符串支持通过getter_Copies() 方法获取wstring / string。 这类字符串同样支持空缓冲区( nsString的buffer永远不会为null)。
  • nsDependentString- 这个字符串永远都不会有自己的buffer。 当把一个原生的字符串转化成(const PRUnichar* or const char*) nsAString类型的时候特别有用。注意你的字符串必须是以null结尾的,如果不是使用 nsDependentSubstring。
  • nsPrintfCString- 类似于 nsCAutoString。 它的构造函数可以接受 printf-style的参数来格式化一个字符串。
  • NS_LITERAL_STRING/NS_NAMED_LITERAL_STRING- 它们可以把常量字符串(such as "abc") 转化成一个nsString或者nsString的子类型。 在支持双字节的平台上 (e.g., MSVC++ or GCC with the -fshort-wchar option), 它们是一些类似nsDependentString使用方式的简单的宏。 但是很显然宏比包装成nsDependentString要快很多。

 

Iterators

因为Mozilla中的字符串是一个单一的buffer,所以可以利用原生指针来完成迭代:

/**
 * Find whether there is a tab character in `data`
 */
bool HasTab(const nsAString& data)
{
  const PRUnichar* cur = data.BeginReading();
  const PRUnichar* end = data.EndReading();

  for (; cur < end; ++cur) {
    if (PRUnichar('\t') == *cur)
      return true;
  }
  return false;
}

注意end指向字符串结束字符的下一个位置,因为永远不要“提领”end指针.

向一个可变的字符串中写入也很容易:

/**
 * Replace every tab character in `data` with a space.
 */
void ReplaceTabs(nsAString& data)
{
  PRUnichar* cur = data.BeginWriting();
  PRUnichar* end = data.EndWriting();

  for (; cur < end; ++cur) {
    if (PRUnichar('\t') == *cur)
      *cur = PRUnichar(' ');
  }
}

可以通过SetLength()来改变字符串的长度。 需要注意的是如果要增加一个字符串长度的话可能会失败 (如没有足够的内存), 如果调用失败的话,字符串会简单的保持它的缓冲区和长度不变; 因此需要调用Length()方法看SetLength()是否成功. 同样要注意的是SetLength()成功以后迭代器指针将会失效:

/**
 * Replace every tab character in `data` with four spaces.
 */
void ReplaceTabs2(nsAString& data)
{
  int len = data.Length();
  PRUnichar *cur = data.BeginWriting();
  PRUnichar *end = data.EndWriting();

  // Because `cur` may change during the loop, track the position
  // within the string.
  int pos = 0;

  while (cur < end) {
    if (PRUnichar('\t') != *cur) {
      ++pos;
      ++cur;
    } else {
      len += 3;
      data.SetLength(len);
      if (data.Length() != len)
          // error handling goes here!
      // After SetLength, read `cur` and `end` again
      cur = data.BeginWriting() + pos;
      end = data.EndWriting();

      // move the remaining data over
      if (pos < len - 1)
        memmove(cur + 4, cur + 1, (len - 1 - pos) * sizeof(PRUnichar));

      // fill the tab with spaces
      *cur = PRUnichar(' ');
      *(cur + 1) = PRUnichar(' ');
      *(cur + 2) = PRUnichar(' ');
      *(cur + 3) = PRUnichar(' ');

      pos += 4;
      cur += 4;
    }
  }
}

如果在写入一个字符串的时候字符串的buffer变小了,用SetLength来通知你的对象:

/**
 * Remove every tab character from `data`
 */
void RemoveTabs(nsAString& data)
{
  int len = data.Length();
  PRUnichar* cur = data.BeginWriting();
  PRUnichar* end = data.EndWriting();

  while (cur < end) {
    if (PRUnichar('\t') == *cur) {
      len -= 1;
      end -= 1;
      if (cur < end)
        memmove(cur, cur + 1, (end - cur) * sizeof(PRUnichar));
    } else {
      cur += 1;
    }
  }

  data.SetLength(len);
}

 

 

帮助类和函数

搜索一个字符串

FindInReadable() 用来替代老的string.Find(..)函数:

PRBool FindInReadable(const nsAString& pattern,
                      nsAString::const_iterator start, nsAString::const_iterator end,
                      nsStringComparator& aComparator = nsDefaultStringComparator());

 start 和end指向搜索的起点和终点。如果搜索成功, start和end将会指向找到的字串的起点和终点。 函数返回PR_TRUE或PR_FALSE来指示搜索是否成功。

An example:

const nsAString& str = GetSomeString();
nsAString::const_iterator start, end;

str.BeginReading(start);
str.EndReading(end);

NS_NAMED_LITERAL_STRING(valuePrefix, "value=");

if (FindInReadable(valuePrefix, start, end)) {
    // end now points to the character after the pattern
    valueStart = end;

}

内存分配

从一个已经存在的字符串类分配一个新的字符buffer(意思是你得到一个新的c-style字符指针或数组,这个c-style的字符指针或数组里面字符的值和字符串类相等,当然如果这样的话意味着您得自己去释放这部分内存)的首选方法如下:

  • PRUnichar* ToNewUnicode(nsAString&) - 从nsAString分配PRUnichar*buffer 。
  • char *ToNewCString(nsACString&) - 从nsACString分配char*buffer。需要注意的是这个函数也可以接受nsAString参数,但是这个时候会进行有损失的转化,所以最好在知道所转化的字符串是ASCII编码的情况下使用此函数。
  • char* ToNewUTF8String(nsAString&) - 从一个 UTF-8编码的nsAString上分配char* buffer。 

这些函数返回的buffer是通过XPCOM的allocator分配空间的(不使用malloc等)。所以必须使用NS_Free来释放其内存。

 


子串(string fragments)

如果不需要重新分配空间并拷贝字符到新空间的话,或者一个字符串的字串是很容易的。 Substring()方法是完成这一工作的首选:

void ProcessString(const nsAString& str) {
    const nsAString& firstFive = Substring(str, 0, 5); // from index 0, length 5
    // firstFive is now a string representing the first 5 characters
}

 

 

 

 

 





分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics