【问题标题】:RegEx to match only a specific column with lookaround正则表达式仅匹配具有环视功能的特定列
【发布时间】:2021-12-04 00:53:47
【问题描述】:

我有一个 .CSV,我正在一个大文件编辑器 (BssEditor) 中处理它:

DOC;NAME;A_TYPE;ADDRESS;NUMBER;COMPLEMENT;NEIGHBORHOOD;CITY;STATE;ZIPCODE
7971530;Obi Wan Kenobi;R;OF THE PITANGUEIRAS;0000731;;MATATU;DUBAI;BA;40255436
7971541;Anakim Skywalker;AV;VISCONDE OF JEQUITINHONHA;0000243;AP 601;GOOD VOYAGE;RECIFE;PE;51021190
7971974;Jabba the Hutt;;DOS ILHEUS;0000118;APT 600;CENTER;FLOWERPOLIS;SC;88010560
7972512;Mando;;JUNDIACANGA;0000037;HOUSE;IPAVA CITY;SAINT PAUL;SP;04950150

列分隔符是 ;,我想匹配 NUMBER 列开头的所有零以替换为空。
例如:0000731731

使用^((.*?;){4})0+ 匹配所有内容并替换为$1 很容易,但使用环视则不然...
我试过这样的正则表达式

/^(?<=.*?;){4}0+/
/(?<=^.*?;.*?;.*?;.*?;)0+/ 

但看起来贪心通配符只适用于前瞻,而不是后瞻。

有办法吗?
并且有办法,在处理数百万条目时是否存在性能问题?

【问题讨论】:

  • 您使用什么语言?有些支持可变长度的lookbehinds,有些则不支持。某些语言不支持任何外观。此外,尚不清楚此处是否适合使用正则表达式。您可能希望使用 CSV 方法来提取字段值。某些语言可以在 CSV 方法中执行您想要的操作。您还可以将 '0000731' 转换为整数 (731),然后将整数转换回字符串 ('731')。
  • 正如我所说的 .csv,我认为应该理解我正在使用一个大文件编辑器... BssEditor 使用带有 MS 正则表达式处理风格的解释。但我在 Notepad++ 上测试它
  • 第五行有 5 个零,您希望它保持原样吗?或者让它改成037

标签: regex regex-lookarounds


【解决方案1】:

只有少数正则表达式引擎(.NET、Python PyPi 模块、较新的 Javascript,如 V8)支持后视中的无限量词,但在使用 boost 的 notepad++ 中不支持。

如果您使用的是 notepad++,则不需要环视或捕获组。您可以重复分号分隔的部分,直到到达数字列并使用\K 清除当前匹配缓冲区。

在替换中使用空字符串。

^(?:[^;\n]*;){4}\K0+
  • ^ 字符串开头
  • (?:[^;\n]*;){4} 重复 4 次匹配除 ; 之外的任何字符或换行符,然后匹配;
  • \K 忘记到目前为止匹配的内容
  • 0+ 匹配一次或多次零

Regex demo

捕获组解决方案似乎是一个不错的解决方案,您可以使用单个捕获组编写它并使用否定字符类而不是 .*? 来防止一些回溯。

^((?:[^;\n]*;){4})0+

在替换使用组 1 中,通常表示为 $\1

Regex demo

【讨论】:

  • 不错。在使用 Regex 的多年中,我不知道 \k。
  • 你为什么要否定[^;\n]?它也适用于^(?:.*?;){4}\K0+。这样看起来更清晰。
  • @Zano 可以,但是.*? 引入了回溯以尽可能少地匹配任何字符。否定字符类匹配除不允许匹配的字符之外的任何字符。例如,您可以在此处查看非贪婪模式 regex101.com/r/lyJ1RK/1 的步数
【解决方案2】:

我不知道 BssEditor,但以下在 Notepad++ 中有效

(?<=;)0+(?=\d+;(?:[^;]*;){4}[^;]*?$)

只有在该行的字符串前面正好有五个分号时才使用正向先行匹配。

在处理数百万个条目时是否存在性能问题?

可能。

【讨论】:

  • 谢谢,它也很好用。如果只有 00000
  • $有什么用?您的代码在 BssEditor 中有效,但没有锚。因为它不擅长处理 EOL。
  • 我看到你在行尾锚定。我可以在 BssEditor 中用 \n 替换它。但是你为什么不一开始就主播呢?
  • @Zano $(或\n)是必需的,否则前面列中的数字可能会匹配,因为行前仍然有 5 个分号。例如,如果没有锚,如果行中前面有 7 个分号,正则表达式将错误地匹配。不需要一开始就锚定。
  • 您好,我想在您的表达式中添加空格,以便删除 [; \d]。所以我做了一系列用零和空格填充的列来测试。我用表达式 (?&lt;=;)[ 0]+(?=(\d+;|;)(?:[^;]*;){5,6}[^;]*?$) 得到了它。但有趣的是,在 Notepad++ 中,其他几列在搜索时会闪烁绿色。它不会选择错误的列,但我担心它会降低性能。你怎么看?
猜你喜欢
  • 1970-01-01
  • 2020-02-20
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多