从文本文件移除停用词后词频统计仍异常的Prolog代码问题
问题分析与解决方案
核心问题1:正则分割逻辑错误,提取内容非目标单词
你使用re_split("\\w+", String, Words)分割文本,但\w+匹配的是单词字符序列,这会导致re_split将单词作为分隔符,返回的Words列表实际是单词之间的非单词内容(如空格、标点、换行),完全搞反了提取单词的逻辑。
正确做法是用\\W+(匹配非单词字符序列)作为分隔符,这样才能把文本分割成单词列表:
re_split("\\W+", String, Words),
核心问题2:过滤谓词参数不匹配,无法识别停用词
exclude(word_to_ignore, Sorted, RelevantWords)中,Sorted的元素是Word - Count格式的二元组(例如"the"-1),但word_to_ignore(Word)仅接受单个单词作为参数,永远无法匹配,导致过滤失效。
修正方法是让word_to_ignore适配二元组结构,提取其中的单词进行检查:
% 过滤待忽略单词的谓词(适配二元组) word_to_ignore(Word - _) :- ignore_words(IgnoreWords), member(Word, IgnoreWords).
额外优化建议
简化小写转换逻辑,跳过空字符串:
修正正则后,Words可能包含空字符串(如文本首尾的非单词字符导致),可以在转小写时直接跳过:lower_case([], []). lower_case([Word|Rest], [Lower|LowerRest]) :- string_length(Word, Len), Len > 0, string_lower(Word, Lower), lower_case(Rest, LowerRest). lower_case([_|Rest], LowerRest) :- lower_case(Rest, LowerRest).调整流程顺序,提升可读性:
先转小写得到纯单词列表,过滤停用词后再生成带计数的二元组,流程更清晰:print_top_words(File, N):- read_file_to_string(File, String, [encoding(utf8)]), re_split("\\W+", String, Words), lower_case(Words, LowerWords), exclude(word_to_ignore_plain, LowerWords, RelevantWords), pairs_keys_values(WordPairs, RelevantWords, [1|_]), sort(1, @=<, WordPairs, Sorted), merge_words(Sorted, Counted), sort(2, @>, Counted, Top_words), writef("Top %w words:\nRank\tCount\tWord\n", [N]), print_top_words(Top_words, N, 1). % 纯单词版本的过滤谓词 word_to_ignore_plain(Word) :- ignore_words(IgnoreWords), member(Word, IgnoreWords).
修正后的完整代码
% 打印高频单词 print_top_words(File, N):- read_file_to_string(File, String, [encoding(utf8)]), re_split("\\W+", String, Words), lower_case(Words, LowerWords), exclude(word_to_ignore_plain, LowerWords, RelevantWords), pairs_keys_values(WordPairs, RelevantWords, [1|_]), sort(1, @=<, WordPairs, Sorted), merge_words(Sorted, Counted), sort(2, @>, Counted, Top_words), writef("Top %w words:\nRank\tCount\tWord\n", [N]), print_top_words(Top_words, N, 1). % 过滤待忽略单词的谓词(纯单词版本) word_to_ignore_plain(Word) :- ignore_words(IgnoreWords), member(Word, IgnoreWords). % 定义待忽略的停用词 ignore_words(['', 'a', 'an', 'the', 'for', 'of', 'and', 'to', 'in', 'is', 'it', 'on', 'that', 'with', 'this', 'you', 'be', 'are', 'at', 'or', 'as', 'if', 'not', 'from']). % 将单词转为小写,跳过空字符串 lower_case([], []). lower_case([Word|Rest], [Lower|LowerRest]) :- string_length(Word, Len), Len > 0, string_lower(Word, Lower), lower_case(Rest, LowerRest). lower_case([_|Rest], LowerRest) :- lower_case(Rest, LowerRest). % 合并相同单词的计数 merge_words([], []):-!. merge_words([Word - C1, Word - C2|Words], Result):- !, C is C1 + C2, merge_words([Word - C|Words], Result). merge_words([W|Words], [W|Rest]):- merge_words(Words, Rest). % 打印前N个高频单词 print_top_words([], _, _):-!. print_top_words(_, 0, _):-!. print_top_words([Word - Count|Rest], N, R):- writef("%w\t%w\t%w\n", [R, Count, Word]), N1 is N - 1, R1 is R + 1, print_top_words(Rest, N1, R1). main:- print_top_words("SuspiciousEmail.txt", 10).
内容的提问来源于stack exchange,提问作者Katie Cook
相关产品推荐
相关产品推荐

