Python 查找文本中单词标记的偏移量
Python find offsets of a word token in a text
我编写了这个函数 findTokenOffset
来查找给定单词在预标记文本中的偏移量(作为间隔单词列表或根据特定标记器)。
重新导入,json
def word_regex_ascii(word):
return r"\b{}\b".format(re.escape(word))
def findTokenOffset(text,tokens):
seen = {} # map if a token has been see already!
items=[] # word tokens
my_regex = word_regex_ascii
# for each token word
for index_word,word in enumerate(tokens):
r = re.compile(my_regex(word), flags=re.I | re.X | re.UNICODE)
item = {}
# for each matched token in sentence
for m in r.finditer(text):
token=m.group()
characterOffsetBegin=m.start()
characterOffsetEnd=characterOffsetBegin+len(m.group()) - 1 # LP: star from 0
found=-1
if word in seen:
found=seen[word]
if characterOffsetBegin > found:
# store last word has been seen
seen[word] = characterOffsetEnd
item['index']=index_word+1 #// word index starts from 1
item['word']=token
item['characterOffsetBegin'] = characterOffsetBegin
item['characterOffsetEnd'] = characterOffsetEnd
items.append(item)
break
return items
当标记是像
这样的单个单词时,此代码可以正常工作
text = "George Washington came to Washington"
tokens = text.split()
offsets = findTokenOffset(text,tokens)
print(json.dumps(offsets, indent=2))
但是,应该有像这里这样的多代币方式的代币:
text = "George Washington came to Washington"
tokens = ["George Washington", "Washington"]
offsets = findTokenOffset(text,tokens)
print(json.dumps(offsets, indent=2))
由于在不同标记中重复单词,偏移量无法正常工作:
[
{
"index": 1,
"word": "George Washington",
"characterOffsetBegin": 0,
"characterOffsetEnd": 16
},
{
"index": 2,
"word": "Washington",
"characterOffsetBegin": 7,
"characterOffsetEnd": 16
}
]
How to add support to multi-token and overlapped token regex matching(感谢评论中对这个确切问题名称的建议)?
如果您想查找 Washington,而不是 George Washington,您可以从初始字符串中删除找到的句子。因此,您可以按单词数量对 'tokens' 进行排序。这让你有机会先浏览句子,然后浏览单词。
如果不需要在结果输出中搜索phrase/word索引信息,可以使用以下方式:
import re,json
def findTokenOffset(text, pattern):
items = []
for m in pattern.finditer(text):
item = {}
item['word']=m.group()
item['characterOffsetBegin'] = m.start()
item['characterOffsetEnd'] = m.end()
items.append(item)
return items
text = "George Washington came to Washington Washington.com"
tokens = ["George Washington", "Washington"]
pattern = re.compile(fr'(?<!\w)(?:{"|".join(sorted(map(re.escape, tokens), key=len, reverse=True))})(?!\w)(?!\.\b)', re.I )
offsets = findTokenOffset(text,pattern)
print(json.dumps(offsets, indent=2))
Python demo的输出:
[
{
"word": "George Washington",
"characterOffsetBegin": 0,
"characterOffsetEnd": 17
},
{
"word": "Washington",
"characterOffsetBegin": 26,
"characterOffsetEnd": 36
}
]
主要部分是 pattern = re.compile(fr'(?<!\w)(?:{"|".join(sorted(map(re.escape, tokens), key=len, reverse=True))})\b(?!\.\b)', re.I )
,它执行以下操作:
map(re.escape, tokens)
- 转义 tokens
字符串中的特殊字符
sorted(..., key=len, reverse=True)
- 按长度降序对转义 tokens
中的项目进行排序(以便 Washigton Post
可以早于 Washington
匹配)
"|".join(...)
- 创建了 tokens
、token1|token2|etc
的交替列表
(?<!\w)(?:...)(?!\w)(?!\.\b)
- 是将 tokens
中的所有选项作为整个单词匹配的最终模式。 (?<!\w)
和 (?!\w)
用于启用单词边界检测,即使 tokens
start/end 带有特殊字符。
关于单词边界的注意事项
您应该检查您的 令牌边界 要求。我添加了 (?!\.\b)
因为你提到 Washington
不应该在 Washington.com
中匹配,所以我推断当它紧跟 .
和一个词时想要使任何词匹配失败边界。还有很多其他可能的解决方案,主要的解决方案是 空白边界 、(?<!\S)
和 (?!\S)
.
此外,参见 。
我编写了这个函数 findTokenOffset
来查找给定单词在预标记文本中的偏移量(作为间隔单词列表或根据特定标记器)。
重新导入,json
def word_regex_ascii(word):
return r"\b{}\b".format(re.escape(word))
def findTokenOffset(text,tokens):
seen = {} # map if a token has been see already!
items=[] # word tokens
my_regex = word_regex_ascii
# for each token word
for index_word,word in enumerate(tokens):
r = re.compile(my_regex(word), flags=re.I | re.X | re.UNICODE)
item = {}
# for each matched token in sentence
for m in r.finditer(text):
token=m.group()
characterOffsetBegin=m.start()
characterOffsetEnd=characterOffsetBegin+len(m.group()) - 1 # LP: star from 0
found=-1
if word in seen:
found=seen[word]
if characterOffsetBegin > found:
# store last word has been seen
seen[word] = characterOffsetEnd
item['index']=index_word+1 #// word index starts from 1
item['word']=token
item['characterOffsetBegin'] = characterOffsetBegin
item['characterOffsetEnd'] = characterOffsetEnd
items.append(item)
break
return items
当标记是像
这样的单个单词时,此代码可以正常工作text = "George Washington came to Washington"
tokens = text.split()
offsets = findTokenOffset(text,tokens)
print(json.dumps(offsets, indent=2))
但是,应该有像这里这样的多代币方式的代币:
text = "George Washington came to Washington"
tokens = ["George Washington", "Washington"]
offsets = findTokenOffset(text,tokens)
print(json.dumps(offsets, indent=2))
由于在不同标记中重复单词,偏移量无法正常工作:
[
{
"index": 1,
"word": "George Washington",
"characterOffsetBegin": 0,
"characterOffsetEnd": 16
},
{
"index": 2,
"word": "Washington",
"characterOffsetBegin": 7,
"characterOffsetEnd": 16
}
]
How to add support to multi-token and overlapped token regex matching(感谢评论中对这个确切问题名称的建议)?
如果您想查找 Washington,而不是 George Washington,您可以从初始字符串中删除找到的句子。因此,您可以按单词数量对 'tokens' 进行排序。这让你有机会先浏览句子,然后浏览单词。
如果不需要在结果输出中搜索phrase/word索引信息,可以使用以下方式:
import re,json
def findTokenOffset(text, pattern):
items = []
for m in pattern.finditer(text):
item = {}
item['word']=m.group()
item['characterOffsetBegin'] = m.start()
item['characterOffsetEnd'] = m.end()
items.append(item)
return items
text = "George Washington came to Washington Washington.com"
tokens = ["George Washington", "Washington"]
pattern = re.compile(fr'(?<!\w)(?:{"|".join(sorted(map(re.escape, tokens), key=len, reverse=True))})(?!\w)(?!\.\b)', re.I )
offsets = findTokenOffset(text,pattern)
print(json.dumps(offsets, indent=2))
Python demo的输出:
[
{
"word": "George Washington",
"characterOffsetBegin": 0,
"characterOffsetEnd": 17
},
{
"word": "Washington",
"characterOffsetBegin": 26,
"characterOffsetEnd": 36
}
]
主要部分是 pattern = re.compile(fr'(?<!\w)(?:{"|".join(sorted(map(re.escape, tokens), key=len, reverse=True))})\b(?!\.\b)', re.I )
,它执行以下操作:
map(re.escape, tokens)
- 转义tokens
字符串中的特殊字符sorted(..., key=len, reverse=True)
- 按长度降序对转义tokens
中的项目进行排序(以便Washigton Post
可以早于Washington
匹配)"|".join(...)
- 创建了tokens
、token1|token2|etc
的交替列表
(?<!\w)(?:...)(?!\w)(?!\.\b)
- 是将tokens
中的所有选项作为整个单词匹配的最终模式。(?<!\w)
和(?!\w)
用于启用单词边界检测,即使tokens
start/end 带有特殊字符。
关于单词边界的注意事项
您应该检查您的 令牌边界 要求。我添加了 (?!\.\b)
因为你提到 Washington
不应该在 Washington.com
中匹配,所以我推断当它紧跟 .
和一个词时想要使任何词匹配失败边界。还有很多其他可能的解决方案,主要的解决方案是 空白边界 、(?<!\S)
和 (?!\S)
.
此外,参见