自己写了一段,不是很满意,请教各位,有没有更好的方法?
#include <iostream>
#include <regex>
#include <string>
#include <fstream>
using namespace std;
int countword(string& str)
{
try
{
int n = 0;
smatch m;
regex ex("\\b\\w*\\b");
while(regex_search(str,m,ex))
{
++n;
str = m.suffix().str();
}
return n;
}
catch (regex_error e)
{
cout<<e.what()<<endl;
}
}
bool readfile(const string name,string& str)
{
ifstream in(name);
if(in.is_open())
{
char line[255] = "";
while(true)
{
in.getline(line,256);
str += line;
if(in.good())
{
str += '\n';
}
else
{
break;
}
}
return true;
}
else
{
return false;
}
}
int main(int argc,char* argv[])
{
if(2 != argc)
{
cout<<"argument error. eg. count.exe demo.txt"<<endl;
}
string str("");
if(readfile(argv[1],str))
{
cout<<str<<endl;
int n = countword(str);
cout<<"there are "<<n<<" words in "<<argv[1]<<endl;
}
return 0;
}
49 个解决方案
#1
不錯了。。。
#2
晕,都isfream了还用Char数组,自己给自己挖坑啊。
#3
在C#里面估计一句就够了
#4
C++同样只需要一句的。
#5
典型的简单问题复杂化啊
#6
哪一句?
#7
你有更加简单的方法?能不能教教我?
#8
不用char数组用什么?
#9
都 #include<string> 了
#10
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z]" );
while( fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#11
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z]" );
while( fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#12
嗯,确实非常简洁
我想再请教一下
fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" )
其中的%*[a-zA-Z]%*[^a-zA-Z]是什么意思?
另外,如果这个单词是由于连字符连接而成的,该如何处理啊?
比如,is-a是一个单词,而不是两个
#13
while (instream >> word)
count++
??
count++
??
#14
这样很不准确
比如“i hate C++ , and you ?”
可能会统计出7个单词
#15
规则是人定的
is-a既可以是一个单词,也可以是两个单词。
is-a既可以是一个单词,也可以是两个单词。
#16
为什么要正则式啊?一个很简单事情。
#17
这个问题复杂度奇高!
试统计以下句子的单词数:
◆That's a problem!
◆这个问题复杂度奇高!
◆이 문장에서 몇 단어?
◆بعض الكلمات في هذه الجملة؟
试统计以下句子的单词数:
◆That's a problem!
◆这个问题复杂度奇高!
◆이 문장에서 몇 단어?
◆بعض الكلمات في هذه الجملة؟
#18
那现在的规则就是将is-a定义成一个单词,用你的fscanf该如何解决呢?
#19
很简单吗?
不如把你的方案写出来,大家参考参考?
#20
哦,倒不一定要针对不同的语种
单单就英文而言,该如何解决呢?
#21
distance(sregex_iterator(。。。), sregex_iterator())
#22
那我的规则就是is-a是两个单词。
#23
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z-]" );
while( fscanf( fp , "%*[a-zA-Z-]%*[^a-zA-Z-]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#24
c/c++中有一个很古老的函数 strtok()就是干这个用的。
这么简单的情况就不要用正则表达式了,自己写一个循环也没多难。
int countword(char const* s)
{
int n = 0;
while(true)
{
while( isspace(*s) ) ++s;
if( !isgraph(*s++)) break;
while( isgraph(*s) ) ++s;
++n;
}
return n;
}
这么简单的情况就不要用正则表达式了,自己写一个循环也没多难。
int countword(char const* s)
{
int n = 0;
while(true)
{
while( isspace(*s) ) ++s;
if( !isgraph(*s++)) break;
while( isgraph(*s) ) ++s;
++n;
}
return n;
}
#25
补充一点,如果需要考虑标点符号的话,可以用strtok的delim参数,也可以把上例中的判断条件换成相应的is...()函数。(提示:可能要用到ispunct()和isalnum()。)
#26
我怎么感觉用正则表达式实现起来还要简单一些??
#28
不在于简单,而是可读性和易维护,代价就是效率低。看用在什么场合了。
实际上对于这么小的例子,用正则表达式实现并不简单。杀鸡用牛刀不一定好用。
#29
用正则很简单,只是lz把代码写的很麻烦而已
#30
你23楼的代码没考虑全各种情况,都写全了也不少。
比如说你没考虑数字,而且当文件以字母结束时的结果是错的。
#31
It's a hand-me-down.
↑这句里面到底有几个单词?
↑这句里面到底有几个单词?
#32
LZ的问题激发了我的想象。
让我们从TCPL中的序章的例子聊起:
很明显这里判断所谓一个单词的方法,就是由<space><tab><newline>充当分隔符,它们所隔开的,就是词;注意,在这种情况,非<space><tab><newline>字符,都会认为是单词的一部分,显然离LZ的“规则”很远,但是这个“规则”很朴素,适合讨论问题。
暂时顿一顿,看看C++的版本:
显然C++的抽象层次高了许多,但明显,这里的“规则”并无发生明显的变化,cin >> word默认情况下,也是按上述“空白”规则来划分单词的。
由于本人C++水平有限,不便以C++展开讨论,所以将上述C++版本,转成了一个C的版本,好讨论:
好,我们看到,c == ' ' || c == '\t' || c == '\n'这样一个逻辑判断,已经从第一个例子中的if语句,单独抽象出来了。
我们再重构一下,也许更容易理解:
好,现在我们有了一个谓词is_separator,那么显然!is_separator就是单词部分。
我们可以很方便的通过separators的定义,来构造规则了。
那么这和第一个例子还有LZ的问题之间有什么关系呢?
个人的理解,第一个例子演示了基本的状态机,而后面C++和C的例子,显然是更高层次的抽象,特别是最后一个例子,我们通过构造一个“集合”,来构造规则,当然这个“集合”很朴素,直接用到了C的基本类型;再高级点,其实就是re了,re提供了更高级的抽象和弹性,来构造我们想要的“规则”,但基本想法,应该是差不多了,就是状态机了。
至于scanf的[]还有strtok之类,从某种程度来讲,都是状态机不同层次的一个抽象。
最后至于Unicode,可以认为是char的延伸,即规则复杂了,“集合”更大更难构造了,但状态机的想法,还是不变的。
以上,就是我想聊的东西,很肤浅,算是一点个人的心得。
万宗同源,这也许就是我喜欢C和第一个例子的原因吧。
如果给出separators[] = ",.? \t\n"
“i hate C++ ,and you ?”
也能给出5个单词了。
当然,LZ还能给出更多的反例,但是归根到底,就是规则和谓词的构造了,比如separators太多,我们可以定义chars集合,它的补集即为separators集合(谓词取反操作)。
不管怎样,总是可以暴力列举所有的字符的集合。
以上所有的讨论,都是建立在“给定一个字符,它要么是单词的一部分,要么是分隔符”这样一个基础规则上,不涉及到语义,否则“我讨厌C++,你呢?”有几个单词?
让我们从TCPL中的序章的例子聊起:
# include <stdio.h>
# define IN 0
# define OUT 1
int main()
{
int c;
int n = 0;
int status = OUT;
while ((c = getchar()) != EOF)
{
if (c == ' ' || c == '\t' || c == '\n')
{
if (status == IN)
status = OUT;
}
else
{
if (status == OUT)
{
status = IN;
n++;
}
}
}
printf("%d\n", n);
return 0;
}
很明显这里判断所谓一个单词的方法,就是由<space><tab><newline>充当分隔符,它们所隔开的,就是词;注意,在这种情况,非<space><tab><newline>字符,都会认为是单词的一部分,显然离LZ的“规则”很远,但是这个“规则”很朴素,适合讨论问题。
暂时顿一顿,看看C++的版本:
# include <iostream>
# include <string>
using namespace std;
int main()
{
string word;
int n;
while (cin >> word)
n++;
cout << n << endl;
return 0;
}
显然C++的抽象层次高了许多,但明显,这里的“规则”并无发生明显的变化,cin >> word默认情况下,也是按上述“空白”规则来划分单词的。
由于本人C++水平有限,不便以C++展开讨论,所以将上述C++版本,转成了一个C的版本,好讨论:
# include <stdio.h>
int is_separator(int c)
{
return c == ' ' || c == '\t' || c == '\n';
}
int get_word(FILE * input)
{
int c;
while ((c = fgetc(input)) != EOF && is_separator(c))
;
if (c == EOF)
return 0;
else
{
ungetc(c, input);
while ((c = fgetc(input)) != EOF && !is_separator(c))
;
if (c != EOF)
ungetc(c, input);
return 1;
}
}
int main()
{
int n = 0;
while (get_word(stdin))
{
n++;
}
printf("%d\n", n);
return 0;
}
好,我们看到,c == ' ' || c == '\t' || c == '\n'这样一个逻辑判断,已经从第一个例子中的if语句,单独抽象出来了。
我们再重构一下,也许更容易理解:
int is_separator(int c)
{
static const char separators[] = " \t\n";
return strchr(separators, c) != NULL;
}
好,现在我们有了一个谓词is_separator,那么显然!is_separator就是单词部分。
我们可以很方便的通过separators的定义,来构造规则了。
那么这和第一个例子还有LZ的问题之间有什么关系呢?
个人的理解,第一个例子演示了基本的状态机,而后面C++和C的例子,显然是更高层次的抽象,特别是最后一个例子,我们通过构造一个“集合”,来构造规则,当然这个“集合”很朴素,直接用到了C的基本类型;再高级点,其实就是re了,re提供了更高级的抽象和弹性,来构造我们想要的“规则”,但基本想法,应该是差不多了,就是状态机了。
至于scanf的[]还有strtok之类,从某种程度来讲,都是状态机不同层次的一个抽象。
最后至于Unicode,可以认为是char的延伸,即规则复杂了,“集合”更大更难构造了,但状态机的想法,还是不变的。
以上,就是我想聊的东西,很肤浅,算是一点个人的心得。
万宗同源,这也许就是我喜欢C和第一个例子的原因吧。
如果给出separators[] = ",.? \t\n"
“i hate C++ ,and you ?”
也能给出5个单词了。
当然,LZ还能给出更多的反例,但是归根到底,就是规则和谓词的构造了,比如separators太多,我们可以定义chars集合,它的补集即为separators集合(谓词取反操作)。
不管怎样,总是可以暴力列举所有的字符的集合。
以上所有的讨论,都是建立在“给定一个字符,它要么是单词的一部分,要么是分隔符”这样一个基础规则上,不涉及到语义,否则“我讨厌C++,你呢?”有几个单词?
#33
请教,用正则表达式如何更好地实现??
#34
啊?还有这个问题?差点采用了
#35
按照三个单词来计算,连字符连接的算一个
#36
只要是以标点或空格分隔开的都应计算为一个单词?
#37
何必那么烦呢?
不知这个如何?
#include <iostream>
#include <string>
#include <ctype.h>
#include <string.h>
using std::cout;
using std::endl;
using std::string;
template<class T>
int WordNum(const T& str,int cef)
{
bool isnum=true;
int i;
int wordnum=0;
//跳过空格和非字母字符
for( i=0; (i < cef) && (!isalpha(str[i])); i++ );
//开始计算
for( ; i < cef; i++ )
{
if( (!isalpha(str[i])) && isnum )
{
wordnum++;
isnum=false;
}
else if( isalpha(str[i]) )
isnum=true;
else
continue;
}
if( isnum )
wordnum++;
return wordnum;
}
int main(int argc,char** argv)
{
string str;
int n;
str="fkfn fn bv,b, b kvmbmvmm......fhfjd";
cout<<str<<"\nword num is=";
n=WordNum(str,str.size());
cout<<n<<endl;
char str1[]="hello word !";
cout<<str1<<"\nword num is=";
n=WordNum(str1,strlen(str1));
cout<<n<<endl;
return 0;
}
不知这个如何?
#include <iostream>
#include <string>
#include <ctype.h>
#include <string.h>
using std::cout;
using std::endl;
using std::string;
template<class T>
int WordNum(const T& str,int cef)
{
bool isnum=true;
int i;
int wordnum=0;
//跳过空格和非字母字符
for( i=0; (i < cef) && (!isalpha(str[i])); i++ );
//开始计算
for( ; i < cef; i++ )
{
if( (!isalpha(str[i])) && isnum )
{
wordnum++;
isnum=false;
}
else if( isalpha(str[i]) )
isnum=true;
else
continue;
}
if( isnum )
wordnum++;
return wordnum;
}
int main(int argc,char** argv)
{
string str;
int n;
str="fkfn fn bv,b, b kvmbmvmm......fhfjd";
cout<<str<<"\nword num is=";
n=WordNum(str,str.size());
cout<<n<<endl;
char str1[]="hello word !";
cout<<str1<<"\nword num is=";
n=WordNum(str1,strlen(str1));
cout<<n<<endl;
return 0;
}
#38
那是不知道具体需求到底是什么而已,加上数字,也就改改正则表达式就行了,不会增加什么代码。
#39
分析得太详细了
谢谢你
我能不能把你这篇文章转载到我的blog,作为这问题的一些补充?
谢谢
#40
我的理解是这样
但是,标点有很多种啊,不太好处理
#41
需求,比如就是简单实现Office Word的字数统计
#42
请便。
#43
谢谢
#44
#include <algorithm>
#include <iostream>
#include<regex>
#include<fstream>
using namespace std;
int main( int argc, char* argv[] )
{
ifstream ifs( "ReadMe.txt" );
std::string s;
int n=0;
while( getline( ifs , s ) )
{
n += distance( sregex_iterator( s.begin() , s.end() , regex("(([a-zA-Z]+-[a-zA-Z]+)|([a-zA-Z]+))(?:\\b)") ) , sregex_iterator() );
}
cout<< n <<endl;
return 0;
}
#45
倒!一口大鲜血啊,竟然用getline,没看过effective stl啊。
#46
其实仅仅是统计单词数的话
ifstream ifs("file1.txt");
int wordCount=count_if(istream_iterator<string>(ifs),istream_iterator<string>(),[](const string &s){return s!=",";});
#47
这个只是无视逗号和空格,其他符号一律看作单词
#48
这个数字也当做单词
ifstream ifs("file1.txt");
regex r("\\w+");
int wordCount=count_if(istream_iterator<string>(ifs),istream_iterator<string>(),[&](const string &s){return regex_search(s,r);});
#49
赶紧找出effective stl看了下
#include <algorithm>
#include <iostream>
#include<regex>
#include<fstream>
using namespace std;
int main( int argc, char* argv[] )
{
string s( istreambuf_iterator<char>( ifstream( "ReadMe.txt" ) ) , istreambuf_iterator<char>() );
cout<< distance( sregex_iterator( s.begin() , s.end()
, regex("(([a-zA-Z]+-[a-zA-Z]+)|([a-zA-Z]+))(?:\\b)") ) , sregex_iterator() ) <<endl;
return 0;
}
#1
不錯了。。。
#2
晕,都isfream了还用Char数组,自己给自己挖坑啊。
#3
在C#里面估计一句就够了
#4
C++同样只需要一句的。
#5
典型的简单问题复杂化啊
#6
哪一句?
#7
你有更加简单的方法?能不能教教我?
#8
不用char数组用什么?
#9
都 #include<string> 了
#10
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z]" );
while( fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#11
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z]" );
while( fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#12
嗯,确实非常简洁
我想再请教一下
fscanf( fp , "%*[a-zA-Z]%*[^a-zA-Z]" )
其中的%*[a-zA-Z]%*[^a-zA-Z]是什么意思?
另外,如果这个单词是由于连字符连接而成的,该如何处理啊?
比如,is-a是一个单词,而不是两个
#13
while (instream >> word)
count++
??
count++
??
#14
这样很不准确
比如“i hate C++ , and you ?”
可能会统计出7个单词
#15
规则是人定的
is-a既可以是一个单词,也可以是两个单词。
is-a既可以是一个单词,也可以是两个单词。
#16
为什么要正则式啊?一个很简单事情。
#17
这个问题复杂度奇高!
试统计以下句子的单词数:
◆That's a problem!
◆这个问题复杂度奇高!
◆이 문장에서 몇 단어?
◆بعض الكلمات في هذه الجملة؟
试统计以下句子的单词数:
◆That's a problem!
◆这个问题复杂度奇高!
◆이 문장에서 몇 단어?
◆بعض الكلمات في هذه الجملة؟
#18
那现在的规则就是将is-a定义成一个单词,用你的fscanf该如何解决呢?
#19
很简单吗?
不如把你的方案写出来,大家参考参考?
#20
哦,倒不一定要针对不同的语种
单单就英文而言,该如何解决呢?
#21
distance(sregex_iterator(。。。), sregex_iterator())
#22
那我的规则就是is-a是两个单词。
#23
#include <stdio.h>
int main ( )
{
int n=0;
FILE* fp = fopen( "hello.c" , "r" );
fscanf( fp , "%*[^a-zA-Z-]" );
while( fscanf( fp , "%*[a-zA-Z-]%*[^a-zA-Z-]" ) >-1 )
{
n++;
}
fclose(fp);
printf( "%d\n" , n );
return 0 ;
}
#24
c/c++中有一个很古老的函数 strtok()就是干这个用的。
这么简单的情况就不要用正则表达式了,自己写一个循环也没多难。
int countword(char const* s)
{
int n = 0;
while(true)
{
while( isspace(*s) ) ++s;
if( !isgraph(*s++)) break;
while( isgraph(*s) ) ++s;
++n;
}
return n;
}
这么简单的情况就不要用正则表达式了,自己写一个循环也没多难。
int countword(char const* s)
{
int n = 0;
while(true)
{
while( isspace(*s) ) ++s;
if( !isgraph(*s++)) break;
while( isgraph(*s) ) ++s;
++n;
}
return n;
}
#25
补充一点,如果需要考虑标点符号的话,可以用strtok的delim参数,也可以把上例中的判断条件换成相应的is...()函数。(提示:可能要用到ispunct()和isalnum()。)
#26
我怎么感觉用正则表达式实现起来还要简单一些??
#27
#28
不在于简单,而是可读性和易维护,代价就是效率低。看用在什么场合了。
实际上对于这么小的例子,用正则表达式实现并不简单。杀鸡用牛刀不一定好用。
#29
用正则很简单,只是lz把代码写的很麻烦而已
#30
你23楼的代码没考虑全各种情况,都写全了也不少。
比如说你没考虑数字,而且当文件以字母结束时的结果是错的。
#31
It's a hand-me-down.
↑这句里面到底有几个单词?
↑这句里面到底有几个单词?
#32
LZ的问题激发了我的想象。
让我们从TCPL中的序章的例子聊起:
很明显这里判断所谓一个单词的方法,就是由<space><tab><newline>充当分隔符,它们所隔开的,就是词;注意,在这种情况,非<space><tab><newline>字符,都会认为是单词的一部分,显然离LZ的“规则”很远,但是这个“规则”很朴素,适合讨论问题。
暂时顿一顿,看看C++的版本:
显然C++的抽象层次高了许多,但明显,这里的“规则”并无发生明显的变化,cin >> word默认情况下,也是按上述“空白”规则来划分单词的。
由于本人C++水平有限,不便以C++展开讨论,所以将上述C++版本,转成了一个C的版本,好讨论:
好,我们看到,c == ' ' || c == '\t' || c == '\n'这样一个逻辑判断,已经从第一个例子中的if语句,单独抽象出来了。
我们再重构一下,也许更容易理解:
好,现在我们有了一个谓词is_separator,那么显然!is_separator就是单词部分。
我们可以很方便的通过separators的定义,来构造规则了。
那么这和第一个例子还有LZ的问题之间有什么关系呢?
个人的理解,第一个例子演示了基本的状态机,而后面C++和C的例子,显然是更高层次的抽象,特别是最后一个例子,我们通过构造一个“集合”,来构造规则,当然这个“集合”很朴素,直接用到了C的基本类型;再高级点,其实就是re了,re提供了更高级的抽象和弹性,来构造我们想要的“规则”,但基本想法,应该是差不多了,就是状态机了。
至于scanf的[]还有strtok之类,从某种程度来讲,都是状态机不同层次的一个抽象。
最后至于Unicode,可以认为是char的延伸,即规则复杂了,“集合”更大更难构造了,但状态机的想法,还是不变的。
以上,就是我想聊的东西,很肤浅,算是一点个人的心得。
万宗同源,这也许就是我喜欢C和第一个例子的原因吧。
如果给出separators[] = ",.? \t\n"
“i hate C++ ,and you ?”
也能给出5个单词了。
当然,LZ还能给出更多的反例,但是归根到底,就是规则和谓词的构造了,比如separators太多,我们可以定义chars集合,它的补集即为separators集合(谓词取反操作)。
不管怎样,总是可以暴力列举所有的字符的集合。
以上所有的讨论,都是建立在“给定一个字符,它要么是单词的一部分,要么是分隔符”这样一个基础规则上,不涉及到语义,否则“我讨厌C++,你呢?”有几个单词?
让我们从TCPL中的序章的例子聊起:
# include <stdio.h>
# define IN 0
# define OUT 1
int main()
{
int c;
int n = 0;
int status = OUT;
while ((c = getchar()) != EOF)
{
if (c == ' ' || c == '\t' || c == '\n')
{
if (status == IN)
status = OUT;
}
else
{
if (status == OUT)
{
status = IN;
n++;
}
}
}
printf("%d\n", n);
return 0;
}
很明显这里判断所谓一个单词的方法,就是由<space><tab><newline>充当分隔符,它们所隔开的,就是词;注意,在这种情况,非<space><tab><newline>字符,都会认为是单词的一部分,显然离LZ的“规则”很远,但是这个“规则”很朴素,适合讨论问题。
暂时顿一顿,看看C++的版本:
# include <iostream>
# include <string>
using namespace std;
int main()
{
string word;
int n;
while (cin >> word)
n++;
cout << n << endl;
return 0;
}
显然C++的抽象层次高了许多,但明显,这里的“规则”并无发生明显的变化,cin >> word默认情况下,也是按上述“空白”规则来划分单词的。
由于本人C++水平有限,不便以C++展开讨论,所以将上述C++版本,转成了一个C的版本,好讨论:
# include <stdio.h>
int is_separator(int c)
{
return c == ' ' || c == '\t' || c == '\n';
}
int get_word(FILE * input)
{
int c;
while ((c = fgetc(input)) != EOF && is_separator(c))
;
if (c == EOF)
return 0;
else
{
ungetc(c, input);
while ((c = fgetc(input)) != EOF && !is_separator(c))
;
if (c != EOF)
ungetc(c, input);
return 1;
}
}
int main()
{
int n = 0;
while (get_word(stdin))
{
n++;
}
printf("%d\n", n);
return 0;
}
好,我们看到,c == ' ' || c == '\t' || c == '\n'这样一个逻辑判断,已经从第一个例子中的if语句,单独抽象出来了。
我们再重构一下,也许更容易理解:
int is_separator(int c)
{
static const char separators[] = " \t\n";
return strchr(separators, c) != NULL;
}
好,现在我们有了一个谓词is_separator,那么显然!is_separator就是单词部分。
我们可以很方便的通过separators的定义,来构造规则了。
那么这和第一个例子还有LZ的问题之间有什么关系呢?
个人的理解,第一个例子演示了基本的状态机,而后面C++和C的例子,显然是更高层次的抽象,特别是最后一个例子,我们通过构造一个“集合”,来构造规则,当然这个“集合”很朴素,直接用到了C的基本类型;再高级点,其实就是re了,re提供了更高级的抽象和弹性,来构造我们想要的“规则”,但基本想法,应该是差不多了,就是状态机了。
至于scanf的[]还有strtok之类,从某种程度来讲,都是状态机不同层次的一个抽象。
最后至于Unicode,可以认为是char的延伸,即规则复杂了,“集合”更大更难构造了,但状态机的想法,还是不变的。
以上,就是我想聊的东西,很肤浅,算是一点个人的心得。
万宗同源,这也许就是我喜欢C和第一个例子的原因吧。
如果给出separators[] = ",.? \t\n"
“i hate C++ ,and you ?”
也能给出5个单词了。
当然,LZ还能给出更多的反例,但是归根到底,就是规则和谓词的构造了,比如separators太多,我们可以定义chars集合,它的补集即为separators集合(谓词取反操作)。
不管怎样,总是可以暴力列举所有的字符的集合。
以上所有的讨论,都是建立在“给定一个字符,它要么是单词的一部分,要么是分隔符”这样一个基础规则上,不涉及到语义,否则“我讨厌C++,你呢?”有几个单词?
#33
请教,用正则表达式如何更好地实现??
#34
啊?还有这个问题?差点采用了
#35
按照三个单词来计算,连字符连接的算一个
#36
只要是以标点或空格分隔开的都应计算为一个单词?
#37
何必那么烦呢?
不知这个如何?
#include <iostream>
#include <string>
#include <ctype.h>
#include <string.h>
using std::cout;
using std::endl;
using std::string;
template<class T>
int WordNum(const T& str,int cef)
{
bool isnum=true;
int i;
int wordnum=0;
//跳过空格和非字母字符
for( i=0; (i < cef) && (!isalpha(str[i])); i++ );
//开始计算
for( ; i < cef; i++ )
{
if( (!isalpha(str[i])) && isnum )
{
wordnum++;
isnum=false;
}
else if( isalpha(str[i]) )
isnum=true;
else
continue;
}
if( isnum )
wordnum++;
return wordnum;
}
int main(int argc,char** argv)
{
string str;
int n;
str="fkfn fn bv,b, b kvmbmvmm......fhfjd";
cout<<str<<"\nword num is=";
n=WordNum(str,str.size());
cout<<n<<endl;
char str1[]="hello word !";
cout<<str1<<"\nword num is=";
n=WordNum(str1,strlen(str1));
cout<<n<<endl;
return 0;
}
不知这个如何?
#include <iostream>
#include <string>
#include <ctype.h>
#include <string.h>
using std::cout;
using std::endl;
using std::string;
template<class T>
int WordNum(const T& str,int cef)
{
bool isnum=true;
int i;
int wordnum=0;
//跳过空格和非字母字符
for( i=0; (i < cef) && (!isalpha(str[i])); i++ );
//开始计算
for( ; i < cef; i++ )
{
if( (!isalpha(str[i])) && isnum )
{
wordnum++;
isnum=false;
}
else if( isalpha(str[i]) )
isnum=true;
else
continue;
}
if( isnum )
wordnum++;
return wordnum;
}
int main(int argc,char** argv)
{
string str;
int n;
str="fkfn fn bv,b, b kvmbmvmm......fhfjd";
cout<<str<<"\nword num is=";
n=WordNum(str,str.size());
cout<<n<<endl;
char str1[]="hello word !";
cout<<str1<<"\nword num is=";
n=WordNum(str1,strlen(str1));
cout<<n<<endl;
return 0;
}
#38
那是不知道具体需求到底是什么而已,加上数字,也就改改正则表达式就行了,不会增加什么代码。
#39
分析得太详细了
谢谢你
我能不能把你这篇文章转载到我的blog,作为这问题的一些补充?
谢谢
#40
我的理解是这样
但是,标点有很多种啊,不太好处理
#41
需求,比如就是简单实现Office Word的字数统计
#42
请便。
#43
谢谢
#44
#include <algorithm>
#include <iostream>
#include<regex>
#include<fstream>
using namespace std;
int main( int argc, char* argv[] )
{
ifstream ifs( "ReadMe.txt" );
std::string s;
int n=0;
while( getline( ifs , s ) )
{
n += distance( sregex_iterator( s.begin() , s.end() , regex("(([a-zA-Z]+-[a-zA-Z]+)|([a-zA-Z]+))(?:\\b)") ) , sregex_iterator() );
}
cout<< n <<endl;
return 0;
}
#45
倒!一口大鲜血啊,竟然用getline,没看过effective stl啊。
#46
其实仅仅是统计单词数的话
ifstream ifs("file1.txt");
int wordCount=count_if(istream_iterator<string>(ifs),istream_iterator<string>(),[](const string &s){return s!=",";});
#47
这个只是无视逗号和空格,其他符号一律看作单词
#48
这个数字也当做单词
ifstream ifs("file1.txt");
regex r("\\w+");
int wordCount=count_if(istream_iterator<string>(ifs),istream_iterator<string>(),[&](const string &s){return regex_search(s,r);});
#49
赶紧找出effective stl看了下
#include <algorithm>
#include <iostream>
#include<regex>
#include<fstream>
using namespace std;
int main( int argc, char* argv[] )
{
string s( istreambuf_iterator<char>( ifstream( "ReadMe.txt" ) ) , istreambuf_iterator<char>() );
cout<< distance( sregex_iterator( s.begin() , s.end()
, regex("(([a-zA-Z]+-[a-zA-Z]+)|([a-zA-Z]+))(?:\\b)") ) , sregex_iterator() ) <<endl;
return 0;
}