使用正则表达式或常规Python替换字符串?

使用正则表达式或常规Python替换字符串?,python,regex,python-3.x,pandas,csv,Python,Regex,Python 3.x,Pandas,Csv,我有一个字符串列表,如下所示 orig = ["a1 2.3 ABC 4 DEFG 567 b890", "a2 3.0 HI 4 5 JKL 67 c65", "b1 1.2 MNOP 3 45 67 89 QR 987 d64 e112"] 这里的上下文是这是一个CSV文件,省略了某些列。我认为读者无法处理这些案件。现在的想法是为缺少的值注入na,因此输出变为 corr = ["a1 2.3 ABC 4

我有一个字符串列表,如下所示

orig = ["a1  2.3  ABC  4  DEFG  567  b890",
        "a2  3.0  HI  4  5  JKL  67  c65",
        "b1  1.2  MNOP  3  45  67  89  QR  987  d64  e112"]
这里的上下文是这是一个CSV文件,省略了某些列。我认为读者无法处理这些案件。现在的想法是为缺少的值注入
na
,因此输出变为

corr = ["a1  2.3  ABC  4  na  na  na  DEFG  567  b890",
        "a2  3.0  HI  4  5  na  na  JKL  67  c65",
        "b1  1.2  MNOP  3  45  67  89  QR  987  d64  e112"]
将第二列与以后导入到pandas中时大写的单词对齐

结构如下:列之间的分隔符是两个或多个空格,两个大写列之间的分隔符必须是四个值。在原始文件中,始终只有两个大写列,它们之间至少有一个和最多四个数字,并且这些大写字之间只有数字值。
我可以毫无问题地用原生Python编写脚本,因此请不要对此提出任何建议。但我想,这可能是regex的一个例子。作为一名regex初学者,我只使用

for line in orig:
    a = re.findall("([A-Z]+[\s\d]+[A-Z]+)", line))
    print(a)
>>>'ABC  4  DEFG' #etc pp
现在在正则表达式中是否有一种简单的方法来确定大写单词之间有多少个数字,并插入'na'值,使其始终有四个值在两者之间?还是应该用本机Python来实现


当然,如果有一种方法可以用熊猫csv阅读器实现这一点,那就更好了。但是我研究了一下,没有发现任何有用的东西。

基于完整的熊猫方法split和concat可能会有帮助,即

ndf = pd.Series(orig).str.split(expand=True)

#   0    1     2  3     4    5     6     7     8     9     10
#0  a1  2.3   ABC  4  DEFG  567  b890  None  None  None  None
#1  a2  3.0    HI  4     5  JKL    67   c65  None  None  None
#2  b1  1.2  MNOP  3    45   67    89    QR   987   d64  e112

df = pd.concat([ndf.iloc[:,:4], ndf.iloc[:,4:].apply(sorted,key=pd.notnull,axis=1)],1)

df.astype(str).apply(' '.join,axis=1).tolist()

['a1 2.3 ABC 4 None None None None DEFG 567 b890',
 'a2 3.0 HI 4 None None None 5 JKL 67 c65',
 'b1 1.2 MNOP 3 45 67 89 QR 987 d64 e112']

尽管大家一致认为regex并不是这种动态字符串替换的最佳工具,但我发现
re
模块在这种情况下使用起来非常方便。捕获模式基于Jon Clements的评论

import re

orig = ["a1  2.3  ABC  4  DEFG  567  b890",
        "a2  3.0  HI  4  5  JKL  67  c65",
        "b1  1.2  MNOP  3  45  67  89  QR  987  d64  e112"]

corr = []

for item in orig:
    #capture group starting with first capitalised word and stopping before the second
    col_betw = re.search("\s{2,}([A-Z]+.*)\s{2,}[A-Z]+\s{2,}", item).group(1)
    #determine, how many elements we have in this segment
    nr_col_betw = len(re.split(r"\s{2,}", col_betw))
    #substitute, if not enough numbers
    if nr_col_betw <= 4:
        #fill with NA, which is interpreted by pandas csv reader as NaN
        subst = col_betw + "   NA" * (5 - nr_col_betw) 
        item = item.replace(col_betw, subst, 1)
    corr.append(item)
重新导入
orig=[“a1 2.3 ABC 4 DEFG 567 b890”,
“a2 3.0 HI 4 5 JKL 67 c65”,
“b1 1.2 MNOP 3 45 67 89 QR 987 d64 e112”]
corr=[]
对于原始版本中的项目:
#捕获从第一个大写单词开始并在第二个大写单词之前停止的组
col_betw=re.search(“\s{2,}([A-Z]+.*)\s{2,}[A-Z]+\s{2,}”,项)。组(1)
#确定我们在该细分市场中拥有多少元素
nr_col_betw=len(关于分裂(r“\s{2,}”,col_betw))
#如果没有足够的数字,则替换

如果nr_col__betw使用简单的python,那么使用regex就不容易了——你需要做一些回溯和分组的工作,也许在替换之前插入假人——如果可能的话,我对此表示怀疑。这里的regex是错误的工具。在阅读了re.module手册和这里的regex问题之后,我也有这样的印象。但我经常感到惊讶,人们会怎么做,所以我想我会问。如果大写单词之间已经有超过4个数字,或者只是一个“ABC DEF GHI JKL MNO”文本,会发生什么?或者如果数字和代码的组合不是大写字母之间的大写字母?除了大写字母分隔符之间应该有“4个单词”之外,还有其他标准吗?@Piinthesky好的-谢谢。因此,如果您不反对使用
re.findall
识别字符串之间的部分,您可以捕获一些组,并在
re.sub
中使用可调用的替换函数?在我的脑海里,我刚刚尝试过:
re.sub(r'\s{2,}([A-Z]+)\s{2,}(.*)\s{2,}([A-Z]+)\b',lambda m:''。join((m.group(1),'na'*4,m.group(3)),orig[1])
-这需要努力,但可能是有用的东西…@Piinthesky总是试图帮助人们学习。。。你有没有一个我可以毫无问题地用原生Python编写脚本的例子?在这一点上,我认为您实际上已经可以使用其中的一些,只需让regex处理调用replace的操作。看起来,您的代码将第一个数字和第二个数字之间的列填充为无值,因此所有行都具有相同的长度。不幸的是,第二个大写列之后的行具有不同的长度,因此这不是所需的输出。但我想我会跟随你的脚步,试着在熊猫身上做到这一点。谢谢你的建议。