基于规则的分词

发布于:2025-03-06 ⋅ 阅读:(42) ⋅ 点赞:(0)

基于规则的分词

基于规则或词典的分词方法是一种较为机械的分词方法,其基本思想如下。

  • 将待分词语句中的字符串和词典逐个匹配。
  • 找到匹配的字符串则切分,不匹配则减去边缘的某些字符。
  • 从头再次匹配,直至匹配完毕或者没有找到词典的字符串而结束。

基于规则分词主要方法如下。

  • 正向最大匹配法(Maximum Match Method,MM法)。
  • 逆向最大匹配法(Reverse Maximum Match Method,RMM法)。
  • 双向最大匹配法(Bi-direction Matching Method,BMM法)。
def precompute_max_length(dictionary):
  """
  计算词典中最大长度词的长度
  :param dictionary: 词典
  :return: 词典中最大长度词的长度
  """
  return max(len(word) for word in dictionary) if dictionary else 0


def forward_segmentation(text, dictionary):
  """
  正向最大匹配
  :param text: 文本字符串
  :param dictionary: 词典
  :return: 将文本字符串中切词后的数组
  """
  result = []
  i = 0
  max_len = precompute_max_length(dictionary)
  while i < len(text):
    found_word = ''
    # 尝试最长可能的词长
    max_possible = min(max_len, len(text) - i)
    for l in range(max_possible, 0, -1):
      candidate = text[i:i + l]
      if candidate in dictionary:
        found_word = candidate
        break
    if found_word:
      result.append(found_word)
      i += len(found_word)
    else:
      # 没有找到任何词,添加单个字符作为词汇
      result.append(text[i])
      i += 1
  return result


def backward_segmentation(text, dictionary):
  """
 逆向最大匹配
 :param text: 文本字符串
 :param dictionary: 词典
 :return: 将文本字符串中切词后的数组
 """
  result = []
  i = len(text)
  max_len = precompute_max_length(dictionary)
  while i > 0:
    found_word = ''
    # 尝试最长可能的词长,从i处往回找
    max_possible = min(max_len, i)
    for l in range(max_possible, 0, -1):
      candidate = text[i - l:i]
      if candidate in dictionary:
        found_word = candidate
        break
    if found_word:
      result.insert(0, found_word)
      i -= len(found_word)
    else:
      # 没有找到任何词,添加最后一个字符作为词汇
      result.insert(0, text[i - 1])
      i -= 1
  return result


def bidirectional_segmentation(text, dictionary):
  """
双向最大匹配
:param text: 文本字符串
:param dictionary: 词典
:return: 将文本字符串中切词后的数组
"""
  result = []
  i = 0
  n = len(text)
  max_len = precompute_max_length(dictionary)
  while i < n:
    # 正向扫描查找词
    forward_word = ''
    max_possible_forward = min(max_len, n - i)
    for l in range(max_possible_forward, 0, -1):
      candidate = text[i:i + l]
      if candidate in dictionary:
        forward_word = candidate
        break
    # 反向扫描查找词
    backward_word = ''
    max_possible_backward = min(max_len, i)
    for l in range(max_possible_backward, 0, -1):
      candidate = text[i - l:i]
      if candidate in dictionary:
        backward_word = candidate
        break
    # 判断选择哪个词,如果长度相同则优先正向词?
    if len(forward_word) >= len(backward_word):
      result.append(forward_word)
      i += len(forward_word)
    else:
      result.append(backward_word)
      i -= len(backward_word)
  return result

# 定义词典
word_set = {"中", "华", "民", "共和", "国", "人民", "共和国"}

# 定义文本字符串
text = "中华人民共和国"

# 正向分词
forward_result = forward_segmentation(text, word_set)
print("正向分词结果:", forward_result)

# 逆向分词
backward_result = backward_segmentation(text, word_set)
print("逆向分词结果:", backward_result)

# 双向分词
bidirectional_result = bidirectional_segmentation(text, word_set)
print("双向分词结果:", bidirectional_result)
正向分词结果: ['中', '华', '人民', '共和国']
逆向分词结果: ['中', '华', '人民', '共和国']
双向分词结果: ['中', '华', '人民', '共和国']

以下是代码的详细注释,解释了每个函数的功能和实现逻辑:

  1. precompute_max_length(dictionary)
    计算词典中最长单词的长度。
    如果词典为空,则返回0。
def precompute_max_length(dictionary):
    # 如果词典不为空,返回词典中最长单词的长度
    return max(len(word) for word in dictionary) if dictionary else 0
  1. forward_segmentation(text, dictionary)
    正向最大匹配分词算法。
    从左到右扫描文本,每次尝试匹配最长的单词。
def forward_segmentation(text, dictionary):
    result = []  # 存储分词结果
    i = 0  # 当前扫描位置
    max_len = precompute_max_length(dictionary)  # 获取词典中最长单词的长度

    while i < len(text):  # 遍历文本
        found_word = ''  # 用于存储找到的单词
        # 计算当前扫描位置的最大可能匹配长度
        max_possible = min(max_len, len(text) - i)
        for l in range(max_possible, 0, -1):  # 从最大可能长度开始递减
            candidate = text[i:i+l]  # 提取当前候选单词
            if candidate in dictionary:  # 如果候选单词在词典中
                found_word = candidate  # 找到匹配单词
                break
        if found_word:  # 如果找到匹配单词
            result.append(found_word)  # 将单词加入结果
            i += len(found_word)  # 更新扫描位置
        else:  # 如果没有找到匹配单词
            result.append(text[i])  # 将当前字符作为单字加入结果
            i += 1  # 更新扫描位置
    return result  # 返回分词结果
  1. backward_segmentation(text, dictionary)
    逆向最大匹配分词算法。
    从右到左扫描文本,每次尝试匹配最长的单词。
def backward_segmentation(text, dictionary):
    result = []  # 存储分词结果
    i = len(text)  # 当前扫描位置(从文本末尾开始)
    max_len = precompute_max_length(dictionary)  # 获取词典中最长单词的长度

    while i > 0:  # 遍历文本
        found_word = ''  # 用于存储找到的单词
        # 计算当前扫描位置的最大可能匹配长度
        max_possible = min(max_len, i)
        for l in range(max_possible, 0, -1):  # 从最大可能长度开始递减
            candidate = text[i-l:i]  # 提取当前候选单词
            if candidate in dictionary:  # 如果候选单词在词典中
                found_word = candidate  # 找到匹配单词
                break
        if found_word:  # 如果找到匹配单词
            result.insert(0, found_word)  # 将单词插入结果列表的开头
            i -= len(found_word)  # 更新扫描位置
        else:  # 如果没有找到匹配单词
            result.insert(0, text[i-1])  # 将当前字符作为单字插入结果列表的开头
            i -= 1  # 更新扫描位置
    return result  # 返回分词结果
  1. bidirectional_segmentation(text, dictionary)
    双向最大匹配分词算法。
    结合正向和逆向最大匹配算法,选择匹配长度更长的单词。
def bidirectional_segmentation(text, dictionary):
    result = []  # 存储分词结果
    i = 0  # 当前扫描位置
    n = len(text)  # 文本长度
    max_len = precompute_max_length(dictionary)  # 获取词典中最长单词的长度

    while i < n:  # 遍历文本
        # 正向扫描查找词
        forward_word = ''  # 存储正向匹配的单词
        max_possible_forward = min(max_len, n - i)  # 计算正向扫描的最大可能匹配长度
        for l in range(max_possible_forward, 0, -1):  # 从最大可能长度开始递减
            candidate = text[i:i+l]  # 提取当前候选单词
            if candidate in dictionary:  # 如果候选单词在词典中
                forward_word = candidate  # 找到匹配单词
                break

        # 反向扫描查找词
        backward_word = ''  # 存储逆向匹配的单词
        max_possible_backward = min(max_len, i)  # 计算逆向扫描的最大可能匹配长度
        for l in range(max_possible_backward, 0, -1):  # 从最大可能长度开始递减
            candidate = text[i-l:i]  # 提取当前候选单词
            if candidate in dictionary:  # 如果候选单词在词典中
                backward_word = candidate  # 找到匹配单词
                break

        # 判断选择哪个词
        if len(forward_word) >= len(backward_word):  # 如果正向匹配的单词长度大于等于逆向匹配的单词
            result.append(forward_word)  # 选择正向匹配的单词
            i += len(forward_word)  # 更新扫描位置
        else:  # 否则选择逆向匹配的单词
            result.append(backward_word)  # 选择逆向匹配的单词
            i -= len(backward_word)  # 更新扫描位置
    return result  # 返回分词结果

总结

  • precompute_max_length:计算词典中最长单词的长度,用于优化分词过程中的最大匹配长度。

  • forward_segmentation:正向最大匹配分词算法,从左到右扫描文本,优先匹配最长的单词。

  • backward_segmentation:逆向最大匹配分词算法,从右到左扫描文本,优先匹配最长的单词。

  • bidirectional_segmentation:双向最大匹配分词算法,结合正向和逆向匹配,选择匹配长度更长的单词,以提高分词的准确性。


网站公告

今日签到

点亮在社区的每一天
去签到