-1

我有一个包含多个项目(文本块)的文本文件,如下所示:

SAMPLE
ITEM_ID sample_id_0000028
blah blah
ABCD <--- do NOT remove
blah blah blah
blah blah
blah
SAMPLE_END


SAMPLE
ITEM_ID sample_id_0000033
other text
more text
ABCD <--- Remove this
more text
SAMPLE_END

SAMPLE
ITEM_ID sample_id_00041
ABCD <--- do NOT remove
blah blah blah
blah
SAMPLE_END

我想替换/删除ABCDID 项中出现的实例sample_id_0000033ABCD挑战在于我想不理会文件中的其他实例。此外,和之间的行数因项目ITEM_ID而异,并且可能在指定项目中找不到。ABCDABCD

我必须通过 VBA 中的 vbscript 操作文件。我想我会使用正则表达式来做到这一点,但 VBA 不支持后向的正则表达式。是否有一种模式可用于通过负前瞻或更简单的方式来完成此任务?

我会在定义为的字符串上执行正则表达式textfile.ReadAll,其中textfile是 TextStream。

4

3 回答 3

1

你可以使用这个:

pattern: (ITEM_ID sample_id_0000033\D(?:[^S]|S(?!=AMPLE_END))+?)ABCD
replace: $1

或者更好的是,这个:

pattern: (ITEM_ID sample_id_0000033\D(?:[^\r]+\r\n)+?)ABCD
replace: $1

或更短的 acheong87 示例:

pattern: (sample_id_0000033\D(?:[^\r]+\r\n)+?)ABCD
replace: $1
于 2013-05-02T22:29:08.657 回答
0

考虑以下通用正则表达式和逻辑的 powershell 示例。这不使用任何正则表达式外观,并且将匹配任何blah blah行上的 ABCD。

您应该能够将此概念重写到您的 VBA 逻辑中。

例子

$Matches = @()
$String = 'SAMPLE
ITEM_ID sample_id_0000028
blah blah
ABCD <--- do NOT remove
blah blah blah
blah blah
blah
SAMPLE_END


SAMPLE
ITEM_ID sample_id_0000033
other text
more text
ABCD <--- Remove this
more text
SAMPLE_END

SAMPLE
ITEM_ID sample_id_00041
ABCD <--- do NOT remove
blah blah blah
blah
SAMPLE_END

SAMPLE
ITEM_ID sample_id_0000028
blah blah
ABCD <--- do NOT remove
blah blah blah
blah blah
blah
SAMPLE_END
SAMPLE
ITEM_ID sample_id_0000033
other text
more text
ABCD <--- Remove this
more text
SAMPLE_END
SAMPLE
ITEM_ID sample_id_00041
ABCD <--- do NOT remove
blah blah blah
blah
SAMPLE_END'


 $NewString = $String
([regex]'(sample_id_0000033((.|\n|\r)*?)SAMPLE_END)').matches($String) | foreach {
    write-host  --------------------------------------------
    Write-Host "found at $($_.Groups[1].Index) = '$($_.Groups[1].Value)'"
    Write-Host "found at $($_.Groups[2].Index) = '$($_.Groups[2].Value)'"

    $ThisRecord = $_.Groups[1].Value

    $InnerText = $_.Groups[2].Value
    $NewInnerText = $InnerText -replace "ABCD", "I like kittens"

    $NewRecord = $ThisRecord -replace $InnerText, $NewInnerText

    write-host
    Write-Host NewRecord:
    Write-Host $NewRecord

    $NewString = $NewString -replace $ThisRecord, $NewRecord


    } # next match

产量

请注意,在此示例中,我将<--- Remove this值保留在字符串上,以便更容易识别更改的位置

--------------------------------------------
found at 136 = 'sample_id_0000033
other text
more text
ABCD <--- Remove this
more text
SAMPLE_END'
found at 153 = '
other text
more text
ABCD <--- Remove this
more text
'

NewRecord:
sample_id_0000033
other text
more text
I like kittens <--- Remove this
more text
SAMPLE_END
--------------------------------------------
found at 452 = 'sample_id_0000033
other text
more text
ABCD <--- Remove this
more text
SAMPLE_END'
found at 469 = '
other text
more text
ABCD <--- Remove this
more text
'

NewRecord:
sample_id_0000033
other text
more text
I like kittens <--- Remove this
more text
SAMPLE_END
--------------------------------------------
New String
SAMPLE
ITEM_ID sample_id_0000028
blah blah
ABCD <--- do NOT remove
blah blah blah
blah blah
blah
SAMPLE_END


SAMPLE
ITEM_ID sample_id_0000033
other text
more text
I like kittens <--- Remove this
more text
SAMPLE_END

SAMPLE
ITEM_ID sample_id_00041
ABCD <--- do NOT remove
blah blah blah
blah
SAMPLE_END

SAMPLE
ITEM_ID sample_id_0000028
blah blah
ABCD <--- do NOT remove
blah blah blah
blah blah
blah
SAMPLE_END
SAMPLE
ITEM_ID sample_id_0000033
other text
more text
I like kittens <--- Remove this
more text
SAMPLE_END
SAMPLE
ITEM_ID sample_id_00041
ABCD <--- do NOT remove
blah blah blah
blah
SAMPLE_END

概括

  1. 使用此正则表达式(sample_id_0000033((.|\n|\r)*?)SAMPLE_END)查找以 sample_id_0000033 开头并以下一个 SAMPLE_END 结尾的所有文本块。当然,如果您对记录结束使用不同的分隔符,您也需要在此处包含该分隔符。
  2. 在幕后,Powershell 隐藏了它如何$Matches使用所有找到的子字符串填充数组。然后将它们传递到相当于 $Matches的foreach循环中(在这种情况下)。$_
  3. foreach块内,我们处理每个找到的匹配实例:
    • ABCD用所需的字符串替换已知文本I like kittens并将结果更改存储到$NewInnerText. 我在这里创建了一个新变量,因为$InnerText它不包括打开和关闭字符串,这取决于您的实际值ABCD可能会意外更改结束标签中的文本。
    • 是根据用inside$NewRecord替换的结果创建的$InnerText$NewInnerText$ThisRecord
    • 然后$NewString我们发出替换$ThisRecord$NewRecord
于 2013-05-03T02:01:18.270 回答
0

您需要某种方式来分隔每个“块”,例如,通过每个块之间的空白行。例如,您可以替换

(sample_id_0000033(?:\r|\n|\r\n)(?:.*\S.*(?:\r|\n|\r\n))*)ABCD

$1

这是正在发生的事情。

  1. sample_id_0000033是不言自明的。
  2. 我将(?:\r|\n|\r\n)“任何类型的换行符”写成简写形式,无论是 CR (Mac)、LF (UNIX) 还是 CR/LF (DOS)。速记是(?:\r|\r?\n). 我不写类似[\r\n]+或的原因\s+是我们不想匹配多个换行符
  3. 然后,我们要跳过至少包含一个非空白字符的行,非空行:.*\S.*。再加上任何类型的换行符,当然,紧随其后。请注意,默认情况下,通配符.匹配换行符 - 如果您处于点匹配换行符模式,那么您应该使用而不是.[^\r\n].
  4. 非捕获组(?: ... )是可选的,但很好的做法,因为我们不打算使用这些组。
  5. ABCD如果我们最终遇到一条$1带有ABCD. 如果我们在遇到空行之前没有遇到一行,则匹配失败并且没有任何内容被替换。ABCD
于 2013-05-02T22:01:48.483 回答