我正在开发一个带文章的应用程序(简单的HTML页面),以及一个词汇表术语列表(每个术语可能是一个单词,一个短语,甚至一个句子),并为每个术语创建一个链接认定。问题是,对于包含更多术语的较大文本,需要很长时间。目前我们通过最初显示未标记的文本,在后台处理链接,最后在处理完成时重新加载Web视图来处理此问题。不过,它可能需要一段时间,我们的一些用户对此不满意。
现在,应用程序在条款上使用了一个简单的循环,在HTML中进行替换。基本上是:
for (int i=0; i<terms.count; i++){
NSString *term = [terms objectAtIndex:i];
NSString *replaceString = [NSString stringWithFormat:@"<a href="myUrl:\\%d>%@</a>", i, term];
htmlString = [htmlString stringByReplacingOccurrencesOfString:term
withString:replaceString
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, [htmlString length] )];
}
但是,我们正在处理多种语言,因此每个学期不只有一个替代品,而是20个!那是因为我们必须在开始时处理标点符号(西班牙语中颠倒的问号)和每个术语的结束。我们必须使用适当的超链接替换"term"
,"term."
和"term?"
。
我是否可以使用更有效的方法来标记此HTML?
我需要保留原始术语的索引,以便以后在用户点击链接时检索它。
答案 0 :(得分:3)
您可以按如下方式处理文本:
不是循环翻译词汇,而是将文本拆分为单词并在词汇表中查找每个单词。
创建一些索引,哈希表或字典以使查找更有效。
请勿使用stringByReplacingOccurrencesOfString
。每次调用它都会生成整个文本的副本,并且在autopool耗尽之前不会释放内存。 (有趣的是,你还没有遇到内存问题。)而是使用NSMutableString
实例来附加每个单词(以及它们之间的字符),无论是原始文本还是装饰链接。
答案 1 :(得分:2)
你现在正在做的是:
for each vocabulary word 'term'
search the HTML text for instances of term
replace each instance of term with an appropriate hyperlink
如果你有一个大文本,那么每次搜索都需要更长的时间。此外,每次进行替换时,都必须创建一个包含文本副本的新字符串以进行替换,因为stringByReplacingOccurrencesOfString:withString:options:range:
返回一个新字符串而不是修改现有字符串。乘以N替换。
更好的选择是在字符串中进行单次传递,一次搜索所有术语,并在可变字符串中构建结果输出字符串以避免Shlemiel the Painter-like runtime。
例如,你可以这样使用regular expressions:
// Create a regular expression that is an alternation of all of the vocabulary
// words. You only need to create this once at startup.
NSMutableString *pattern = [[[NSMutableString alloc] init] autorelease];
[pattern appendString:@"\\b("];
BOOL isFirstTerm = YES;
for (NSString *term in vocabularyList)
{
if (!isFirstTerm)
{
[pattern appendString:@"|"];
isFirstTerm = NO;
}
[pattern appendString:term];
}
[pattern appendString:@")\\b"];
// Create regular expression object
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
// Replace vocabulary matches with a hyperlink
NSMutableString *htmlCopy = [[htmlString mutableCopy] autorelease];
[regex replaceMatchesInString:htmlCopy
options:0
range:NSMakeRange(0, [htmlString length])
withTemplate:@"<a href=\"vocab.html?word=\\1\">\\1</a>"];
// Now use htmlCopy
答案 2 :(得分:1)
由于字符串替换功能你的调用是命令N(它扫描替换n个单词)而你正在用m个词汇表术语,你有一个n ^ 2算法。
如果你可以一次性完成,那将是最佳的(在html中命令n - n个单词)。首先展示未被替换的文本的想法仍然是一个好的,除非它对于大型文档来说是不明显的。
如何对词汇单词的哈希集进行扫描,通过html单词扫描(跳过html标记),如果当前扫描的单词在哈希集中,则将其附加到目标缓冲区而不是扫描的单词。这样你就可以在内存中拥有2 X个html内容+ 1个词汇表哈希值。
答案 3 :(得分:1)
有两种方法。
哈希地图 - 如果你的短语的最大长度被限制为例如2,你可以迭代所有单词和双字母(2个单词)并在HashMap中检查它们 - 复杂性是liniar,因为哈希是恒定的时间在理想
自动机理论 您可以将简单的自动机组合为单一的自动机和更快的评估(即动态编程)。例如,我们将“John Smith”|“John Stuard”合并,我们得到John S(mith | tuard)它就是所谓的前缀优化(http://code.google.com/p/graph-expression/wiki/ RegexpOptimization)
此处可以找到更多advenced算法http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm
我更喜欢这种方法,因为没有短语长度的限制,它允许组合复杂的正则表达式。