如何将字符串按 4 分组?

Posted

技术标签:

【中文标题】如何将字符串按 4 分组?【英文标题】:How to group string of characters by 4? 【发布时间】:2017-04-14 17:13:48 【问题描述】:

我有字符串1234567890,我想将其格式化为1234 5678 90

我写了这个正则表达式:

$str =~ s/(.4)/$1 /g;

但是对于这种情况12345678 这不起作用。最后我得到了多余的空格:

>>1234 5678 <<

我尝试用前瞻重写正则表达式:

s/((?:.4)?=.)/$1 /g;

如何重写正则表达式来解决这种情况?

【问题讨论】:

你可以写$str =~ s/.4\K(?!$))/ /g;,但你也可以选择结果。 您现在已删除的答案的介绍段落,其中您说“我在写问题时注意到错误”听起来您在措辞时犯了错误,这就是原因建议您改为更新您的问题。现在看,我意识到这是试图指出 s/((?:.4)?=.)/$1 /g; 的具体问题......对不起。 Can I use unpack to split a string into characters in Perl?的可能重复 【参考方案1】:

只需使用unpack

use strict;
use warnings 'all';

for ( qw/ 12345678 1234567890 / ) 
    printf ">>%s<<\n", join ' ', unpack '(A4)*';

输出

>>1234 5678<<
>>1234 5678 90<<

【讨论】:

【参考方案2】:

上下文是你的朋友:

join(' ', $str =~ /(.1,4)/g)

在列表上下文中,匹配将匹配所有四个字符块(以及任何比字符串末尾更短的内容——多亏了贪婪)。 join 将确保块用空格分隔,并且末尾没有尾随空格。

如果$str 很大并且临时列表过多地增加了内存占用,那么您可能只想执行s///g 并去除尾随空格。

我的偏好是在正则表达式中使用最简单的模式。另外,我没有测量过,但是对于长字符串,单个chop 可能比s///g 中的条件模式便宜:

$ echo $'12345678\n123456789' | perl -lnE 's/(.1,4)/$1 /g; chop; say ">>$_<<"'
>>1234 5678<<
>>1234 5678 9<<

【讨论】:

这很有趣。谢谢 我使用前瞻来防止尾随空格【参考方案3】:

您的语法几乎是正确的。您不仅需要?=.,还需要(?=.)(括号是前瞻语法的一部分)。所以:

s/((?:.4)(?=.))/$1 /g

但你不需要非捕获分组:

s/(.4(?=.))/$1 /g

而且我认为如果捕获不包括前瞻则更清楚:

s/(.4)(?=.)/$1 /g

根据您的示例数据,非词边界断言也有效:

s/(.4)\B/$1 /g

或者使用\K自动保留匹配的部分:

s/.4\B\K/ /g

【讨论】:

奇怪,但我自己使用s/(.4(?=.))/$1 /g 的答案已被版主删除( @EugenKonkov 对不起,我的错。它被标记为“必须对帖子进行编辑”,我阅读了第一句话,它看起来像是对问题的更正,因此我将其删除。 (看惯了不好的帖子,每天大概2500个flag,所以我的眼睛骗了我)。再次抱歉。 :(【参考方案4】:

要修复我应该写的正则表达式:

$str =~ s/(.4(?=.))/$1 /g;

我应该在?=. 周围加上括号。没有它们?=. 被视为非贪婪匹配,然后是=.

所以我们匹配四个字符并在它们后面附加空格。然后我向前看,仍然有字符。例如,正则表达式将不匹配字符串1234

【讨论】:

【参考方案5】:

只需向前看,您至少还剩一个字符:

$ echo $'12345678\n123456789' | perl -lnE 's/.4\K(?=.1)/ /g; say ">>$_<<"'
>>1234 5678<<
>>1234 5678 9<<

【讨论】:

以上是关于如何将字符串按 4 分组?的主要内容,如果未能解决你的问题,请参考以下文章

如何按前缀对字符串进行分组

如何按第一个字符串对字符串对的向量进行分组?

Pandas groupby:如何按字符串的指定部分分组

Python:如何按对象的特征或属性对对象列表进行分组? [复制]

如何将连接值分组并聚合为字符串[重复]

如何使用 python itertools.groupby() 按字符串的第一个字符对字符串列表进行分组?