~ubuntu-branches/ubuntu/jaunty/imms/jaunty

« back to all changes in this revision

Viewing changes to strmanip.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Veber
  • Date: 2005-04-13 23:43:11 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050413234311-kzr68z9l7z5mv551
Tags: 2.0.3-2
Build depend on xmms-dev (>= 1.2.10+cvs20050209)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "strmanip.h"
2
 
 
3
 
#include <sys/types.h>
4
 
#include <dirent.h>
5
 
#include <string.h>
6
 
 
7
 
#include <iostream>
8
 
 
9
 
using std::list;
10
 
 
11
 
Regexx rex;
12
 
 
13
 
string extradelims;
14
 
 
15
 
#define DELIM "[-\\s_\\.'\\(\\)\\[\\]]"
16
 
#define NUMRE "(^|" DELIM "+)(\\d+)($|" DELIM "+)"
17
 
 
18
 
void string_split(list<string> &store, const string &s, const string &delims)
19
 
{
20
 
    string expr("(?>[^" + delims + "]+)");
21
 
    rex.exec(s, expr, Regexx::global);
22
 
    store.insert(store.end(), rex.match.begin(), rex.match.end());
23
 
}
24
 
 
25
 
string escape_char(char c)
26
 
{
27
 
    string s(1, c);
28
 
    switch (c)
29
 
    {
30
 
        case '[':
31
 
        case ']':
32
 
        case '(':
33
 
        case ')':
34
 
        case '.':
35
 
            s = "\\" + s;
36
 
        default:
37
 
            break;
38
 
    }
39
 
    return s;
40
 
}
41
 
 
42
 
bool imms_magic_preprocess_filename(string &filename)
43
 
{
44
 
    filename = rex.replace(filename, "[-\\s_\\.]{2,}", "/");
45
 
 
46
 
    bool confident = rex.matches();
47
 
 
48
 
    if (confident)
49
 
        return true;
50
 
 
51
 
    if (extradelims != "")
52
 
    {
53
 
        filename = rex.replace(filename, "[" + extradelims + "]",
54
 
                "/", Regexx::global);
55
 
        confident = rex.matches();
56
 
    }
57
 
 
58
 
    if (!confident)
59
 
    {
60
 
        int spaces = rex.exec(filename, " ", Regexx::global);
61
 
        int dashes = rex.exec(filename, "-", Regexx::global);
62
 
        int scores = rex.exec(filename, "_", Regexx::global);
63
 
 
64
 
        if ((!spaces || !scores) && dashes && dashes < 3
65
 
                && (spaces >= dashes || scores >= dashes))
66
 
            filename = rex.replace(filename, "-", "/", Regexx::global);
67
 
    }
68
 
 
69
 
    return confident;
70
 
}
71
 
 
72
 
void imms_magic_preprocess_path(string &path)
73
 
{
74
 
    path = string_tolower(path);
75
 
    path = rex.replace(path, "[-\\s_\\.]{2,}", "/", Regexx::global);
76
 
    path = rex.replace(path, "(/|^)[\\(\\[]", "/", Regexx::global);
77
 
    path = rex.replace(path, "[\\(\\[][^/]+[\\)\\]]/", "/", Regexx::global);
78
 
    path = rex.replace(path, "[-\\s_\\./][iv]{2}i?[/$]", "/", Regexx::global);
79
 
    path = rex.replace(path, "[^a-z/]", "", Regexx::global);
80
 
}
81
 
 
82
 
bool imms_magic_parse_filename(list<string> &store, string filename)
83
 
{
84
 
        bool result = imms_magic_preprocess_filename(filename);
85
 
        imms_magic_preprocess_path(filename);
86
 
    string_split(store, filename, "/");
87
 
    return result;
88
 
}
89
 
 
90
 
void imms_magic_parse_path(list<string> &store, string path)
91
 
{
92
 
    path = rex.replace(path, "/+$", "", Regexx::global);
93
 
 
94
 
        string lastdir = path_get_filename(path);
95
 
        path = path_get_dirname(path);
96
 
 
97
 
        imms_magic_preprocess_path(path);
98
 
    string_split(store, path, "/");
99
 
 
100
 
        imms_magic_preprocess_filename(lastdir);
101
 
        imms_magic_preprocess_path(lastdir);
102
 
        string_split(store, lastdir, "/");
103
 
}
104
 
 
105
 
string string_normalize(string s)
106
 
{
107
 
    s = string_brfilter(string_tolower(s));
108
 
    s = rex.replace(s, "[^a-z]", "", Regexx::global);
109
 
    return s;
110
 
}
111
 
 
112
 
bool string_like(const string &s1, const string &s2, int slack)
113
 
{
114
 
    int len1 = s1.length();
115
 
    int len2 = s2.length();
116
 
 
117
 
    int distance = lev_edit_distance(len1, s1.c_str(), len2, s2.c_str(), 0);
118
 
    return (len1 + len2) / (13 - slack) >= distance;
119
 
}
120
 
 
121
 
LevMatchingBlock *get_matching_blocks(const string &s1, const string &s2,
122
 
        size_t &n)
123
 
{
124
 
    int len1 = s1.length(), len2 = s2.length();
125
 
    size_t num_editops;
126
 
    LevEditOp *editops = lev_editops_find(len1, s1.c_str(), len2, s2.c_str(),
127
 
            &num_editops);
128
 
 
129
 
    LevMatchingBlock *blocks =
130
 
        lev_editops_matching_blocks(len1, len2, num_editops, editops, &n);
131
 
 
132
 
    free(editops);
133
 
 
134
 
    return blocks;
135
 
}
136
 
 
137
 
string filename_cleanup(const string &s)
138
 
{
139
 
    return string_tolower(rex.replace(s, "(\\d)", "#", Regexx::global));
140
 
}
141
 
 
142
 
string get_filename_mask(const string& path)
143
 
{
144
 
    string dirname = path_get_dirname(path);
145
 
    string filename = filename_cleanup(path_get_filename(path));
146
 
    string extension = path_get_extension(path);
147
 
 
148
 
    list<string> files;
149
 
 
150
 
    DIR *dir = opendir(dirname.c_str());
151
 
    struct dirent *de;
152
 
    while ((de = readdir(dir)))
153
 
    {
154
 
        if (de->d_name[0] != '.' && path_get_extension(de->d_name) == extension)
155
 
            files.push_back(filename_cleanup(path_get_filename(de->d_name)));
156
 
    }
157
 
    closedir(dir);
158
 
 
159
 
    char *mask = new char[filename.length() + 1];
160
 
    memset(mask, 0, filename.length() + 1);
161
 
 
162
 
    int count = 0;
163
 
    for (list<string>::iterator i = files.begin(); i != files.end(); i++)
164
 
    {
165
 
        count++;
166
 
        size_t num_blocks;
167
 
        LevMatchingBlock *blocks = get_matching_blocks(filename, *i, num_blocks);
168
 
 
169
 
        for (size_t j = 0; j < num_blocks; j++)
170
 
        {
171
 
            for (size_t k = 0; k < blocks[j].len; k++)
172
 
                mask[blocks[j].spos + k]++;
173
 
        }
174
 
 
175
 
        free(blocks);
176
 
        if (count > 20)
177
 
            break;
178
 
    }
179
 
 
180
 
    string strmask = "";
181
 
    for (size_t i = 0; i < filename.length(); i++)
182
 
    {
183
 
        strmask += mask[i] > count * 0.7 ? filename[i] : '*';
184
 
    }
185
 
 
186
 
    delete[] mask;
187
 
 
188
 
    return strmask;
189
 
}
190
 
 
191
 
struct H
192
 
{
193
 
    static string filename;
194
 
    static string mask;
195
 
    static string double_erase(const regexx::RegexxMatch& _match)
196
 
    {
197
 
        mask.erase(_match.start(), _match.length());
198
 
        filename.erase(_match.start(), _match.length());
199
 
 
200
 
        return "";
201
 
    }
202
 
    static string numerals(const regexx::RegexxMatch& _match)
203
 
    {
204
 
        extradelims = "";
205
 
        string replacement = "/";
206
 
        int l1 = _match.atom[0].length(), l2 = _match.atom[2].length();
207
 
 
208
 
        if (l1 < 2 && l2 < 2)
209
 
        {
210
 
            if (_match.atom[0].str() != " " && _match.atom[0].str() != "_")
211
 
            {
212
 
                replacement = _match.atom[0].str();
213
 
                if (_match.atom[0].length() == 1)
214
 
                    extradelims += escape_char(_match.atom[0].str()[0]);
215
 
            }
216
 
            if (_match.atom[2].str() != " " && _match.atom[2].str() != "_")
217
 
            {
218
 
                replacement = _match.atom[2].str();
219
 
                if (_match.atom[2].length() == 1)
220
 
                    extradelims += escape_char(_match.atom[2].str()[0]);
221
 
            }
222
 
        }
223
 
        else
224
 
        {
225
 
            replacement = _match.atom[(!!(l1 < l2)) * 2].str();
226
 
        }
227
 
 
228
 
        mask.replace(_match.start(), _match.length(), replacement);
229
 
        filename.replace(_match.start(), _match.length(), replacement);
230
 
        return "";
231
 
    }
232
 
};
233
 
 
234
 
string H::filename, H::mask;
235
 
 
236
 
pair<string, string> get_simplified_filename_mask(const string &path)
237
 
{
238
 
    H::filename = string_tolower(path_get_filename(path));
239
 
    H::mask = get_filename_mask(path);
240
 
 
241
 
    if (rex.exec(H::mask, "(\\)|\\]|\\*[a-z]{0,3})-[a-z0-9]{3,4}$"))
242
 
        rex.replacef(H::mask, "-[a-z]{3,4}$", H::double_erase, Regexx::global);
243
 
 
244
 
    rex.replacef(H::filename,
245
 
            "[-\\s_\\.]*[\\(\\[][^\\]\\)]{0,60}[\\]\\)]?$",
246
 
            H::double_erase, Regexx::global);
247
 
 
248
 
    do
249
 
    {
250
 
        rex.replacef(H::filename, NUMRE, H::numerals, Regexx::global);
251
 
    } while (rex.matches());
252
 
 
253
 
    rex.replacef(H::filename, "^[-\\s_\\.']+|[-\\s_\\.']+$",
254
 
            H::double_erase, Regexx::global);
255
 
 
256
 
    return pair<string, string>(H::filename, H::mask);
257
 
}
258
 
 
259
 
string album_filter(const string &album)
260
 
{
261
 
    return string_normalize(rex.replace(string_tolower(album),
262
 
            "(lp|ep|cmd|promo|demo|maxi)$", "", Regexx::global));
263
 
}
264
 
 
265
 
string title_filter(const string &title)
266
 
{
267
 
    string normtitle = string_normalize(title);
268
 
    size_t p = title.rfind("- ");
269
 
    if (p == string::npos)
270
 
        return normtitle;
271
 
    return string_normalize(title.substr(p));
272
 
}
273
 
 
274
 
string path_get_dirname(const string &path)
275
 
{
276
 
    size_t last_slash = path.find_last_of("/") + 1;
277
 
    return path.substr(0, last_slash);
278
 
}
279
 
 
280
 
string path_get_filename(const string &path)
281
 
{
282
 
    size_t last_slash = path.find_last_of("/") + 1;
283
 
    size_t last_dot = path.find_last_of(".");
284
 
 
285
 
    if (last_dot == string::npos || last_dot < path.length() - 4)
286
 
        last_dot = path.length();
287
 
 
288
 
    return path.substr(last_slash, last_dot - last_slash);
289
 
}
290
 
 
291
 
string path_get_extension(const string &path)
292
 
{
293
 
    size_t last_dot = path.find_last_of(".");
294
 
 
295
 
    if (last_dot == string::npos)
296
 
        last_dot = path.length();
297
 
    else
298
 
        last_dot++;
299
 
 
300
 
    return path.substr(last_dot);
301
 
}
302
 
 
303
 
string string_delete(const string &haystack, const string &needle)
304
 
{
305
 
    return rex.replace(haystack, needle, "", Regexx::global);
306
 
}