繁体   English   中英

Python re.sub()优化

[英]Python re.sub() optimization

我有一个python列表,每个字符串是以下4个可能的选项之一(当然名称会有所不同):

Mr: Smith\n
Mr: Smith; John\n
Smith\n
Smith; John\n

我希望这些更正为:

Mr,Smith,fname\n
Mr,Smith,John\n
title,Smith,fname\n
title,Smith,John\n

使用4 re.sub()很容易:

with open ("path/to/file",'r') as fileset:
    dataset = fileset.readlines()
for item in dataset:
    dataset = [item.strip() for item in dataset]    #removes some misc. white noise
    item = re.sub((.*):\W(.*);\W,r'\g<1>'+','+r'\g<2>'+',',item)
    item = re.sub((.*);\W(.*),'title,'+r'\g<1>'+','+r'\g<2>',item)
    item = re.sub((.*):\W(.*),r'\g<1>'+','+r'\g<2>'+',fname',item)
    item = re.sub((*.),'title,'+r'\g<1>'+',fname',item)

虽然这对我正在使用的数据集很好,但我希望更有效率。
是否有单一操作可以简化此过程?

请原谅我忘了引用或其他一些; 我现在不在我的工作站,我知道我已经删除了换行符( \\n )。

谢谢,

简要

您可以将其减少到一行,而不是运行两个循环。 改编自如何在Python中迭代文件 (并使用我的代码部分中的代码 ):

f = open("path/to/file",'r')
while True:
    x = f.readline()
    if not x: break
    print re.sub(r, repl, x)

请参阅Python - 如何在Python中逐行使用regexp,以获取其他替代方案。


为了便于查看,我已将文件更改为数组。

请参阅此处使用的正则表达式

^(?:([^:\r\n]+):\W*)?([^;\r\n]+)(?:;\W*(.+))?

注意:你不需要python中的所有内容,为了在regex101上显示它,所以你的正则表达式实际上只是^(?:([^:]+):\\W*)?([^;]+)(?:;\\W*(.+))?

用法

请参阅此处使用的代码

import re

a = [
    "Mr: Smith",
    "Mr: Smith; John",
    "Smith",
    "Smith; John"
]
r = r"^(?:([^:]+):\W*)?([^;]+)(?:;\W*(.+))?"

def repl(m):
    return (m.group(1) or "title" ) + "," + m.group(2) + "," + (m.group(3) or "fname")

for s in a:
    print re.sub(r, repl, s)

说明

  • ^在行的开头断言位置
  • (?:([^:]+):\\W*)? 可选择匹配以下内容
    • ([^:]+)捕获任何字符,除了:一次或多次进入捕获组1
    • :字面意思匹配
    • \\W*匹配任意数量的非单词字符(从OP的原始代码复制,我假设可以使用\\s*代替)
  • ([^;]+)分组除以外的任何字符; 一次或多次进入捕获组2
  • (?:;\\W*(.+))? 可选择匹配以下内容
    • ; 按字面意思匹配
    • \\W*匹配任意数量的非单词字符(从OP的原始代码复制,我假设可以使用\\s*代替)
    • (.+)任何字符捕获一次或多次到捕获组3中

鉴于正则表达式部分的上述解释。 re.sub(r, repl, s)工作原理如下:

  • repl是对repl函数的回调,它返回:
    • group 1如果它捕获任何东西,否则title
    • group 2 (它应该总是设置 - 再次使用OP的逻辑)
    • group 3如果它捕获任何东西, fname否则

恕我直言,RegEx在这里太复杂了,你可以使用经典的字符串函数来分割你的字符串项目 为此,您可以使用partition (或rpartition )。

首先,将您的项目字符串拆分为“记录”,如下所示:

item = "Mr: Smith\n Mr: Smith; John\n Smith\n Smith; John\n"
records = item.splitlines()
# -> ['Mr,Smith,fname', 'Mr,Smith,John', 'title,Smith,fname', 'title,Smith,John']

然后,您可以创建一个简短的函数来规范化每个“记录”。 这是一个例子:

def normalize_record(record):
    # type: (str) -> str
    name, _, fname = record.partition(';')
    title, _, name = name.rpartition(':')
    title = title.strip() or 'title'
    name = name.strip()
    fname = fname.strip() or 'fname'
    return "{0},{1},{2}".format(title, name, fname)

此函数比RegEx集合更容易理解。 而且,在大多数情况下,它更快。

为了更好地集成,您可以定义另一个函数来处理每个项目

def normalize(row):
    records = row.splitlines()
    return "\n".join(normalize_record(record) for record in records) + "\n"

演示:

item = "Mr: Smith\n Mr: Smith; John\n Smith\n Smith; John\n"
item = normalize(item)

你得到:

'Mr,Smith,fname\nMr,Smith,John\ntitle,Smith,fname\ntitle,Smith,John\n'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM