14

试图转身

a: 1, 2, 3
a: a, b, v
b: 5, 6, 7
b: 10, 1543, 1345
b: e, fe, sdf
cd: asdf, asdfas dfasdfa,asdfasdfa,afdsfa sdf
e1: asdfas, dafasd, adsf, asdfasd
e1: 1, 3, 2
e1: 9, 8, 7, 6

进入

a: 1, 2, 3
   a, b, v
b: 5, 6, 7
   10, 1543, 1345
   e, fe, sdf
cd: asdf, asdfas dfasdfa,asdfasdfa,afdsfa sdf
e1: asdfas, dafasd, adsf, asdfasd
    1, 3, 2
    9, 8, 7, 6

因此,行已排序。如果连续的行以相同的字符序列开始,直到/包括一些分隔符(这里是冒号(以及它后面的空格)),则只应保留第一个实例 - 所有行的其余部分也应保留。以相同的字符序列开头的行可能多达十几行(半行)。输入包含大约 4,500 行...</p>

在 TextWrangler 中尝试过。

虽然搜索模式

^([[:alnum:]]+): (.+)\r((\1:) (.+)\r)*

匹配正确,既不替换

\1:\t\2\r\t\3\r

也不

\1:\t\2\r\t\4\r

让我接近我正在寻找的任何地方。

搜索模式

^(.+): (.+)\r((?<=\1:) (.+)\r)*

由于后视不是固定长度而被拒绝。- 不确定,但无论如何它都会朝着正确的方向发展。

查看 如何合并文本文件中以相同项目开头的行, 我想知道是否有一个优雅的(比如:一种搜索模式、一种替换、运行一次)解决方案。

另一方面,我可能只是无法提出正确的问题来搜索网络。如果您知道得更好,请指出我正确的方向。

保持其余行对齐当然是锦上添花……</p>

感谢您的时间。

4

6 回答 6

6

作为可变长度lookbehind的解决方法:PCRE允许可变长度的替代方案

PCRE 不完全兼容 Perl。虽然 Perl 要求后向内的备选方案具有相同的长度,但 PCRE 允许可变长度的备选方案。

需要为最大前缀长度的每个字符添加管道的想法:

(?<=(\w\w:)|(\w:)) (.*\n?)\1?\2?

并替换为\t\3. 请参阅regex101 处的测试。在后视中捕获对于不消耗/不跳过匹配非常重要。相同的模式变量,例如 .NET(?<=(\w+:)) (.*\n?)\1?

  • (?<=(\w\w:)|(\w:))前两个捕获组在lookbehind 中捕获前缀:两个或一个单词字符后跟一个冒号。\w是的简写[A-Za-z0-9_]

  • (.*\n?)第三个捕获组,用于前缀之间的内容。可选换行符以获取最后一场比赛。

  • \1?\2?如果在以下行中,将可选地替换相同的前缀。只能设置两者之一:\1xor \2。冒号后的空格也将始终匹配 - 无论前缀。


摘要:每个前缀转换为制表符后的空格。仅当匹配当前行时,下一行的前缀。
       匹配和替换多个空格和制表符:(?<=(\w\w:)|(\w:))[ \t]+(.*\n?)\1?\2?

于 2015-08-04T04:22:10.287 回答
4

替换的问题是匹配的数量不确定。当您将该数字限制为 12 时,您可以使用这样的正则表达式:

^([^:]+): ([^\n]+[\n]*)(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?(\1: ([^\n]+[\n]*))?

用这个替换:

\n\1:\t\2\t\4\t\6\t\8\t\10\t\12\t\14\t\16\t\18\t\20\t\22\t\24

解释:它基本上只包含两个子正则表达式

  • ^([^:]+): ([^\n]+[\n]*)= 匹配组的第一行

  • (\1: ([^\n]+[\n]*))?= 连续行上的可选匹配,属于同一组。您必须根据需要经常复制此正则表达式以匹配所有行(即在本例中为 12x)。?如果没有足够的匹配项进行所有替换,则(= 可选)匹配项不会给您错误。

  • \n格式问题需要替换开头的

  • 结果将包含一些空行,但我敢肯定,你可以解决这个问题...... ;-)

演示 1

但是,由于我不喜欢过大的正则表达式 - 并且对于您有更多潜在匹配项的情况 - 我更喜欢这样的解决方案:

演示 2

于 2015-08-03T02:17:45.193 回答
1

下面的 awk one-liner 会做你想做的事

awk -F: 'NR==1 {print $0} NR != 1 {if ($1 != prev) print $0; else {for (i=0; i<=length($1); ++i) printf " "; print $2;}} {prev=$1}' < input_file.txt

(将原文放入input_file.txt)

我相信可以写出更好的代码,但该睡觉了)

于 2015-08-02T03:34:06.417 回答
1

我在 Bare Bones Software Inc. 的 TextWrangler 中尝试了您的示例,我想出了一个两遍解决方案,该解决方案仅限于n个连续行,它使用制表符而不是试图神奇地匹配前缀的长度。另请注意,文件的最后一行应为空行(, 6在您的示例之后添加换行符)

出于我们的目的,我将向您展示n = 4 的位置:

Find: ^([[:alnum:]]+\:)(.+\r)(?:\1(.+\r))?\1(.+)\r
Replace: \1\2\t\3\t\4\t\5\r

您可以通过复制 a in并在before in中添加一个来为任何n添加一个,其中 *n* 是在 that 之前的最后一个数字之后的增量。(?:\1(.+\r))?Find\t\n\rReplace\r

用这个替换所有,你可以跟进它:

Find: ^\t+
Replace: \t

主要是得到你想要的结果。

于 2015-08-04T07:20:10.120 回答
0

因此,由于您想替换除第一个实例之外的所有其他实例,我假设您需要正则表达式来匹配除第一个之外的所有实例,以便您可以替换它们。你知道正则表达式不能修改或改变原始字符串,只返回一个特定的匹配,它本身可以用来指定要修改的字符串的一部分。

我能想到的最好的正则表达式是/(\b[a-zA-Z0-9]+: )[^\n]+(?:\n|$)(?!\1)/g.

这将捕获每个唯一实例xx:并匹配它的最后一个实例。唯一的问题是即使它是唯一的实例,它仍然会匹配最后一个实例。

我的结论是,我不相信你可以用正则表达式做到这一切。我可能错了,如果有人能找到支持后向和反向引用的在线正则表达式调试器,请告诉我,我会看看我是否可以编写一个表达式来工作。我个人找不到任何接受反向引用和向后查找的正则表达式调试器。在我的示例中,我使用前瞻来代替它检查是否有任何它的实例,如果有,则忽略当前匹配(因此它只选择最后一个实例)。

如果您真的想找到一种方法来自动化它以使其工作,请使用/(\b[a-zA-Z0-9]+: )/g匹配 的每个实例xx:,将它们全部存储在一个数组中,如果有重复,请在该特定实例上运行原始正则表达式以继续修剪它直到没有更多的重复项。同样,您可以使用它来存储所有唯一实例并以某种方式利用它。

希望这有助于或澄清您的问题,如果没有,请道歉。

于 2015-08-02T03:13:56.977 回答
-1

没有要测试的 Textwrangler,但我在其他 Regex Tool 中测试过,效果很好,请尝试:

(?<=(?:(?:.+\n)|^)(\w+?:).+\n)\1(?=\s)
于 2014-08-14T02:19:22.133 回答