XPCOM中的字符串类可以用操作做宽字节(16bit)和窄字节字符串。
宽字节和窄字节字符串基类是分开的,但是它们提供的接口是一致的。而对于每一个宽字节的实现类,都有一个类似的窄字节实现类。
| 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'结尾的字符数组)。
.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字符串类继承结构

-
nsString / nsCString- 一个以null结尾的字符串,数据在堆(heap)上分配,在对象析构的时候会把数据也给干掉。 -
nsAutoString / nsCAutoString- 拥有一个64个字符的缓冲区,缓冲区和字符串类本身位于同一存储空间。如果为之类字符串赋一个小于64个字符的值,它会使用它本身的缓冲区,如果超过64字符,它会在对上分配一个新的缓冲区。 -
nsXPIDLString / nsXPIDLCString- 这类字符串支持通过getter_Copies()方法获取wstring / string。这类字符串同样支持空缓冲区(nsString的buffer永远不会为null)。 -
nsDependentString- 这个字符串永远都不会有自己的buffer。 当把一个原生的字符串转化成(const PRUnichar*orconst 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
}
本文介绍了XPCOM中用于处理宽字节和窄字节字符串的类及其操作方法,包括字符串的赋值、追加、替换等功能。同时,还讨论了字符串类的继承结构和迭代器的使用。
2035

被折叠的 条评论
为什么被折叠?



