gpt4 book ai didi

perl - 是否可以修改单词字符类或\b 边界以排除下划线字符?

转载 作者:行者123 更新时间:2023-12-03 23:02:33 26 4
gpt4 key购买 nike

我需要替换一个非常大的预定义模式列表。
这些模式只能包含 [a-zA-Z] 字符,不包括下划线。
这些模式可能以不同的形式出现:作为一个完整的单词或单词前面和/或后面跟一个 undescore char '_'
示例:我想用 BAR 替换 FOO
我使用以下 4 个说明

$ cat > /tmp/try.pl
s/\bFOO\b/BAR/g;s/\bFOO_/BAR_/g;s/_FOO\b/_BAR/g;s/_FOO_/_BAR_/g;
$ perl -p /tmp/try.pl
FOO aaa_FOO FOO_bbb FOO.txt a-FOO-b.txt aaa_FOO_bbb dontchange_FOOQUX_dontchange
BAR aaa_BAR BAR_bbb BAR.txt a-BAR-b.txt aaa_BAR_bbb dontchange_FOOQUX_dontchange
它正是我想要的。但是有数千个单词需要时间。
如果我可以从单词字符类中排除下划线,我想我只能使用一条指令:
s/\bFOO\b/BAR/g.
那么有没有办法修改 perl 世界字符类或/b 边界定义以排除下划线字符?

最佳答案

更新
需要澄清的是,要替换的单词是给定列表中的文字字符串(无需匹配 [a-zA-Z])——然后使用由这些单词构建的交替。† 此外,这些单词中的每一个都需要替换为同样预定义的,给定,模式。为此使用哈希。
我认为一个词不能被除 _ 之外的任何东西包围。或字边界,在任一侧。为此可以使用 lookarounds
一个测试程序

use warnings;
use strict;
use feature 'say';

my @words_to_replace = qw(one ones thing nothing clean);
my %replacement = map { $_ => 'NEW.'.$_ } @words_to_replace;

my $re_word = join '|', @words_to_replace; # no quotemeta; only [a-zA-Z]

my @test = qw(noone ones_ athing _thing nothing. _nothing_ clean);

for (@test) {
printf "For %-12s: ", "|$_|";

if ( s{ (?<! [^_\W]) ($re_word) (?! [^_\W]) }{$replacement{$1}}x ) {
say "mathced |$1|, now have |$_|";
}
else { say '' }
}
我通过附加 NEW. 来替换每个单词到它。按预期打印。
环顾四周指定单词不能被除 _ 以外的任何东西包围。或 \W (字符字边界)。那里令人讨厌的三重否定(不是任何非单词边界字符)也是一种在环视中解释零宽度 anchor 的方法。

† 如果获得的模式长于大约 32k 左右的字符,则用(“数千”个)单词构建的交替对于正则表达式来说可能是一个问题。如果您的列表确实很长,以至于 $re_word的长度超过这个数字,也许最​​经济的方法是将列表分成多个足够小的列表,并为每个列表执行上述操作。 (尝试一次匹配和替换一个单词会慢得多。)

原回复 (相信我们需要匹配 [a-zA-Z],只有可能的 _ 左右)
一种方法是使用 POSIX character classes ,其中 [[:alpha:]]匹配 [a-zA-Z]我不清楚通用词的替代品是什么,但是一旦给出
s/([[:alpha:]]+)/$replacement/;
另一种方法是按照你喜欢的方式形成一个模式并使用它
my $re_char = qr/[a-zA-Z]/;

s/($re_char+)/$replacement/;
请说明该替换应该如何工作(除了 foo-bar 语言)。
如果替换本身无关紧要,但仅当匹配的单词可能在两侧仅被 _ 包围时才需要进行替换。那么可以使用 lookarounds排除除 _ 以外的任何字符
m/(?<! [^_] )( [[:alpha:]]+ ) (?! [^_]) /x;
( 编辑— 要添加词边界,请改用 [^_\W]。参见第一部分)
一个测试程序
use warnings;
use strict;
use feature 'say';

my @words = qw(_before _. after_ _both_ none .ahem nah/);

for (@words) {
printf "%-8s:\t", $_;
if ( m/(?<! [^_] )( [[:alpha:]]+ ) (?! [^_]) /x ) {
say $1;
}
else { say "... no match" }
}
这匹配单词( [a-zA-Z] )在两侧或两侧带有下划线,或者它们周围没有任何东西,但不匹配带有其他字符的单词( ./ )。
( 编辑— 要允许词边界与 _ 一起使用 [^_\W] 。参见第一部分)

关于perl - 是否可以修改单词字符类或\b 边界以排除下划线字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64685994/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com