Coding的痕迹

一位互联网奔跑者的网上日记

0%

(原) VC++lrc歌词解析类

由于时间仓促,所以没有加过多的错误处理或检查,另外结构体、变量和字符串等没有动态定义,可能会导致严重的缓冲区错误,所以如果要当做一个项目来做的话,建议加上这些处理、检查,并动态分配内存。
虽然说这是写成了一个C++类,但是文件读写以及许多函数都是C中的。见代码吧!代码看起来比较简单,老规矩,下载地址在后面。

差点忘记说明了,这种实现比较不好暂停,若有好点子,欢迎回复。谢谢!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// 编译环境:Microsoft Visual C++ 6.0

#include <stdio.h>
#include <windows.h>

typedef struct
{
unsigned int time;
char data[40]; // 可能导致长的歌词无法显示/缓冲区溢出,但是大部分歌词是没这么长的……

}LineData;

class CLrc
{
public:

BOOL Open( LPTSTR FileName );
void Close();
BOOL GetTitle( LPTSTR Title ); // 未实现
BOOL GetAlbum( LPTSTR Album ); // 未实现
BOOL GetArtist( LPTSTR Artist ); // 未实现
BOOL GetEditor( LPTSTR Editor ); // 未实现
BOOL ReadLine( LPTSTR Data );
CLrc()
{
memset( LrcFile, 0, 128 );
ldpoint = 0;
hLrcFile = NULL;
}
~CLrc()
{
if( hLrcFile != NULL )
{
fclose( hLrcFile );
}
}
// private: // 测试用,所以所有函数、类都使用public的了
FILE *hLrcFile;
char LrcFile[128];
LineData ld[100];
int ldpoint;
void DelCRLF( char *Data );
void Sort();
int Findch( const char *str, unsigned char ch );
int GetTime( const char *line );
void ResolveLine( const char *line );
void GetLineData( const char *line, char *data );
};

// 打开文件
BOOL CLrc::Open( LPTSTR FileName )
{
FILE *fp;
fp = fopen(FileName, "r");
if( fp == NULL )
{
return FALSE;
}
hLrcFile = fp;
return TRUE;
}
// 关闭文件
void CLrc::Close()
{
if( hLrcFile != NULL )
{
fclose( hLrcFile );
}
}
// 获得行的歌词
// 例如,[00:00.01]abc,该函数将获取到的"abc"保存到data中
void CLrc::GetLineData( const char *line, char *data )
{
int i = 0,
j = 0,
len;
if( strcmp( line, "" ) )
{
len = strlen( line );
i = len;
while( line[i] != ']' && i > 0 )
{
i--;
}
for( j = i + 1, i += 1; j <= len; j++ )
{
data[j - i] = line[j];
}
}
}
// 读取下一行数据
BOOL CLrc::ReadLine( char *line )
{
char Line[100];
memset( Line, 0, 100 );
if( feof( hLrcFile ) || fgets( Line, 100, hLrcFile) == NULL )
{
return FALSE; // 表示文件结束
}
DelCRLF( Line );
strcpy( line, Line );
return TRUE; // 正常
}
// 删除Data中的空格
void CLrc::DelCRLF( char *Data )
{
int i = 0;
int len = strlen( Data );
for( ; i < len; i++ )
{
if( Data[i] == 0x0D || Data[i] == 0x0A )
{
int j = i;
for( ; j < len ; j++ )
{
Data[j] = Data[j + 1];
}
}
}
}
// Findch用于检测ch在str中出现的次数
int CLrc::Findch( const char *str, unsigned char ch )
{
int i = strlen( str );
int quan = 0;
while( i-- )
{
if( str[i] == ch )
{
quan++;
}
}
return quan;
}
// 获得歌词时间
int CLrc::GetTime( const char *line )
{
int min = 0,
sec = 0,
ms = 0;
if(Findch(line, '.') == 0)
{
sscanf( line, "[%d:%d]", &min, &sec );
}
else
{
sscanf( line, "[%d:%d.%d]", &min, &sec, &ms );
}
return (min * 6000 + sec * 100 + ms );
}
// 解析每一行的数据,存入结构
void CLrc::ResolveLine( const char *line )
{
char str[100];
int i = 0,
j = 0,
last = 0;
strcpy( str, line );
if (Findch(str, '[') != Findch(str, ']') ) // 检测正确性
{
return;
}
for (i = 0; i <= strlen(str); i++ )
{
if (str[i] == ']')
{
char buf[50] = "";
int t = 0;

for (j = last; j <= i; j++ )
{
buf[t++] = str[j];
}
ld[ ldpoint ].time = GetTime( buf ) * 10;
GetLineData( line, ld[ldpoint].data);
ldpoint++;

i++;
last = i;
}
}
}
// 将结构中所有歌词排序,冒泡排序
void CLrc::Sort()
{
int i = 0, j;
for( ; i < ldpoint - 1; i++ )
{
for( j = i; j < ldpoint - i; j++ )
{
if( ld[j].time > ld[j + 1].time )
{
LineData t;
t = ld[j];
ld[j] = ld[j + 1];
ld[j + 1] = t;
}
}
}
}

调用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int main( int argc, char  *argv[] )
{
CLrc lrc;
if( lrc.Open("lrc file.lrc") == FALSE )
{
printf( "无法打开歌词文件!\n" );
return 0;
}

while( true )
{
char line[100] = "";

if( !lrc.ReadLine( line ) ) // 读完了
{
break;
}
if( strcmp( line, "" ) )
{
lrc.ResolveLine( line ); // 解析数据
}
}
lrc.Close(); // 关闭文件句柄
lrc.Sort(); // 排序
if( lrc.ldpoint ) // 若ldpoint == 0,则无数据。所以防止出现这种情况
{

/* Sleep()在printf的前面,我曾经弄反了,结果…… */
Sleep( lrc.ld[0].time );
printf( "%s\n", lrc.ld[0].data ); // 输出第一行

for( int i = 1; i < lrc.ldpoint; i++ )
{
Sleep( lrc.ld[i].time - lrc.ld[i - 1].time );
printf( "%s\n", lrc.ld[i].data );
}
}
return 0;
}

现在好多人都用baidu,不知何故,真是后出来的反而被推崇……只有像我这样的小白才用360了 [原]VC++lrc歌词解析类 - sunnysab - 奋斗,百度太抠门,做个活动送几百GB还要银子

2013-09-21 17:09
特别说明:[xx:xx.xx]必须在某一行的前面。且歌词中不应出现’[‘或’]’。