去除string首尾非\t、\r\n、""字符,要求高效

1yyyyyyyyyyyy 2013-09-13 11:17:41
比如这样一个string = "\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ";

要求只留下“京信通信系统(广州)有限公司南京办事处”

我写了一个,貌似速度问题很大,而且不通用,最后一个\t也未能去除:


string& StringTrim(string& str)
{
if (str.empty())
{
return str;
}

// str.erase(0, str.find_first_not_of("\r\n"));

int pos = str.find_first_not_of("\r\n");
if (pos > 0)
{
str.erase(0, pos);
}

while (true)
{
pos = str.find_first_of("\\t");
if (pos > 0)
{
str.erase(0, pos);
continue;
}
break;
}
str.erase(0, str.find_first_not_of("\t"));
str.erase(0, str.find_first_not_of(" "));
str.erase(str.find_last_not_of(" "));

str.erase(0, str.find_first_not_of("\t"));
str.erase(0, str.find_first_not_of(" "));

return str;
}


请教一下大家,这个函数应该怎样写?
...全文
1532 32 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2013-09-16
  • 打赏
  • 举报
回复
用c库函数,isspace即可 如果不用库函数 inline int isspace(int c){return c<' ';} 或者 inline bool isspace(int c){return c<' ';};
lm_whales 2013-09-16
  • 打赏
  • 举报
回复
只需要,计算前后的空白数 然后 复制字符,重置串长就结束了. 时间O(N),空间O(1);
mLee79 2013-09-14
  • 打赏
  • 举报
回复
它不用扫描一遍仅仅是因为它保存了字符串长度而已, 加个长度的参数我的也照样的不用整个扫描一遍, 还有用 find_last_not_of 复杂是 O(LN), 我不喜欢这样的玩意...
引用 25 楼 akirya 的回复:
[quote=引用 19 楼 mLee79 的回复:] 只扫描一遍, 不要分配内存:
#include <stdio.h>
#include <wchar.h>

#define XIN_SET(x)			((x)=='\r'||(x)=='\n'||(x)==' '||(x)=='\t')
#define XIN_SET_04(x)		XIN_SET(x+0),XIN_SET(x+1),XIN_SET(x+2),XIN_SET(x+3)
#define XIN_SET_16(x)		XIN_SET_04(x+0),XIN_SET_04(x+4),XIN_SET_04(x+8),XIN_SET_04(x+12)
#define XIN_SET_64(x)		XIN_SET_16(x+0),XIN_SET_16(x+16),XIN_SET_16(x+32),XIN_SET_16(x+48)

static const char filter[256]={XIN_SET_64(0), XIN_SET_64(64), XIN_SET_64(128), XIN_SET_64(192)};

char* slove(const char* input, char**end)
{
	const char *first = NULL, *last = NULL;
	
	for(; *input && 0!=filter[*input]; ++input)
		;
	
	if(!*input)
		return *end = (char*)input;
	
	first = last = input;
	for(;*++input;)
	{
		if(0 == filter[*input])
			last = input;
	}
	
	*end = (char*)last + 1;
	return (char*)first;
}

wchar_t* sloveW(const wchar_t* input, wchar_t**end)
{
	const wchar_t *first = NULL, *last = NULL;

	for(; *input && *input<256&&0!=filter[*input]; ++input)
		;

	if(!*input)
		return *end = (wchar_t*)input;

	first = last = input;
	for(;*++input;)
	{
		if(*input>=256||0 == filter[*input])
			last = input;
	}

	*end = (wchar_t*)last + 1;
	return (wchar_t*)first;
}

int main()
{
	{
		char *p , *end;
		
		p = slove("\r\n\t \t AAA\tBBB\rCCC\nDDDD\t\t ", &end);

		
		printf("RESULT: ||");
		fwrite(p, sizeof(char), end - p, stdout);
		printf("||\n");
	}

	{
		FILE* fp;
		wchar_t *p , *end;
		wchar_t BOM = 0xFEFF;

		p = sloveW(L"\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ", &end);

		fp = fopen("result.txt", "wb");
		fwrite(&BOM, 1, sizeof(BOM), fp);
		fwrite(p, sizeof(wchar_t), end - p, fp);
		fclose(fp);
	}
	return 0;
}

太复杂了,而且用string::find_last_not_of string::find_first_not_of连一遍扫描也不需要.[/quote]
  • 打赏
  • 举报
回复
引用 19 楼 mLee79 的回复:
只扫描一遍, 不要分配内存:
#include <stdio.h>
#include <wchar.h>

#define XIN_SET(x)			((x)=='\r'||(x)=='\n'||(x)==' '||(x)=='\t')
#define XIN_SET_04(x)		XIN_SET(x+0),XIN_SET(x+1),XIN_SET(x+2),XIN_SET(x+3)
#define XIN_SET_16(x)		XIN_SET_04(x+0),XIN_SET_04(x+4),XIN_SET_04(x+8),XIN_SET_04(x+12)
#define XIN_SET_64(x)		XIN_SET_16(x+0),XIN_SET_16(x+16),XIN_SET_16(x+32),XIN_SET_16(x+48)

static const char filter[256]={XIN_SET_64(0), XIN_SET_64(64), XIN_SET_64(128), XIN_SET_64(192)};

char* slove(const char* input, char**end)
{
	const char *first = NULL, *last = NULL;
	
	for(; *input && 0!=filter[*input]; ++input)
		;
	
	if(!*input)
		return *end = (char*)input;
	
	first = last = input;
	for(;*++input;)
	{
		if(0 == filter[*input])
			last = input;
	}
	
	*end = (char*)last + 1;
	return (char*)first;
}

wchar_t* sloveW(const wchar_t* input, wchar_t**end)
{
	const wchar_t *first = NULL, *last = NULL;

	for(; *input && *input<256&&0!=filter[*input]; ++input)
		;

	if(!*input)
		return *end = (wchar_t*)input;

	first = last = input;
	for(;*++input;)
	{
		if(*input>=256||0 == filter[*input])
			last = input;
	}

	*end = (wchar_t*)last + 1;
	return (wchar_t*)first;
}

int main()
{
	{
		char *p , *end;
		
		p = slove("\r\n\t \t AAA\tBBB\rCCC\nDDDD\t\t ", &end);

		
		printf("RESULT: ||");
		fwrite(p, sizeof(char), end - p, stdout);
		printf("||\n");
	}

	{
		FILE* fp;
		wchar_t *p , *end;
		wchar_t BOM = 0xFEFF;

		p = sloveW(L"\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ", &end);

		fp = fopen("result.txt", "wb");
		fwrite(&BOM, 1, sizeof(BOM), fp);
		fwrite(p, sizeof(wchar_t), end - p, fp);
		fclose(fp);
	}
	return 0;
}

太复杂了,而且用string::find_last_not_of string::find_first_not_of连一遍扫描也不需要.
「已注销」 2013-09-14
  • 打赏
  • 举报
回复
引用 20 楼 u012053386 的回复:
改成C的就不要出现string比较好了 哈哈
可能你后文还可能用string处理方便呢,就按你的意思去做嘛。 上面那个char 跟w_char 分开是没必要的,除非代码里面混乱的出现了两种编码,否者用windows定义的 TCHAR 就OK。
Kaile 2013-09-14
  • 打赏
  • 举报
回复
#include <boost/algorithm/string.hpp> boost::trim(s); // removes all leading and trailing white spaces boost::trim_if(s, boost::is_any_of("\t")); // removes only tabs
  • 打赏
  • 举报
回复
引用 1 楼 baichi4141 的回复:
开一个同样大的字符数组,逐个字符复制,遇到不要的字符就跳过 多次erase中间的字符会造成大量无意义的复制操作,例如你删除第一个字符,会导致后面的所有字符向前一个位置复制 用STL要时刻清楚它内部的操作是怎么样的,否则c/c++的最大优势——运算效率高——就彻底完蛋
+10086
  • 打赏
  • 举报
回复
引用 26 楼 mLee79 的回复:
它不用扫描一遍仅仅是因为它保存了字符串长度而已, 加个长度的参数我的也照样的不用整个扫描一遍, 还有用 find_last_not_of 复杂是 O(LN), 我不喜欢这样的玩意... [quote=引用 25 楼 akirya 的回复:] [quote=引用 19 楼 mLee79 的回复:] 只扫描一遍, 不要分配内存:
#include <stdio.h>
#include <wchar.h>

#define XIN_SET(x)			((x)=='\r'||(x)=='\n'||(x)==' '||(x)=='\t')
#define XIN_SET_04(x)		XIN_SET(x+0),XIN_SET(x+1),XIN_SET(x+2),XIN_SET(x+3)
#define XIN_SET_16(x)		XIN_SET_04(x+0),XIN_SET_04(x+4),XIN_SET_04(x+8),XIN_SET_04(x+12)
#define XIN_SET_64(x)		XIN_SET_16(x+0),XIN_SET_16(x+16),XIN_SET_16(x+32),XIN_SET_16(x+48)

static const char filter[256]={XIN_SET_64(0), XIN_SET_64(64), XIN_SET_64(128), XIN_SET_64(192)};

char* slove(const char* input, char**end)
{
	const char *first = NULL, *last = NULL;
	
	for(; *input && 0!=filter[*input]; ++input)
		;
	
	if(!*input)
		return *end = (char*)input;
	
	first = last = input;
	for(;*++input;)
	{
		if(0 == filter[*input])
			last = input;
	}
	
	*end = (char*)last + 1;
	return (char*)first;
}

wchar_t* sloveW(const wchar_t* input, wchar_t**end)
{
	const wchar_t *first = NULL, *last = NULL;

	for(; *input && *input<256&&0!=filter[*input]; ++input)
		;

	if(!*input)
		return *end = (wchar_t*)input;

	first = last = input;
	for(;*++input;)
	{
		if(*input>=256||0 == filter[*input])
			last = input;
	}

	*end = (wchar_t*)last + 1;
	return (wchar_t*)first;
}

int main()
{
	{
		char *p , *end;
		
		p = slove("\r\n\t \t AAA\tBBB\rCCC\nDDDD\t\t ", &end);

		
		printf("RESULT: ||");
		fwrite(p, sizeof(char), end - p, stdout);
		printf("||\n");
	}

	{
		FILE* fp;
		wchar_t *p , *end;
		wchar_t BOM = 0xFEFF;

		p = sloveW(L"\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ", &end);

		fp = fopen("result.txt", "wb");
		fwrite(&BOM, 1, sizeof(BOM), fp);
		fwrite(p, sizeof(wchar_t), end - p, fp);
		fclose(fp);
	}
	return 0;
}

太复杂了,而且用string::find_last_not_of string::find_first_not_of连一遍扫描也不需要.[/quote][/quote] 换个别的函数判断就行了,用switch应该就够快了。
turing-complete 2013-09-13
  • 打赏
  • 举报
回复
引用 3 楼 healer_kx 的回复:
赵老师开始学着写C++了?
我认为是这样的。 FYI
turing-complete 2013-09-13
  • 打赏
  • 举报
回复
当你Google不到的时候,就直接去stackoverflow,再没有答案再到这里来。 http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
武汉元码科技 2013-09-13
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
[quote=引用 3 楼 healer_kx 的回复:] 赵老师开始学着写C++了?
能从MSDN复制粘贴的时候,赵老师他从不错过![/quote] 赵老师太诚实了
赵4老师 2013-09-13
  • 打赏
  • 举报
回复
引用 3 楼 healer_kx 的回复:
赵老师开始学着写C++了?
能从MSDN复制粘贴的时候,赵老师他从不错过!
大尾巴猫 2013-09-13
  • 打赏
  • 举报
回复
引用 5 楼 baichi4141 的回复:
或者不用开新的字符数组,直接在原字符串上复制,最后按计数erase掉,都可以 基本思想就是,别做多余的操作,就这样
++ 逐个字节往前复制,只需遍历一次。
  • 打赏
  • 举报
回复
先删除后面的,再删除前面的
	string s = "\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ";
	
	size_t n = s.find_last_not_of( " \r\n\t" );
	if( n != string::npos )
	{
		s.erase( n + 1 , s.size() - n );
	}
	
	n = s.find_first_not_of ( " \r\n\t" );
	if( n != string::npos )
	{
		s.erase( 0 , n );
	}
baichi4141 2013-09-13
  • 打赏
  • 举报
回复
或者不用开新的字符数组,直接在原字符串上复制,最后按计数erase掉,都可以 基本思想就是,别做多余的操作,就这样
rocktyt 2013-09-13
  • 打赏
  • 举报
回复
我想问下,你这里的\t是制表符还是\和t 2个字符?
healer_kx 2013-09-13
  • 打赏
  • 举报
回复
赵老师开始学着写C++了?
赵4老师 2013-09-13
  • 打赏
  • 举报
回复
   
Contents  Index  Topic Contents
 
Previous Topic: StrToIntEx
Next Topic: Path Functions
 

StrTrim


BOOL StrTrim(
    LPTSTR psz,
    LPCTSTR pszTrimChars
    );

Removes (trims) any leading and trailing characters from a string. 

Returns nonzero if any characters were removed, or zero otherwise. 
psz 
Address of a string buffer that contains the string to be trimmed. 
pszTrimChars 
Address of an array of characters that will be trimmed from psz. The last element in this array must be zero. 
Example: 

#include <windows.h>
#include <iostream.h>
#include "Shlwapi.h"

void main( void )
{
  //String one
  TCHAR buffer[] = TEXT("_!ABCDEFG#");
  TCHAR trim[] = TEXT("#A!_\0");

  cout  <<  "The string before calling StrTrim: ";
  cout  <<  buffer;
  cout  <<  "\n";

  StrTrim(buffer, trim);

  cout  <<  "The string after calling StrTrim: ";
  cout  <<  buffer;
  cout  <<  "\n";

}

OUTPUT:
- - - - - -
The string before calling StrTrim: _!ABCDEFG#
The string after calling StrTrim: BCDEFG


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

 Top of Page 
© 1997 Microsoft Corporation. All rights reserved. Terms of Use. 
baichi4141 2013-09-13
  • 打赏
  • 举报
回复
开一个同样大的字符数组,逐个字符复制,遇到不要的字符就跳过 多次erase中间的字符会造成大量无意义的复制操作,例如你删除第一个字符,会导致后面的所有字符向前一个位置复制 用STL要时刻清楚它内部的操作是怎么样的,否则c/c++的最大优势——运算效率高——就彻底完蛋
水月飘零 2013-09-13
  • 打赏
  • 举报
回复
引用 6 楼 akirya 的回复:
先删除后面的,再删除前面的
	string s = "\r\n\t \t 京信通信系统(广州)有限公司南京办事处\t\t ";
	
	size_t n = s.find_last_not_of( " \r\n\t" );
	if( n != string::npos )
	{
		s.erase( n + 1 , s.size() - n );
	}
	
	n = s.find_first_not_of ( " \r\n\t" );
	if( n != string::npos )
	{
		s.erase( 0 , n );
	}
何必搞那么复杂呢,我觉得这个函数就非常完美了
加载更多回复(11)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧