可以使用Regex进行这种特殊的字符串操作吗?

时间:2008-09-26 10:00:11

标签: c# python regex language-agnostic

我需要在字符串中将字符(例如) x 替换为字符(例如) P ,但前提是它包含在带引号的子字符串中。 一个例子使它更清晰:

axbx'cxdxe'fxgh'ixj'k  -> axbx'cPdPe'fxgh'iPj'k

为简单起见,我们假设引号总是成对出现。

显而易见的方法是一次只处理一个字符串(简单的状态机方法);
但是,我想知道是否可以使用正则表达式一次完成所有处理。

我的目标语言是C#,但我想我的问题与任何有正则表达式内置或库支持的语言有关。

9 个答案:

答案 0 :(得分:9)

我将Greg Hewgill的python代码转换为C#并且它有效!

[Test]
public void ReplaceTextInQuotes()
{
  Assert.AreEqual("axbx'cPdPe'fxgh'iPj'k", 
    Regex.Replace("axbx'cxdxe'fxgh'ixj'k",
      @"x(?=[^']*'([^']|'[^']*')*$)", "P"));
}

那个测试通过了。

答案 1 :(得分:8)

我能用Python做到这一点:

>>> import re
>>> re.sub(r"x(?=[^']*'([^']|'[^']*')*$)", "P", "axbx'cxdxe'fxgh'ixj'k")
"axbx'cPdPe'fxgh'iPj'k"

这样做是使用非捕获匹配(?= ...)来检查字符x是否在带引号的字符串中。它会查找下一个引号之前的一些非引号字符,然后查找单个字符或引用字符组的序列,直到字符串结尾。

这取决于您的假设,即报价始终是平衡的。这也不是很有效。

答案 2 :(得分:2)

诀窍是使用非捕获组来匹配字符串匹配的部分(字符 x ),我们正在搜索。 尝试将字符串匹配到 x 只能找到第一个或最后一个出现,具体取决于是否使用了非贪婪的量词。 这是Greg的想法转移到Tcl,带有评论。

set strIn {axbx'cxdxe'fxgh'ixj'k}
set regex {(?x)                     # enable expanded syntax 
                                    # - allows comments, ignores whitespace
            x                       # the actual match
            (?=                     # non-matching group
                [^']*'              # match to end of current quoted substring
                                    ##
                                    ## assuming quotes are in pairs,
                                    ## make sure we actually were 
                                    ## inside a quoted substring
                                    ## by making sure the rest of the string 
                                    ## is what we expect it to be
                                    ##
                (
                    [^']*           # match any non-quoted substring
                    |               # ...or...
                    '[^']*'         # any quoted substring, including the quotes
                )*                  # any number of times
                $                   # until we run out of string :)
            )                       # end of non-matching group
}

#the same regular expression without the comments
set regexCondensed {(?x)x(?=[^']*'([^']|'[^']*')*$)}

set replRegex {P}
set nMatches [regsub -all -- $regex $strIn $replRegex strOut]
puts "$nMatches replacements. "
if {$nMatches > 0} {
    puts "Original: |$strIn|"
    puts "Result:   |$strOut|"
}
exit

打印:

3 replacements. 
Original: |axbx'cxdxe'fxgh'ixj'k|
Result:   |axbx'cPdPe'fxgh'iPj'k|

答案 3 :(得分:2)

#!/usr/bin/perl -w

use strict;

# Break up the string.
# The spliting uses quotes
# as the delimiter.
# Put every broken substring
# into the @fields array.

my @fields;
while (<>) {
    @fields = split /'/, $_;
}

# For every substring indexed with an odd
# number, search for x and replace it
# with P.

my $count;
my $end = $#fields;
for ($count=0; $count < $end; $count++) {
    if ($count % 2 == 1) {
        $fields[$count] =~ s/a/P/g;
    }    
}

这个大块不会做这个工作吗?

答案 4 :(得分:2)

更通用(且更简单)的解决方案,允许使用非配对引号。

  1. 查找引用字符串
  2. 将'x'替换为字符串

    中的'P'
    #!/usr/bin/env python
    import re
    
    text = "axbx'cxdxe'fxgh'ixj'k"
    
    s = re.sub("'.*?'", lambda m: re.sub("x", "P", m.group(0)), text)
    
    print s == "axbx'cPdPe'fxgh'iPj'k", s
    # ->   True axbx'cPdPe'fxgh'iPj'k
    

答案 5 :(得分:1)

不是普通的正则表达式。正则表达式没有“记忆”,因此无法区分“内部”或“外部”引号。

你需要更强大的东西,例如使用gema它会是直截了当的:

'<repl>'=$0
repl:x=P

答案 6 :(得分:1)

关于平衡文本替换的类似讨论:Can regular expressions be used to match nested patterns?

虽然你可以在Vim中尝试这个,但是只有当字符串在一行上并且只有一对时,它才能正常工作。

:%s:\('[^']*\)x\([^']*'\):\1P\2:gci

如果还有一对甚至是不平衡的,那么它可能会失败。这就是我在c命令中包含ex a.k.a.确认标志的方式。

使用sed可以完成相同操作,无需进行交互 - 或使用awk,因此您可以添加一些互动。

一种可能的解决方案是打破'对上的行,然后你可以使用vim解决方案。

答案 7 :(得分:1)

Pattern:     (?s)\G((?:^[^']*'|(?<=.))(?:'[^']*'|[^'x]+)*+)x
Replacement: \1P
  1. \G - 在前一个匹配或字符串开头处锚定每个匹配。
  2. (?:^[^']*'|(?<=.)) - 如果它位于字符串的开头,则匹配第一个引号。
  3. (?:'[^']*'|[^'x]+)*+ - 匹配任何未加引号的字符块或任何(非引用)字符,最多为“x”。
  4. 通过源字符串进行一次扫描,除了单个字符后视。

答案 8 :(得分:0)

很抱歉打破你的希望,但你需要一个下推式自动机来做到这一点。这里有更多信息: Pushdown Automaton

简而言之,正则表达式,即有限状态机只能读取并且没有内存,而下推自动机具有堆栈和操作功能。

编辑:拼写...

相关问题