【问题标题】:Remove single line breaks, keep "empty" lines删除单个换行符,保留“空”行
【发布时间】:2012-05-14 22:29:16
【问题描述】:

假设我用光标选择了如下文本:

This is a test. 
This 
is a test.

This is a test. 
This is a 
test.

我想把它改成:

This is a test. This is a test

This is a test. This is a test

换句话说,我想用空格替换单个换行符,留下空行。

我认为类似以下的方法会起作用:

RemoveSingleLineBreaks()
{
  ClipSaved := ClipboardAll
  Clipboard =
  send ^c
  Clipboard := RegExReplace(Clipboard, "([^(\R)])(\R)([^(\R)])", "$1$3")    
  send ^v
  Clipboard := ClipSaved
  ClipSaved = 
}

但事实并非如此。如果我将它应用于上面的文本,它会产生:

This is a test. This is a test.
This is a test. This is a test.

这也删除了中间的“空行”。这不是我想要的。

澄清一下:空行是指任何带有“白色”字符(例如制表符或空格)的行

有什么想法吗?

【问题讨论】:

    标签: regex autohotkey


    【解决方案1】:
    RegExReplace(Clipboard, "([^\r\n])\R(?=[^\r\n])", "$1$2")
    

    假设新行标记在末尾包含CRLF(例如CRLFCR+LFLF+CR),这将去除单个换行符。它不会将空格视为空。

    你的主要问题是\R的使用:

    \R 在字符类中只是字母“R”[source]

    解决方法是直接使用CRLF 字符。


    澄清一下:空行是指任何带有“白色”字符的行(例如制表符或空格)

    RegExReplace(Clipboard, "(\S.*?)\R(?=.*?\S)", "$1")
    

    这与上面的相同,但将空格视为空。它之所以有效,是因为它以非贪婪方式接受除换行符 (*?) 之外的所有字符,直到换行符前后的第一个非空白字符,因为默认情况下 . 不匹配换行符。

    前瞻用于避免“吃掉”(匹配)下一个字符,这可能会在单字符行上中断。请注意,由于它不匹配,因此它不会被替换,我们可以将它排除在替换字符串之外。由于 PCRE 不支持可变长度的lookbehind,因此不能使用lookbehind,因此使用普通的捕获组和反向引用代替。


    我想用空格替换单个换行符,留下空行。

    如果想用空格代替换行符,这样比较合适:

    RegExReplace(Clipboard, "(\S.*?)\R(?=.*?\S)", "$1 ")
    

    这将用空格替换单个换行符。


    如果你想使用lookbehinds和lookaheads:


    去除单个换行符:

    RegExReplace(Clipboard, "(?<=[^\r\n\t ][^\r\n])\R(?=[^\r\n][^\r\n\t ])", "")
    


    用空格替换单个换行符:

    RegExReplace(Clipboard, "(?<=[^\r\n\t ][^\r\n])\R(?=[^\r\n][^\r\n\t ])", " ")
    

    由于某种原因,\S 似乎在后视和前瞻中不起作用。至少,在我的测试中没有。

    【讨论】:

    • 我想赞成和反对:非常有帮助,但([^\r\n])\R([^\r\n])(\S.*?)\R(.*?\S) 不适用于使用单个(非换行符)字符连接行。例如。 Java 表示法中的此字符串:"aaa\n" + "b\n" + "ccc" 被错误地转换为 "aaab\nccc"。此外,我不完全理解 (\S.*?)\R(.*?\S) 的解释 - 你介意扩展它吗?
    • @JanŻankowski ...哇,这是 7 年前的事了。通过使用前瞻来编辑和修复单字符大小写。有关详细的正则表达式解释,请参阅AHK quickreference 和在线提供的各种 PCRE 教程/解释。 regular-expressions.info 不错。或者使用可以解析/解释正则表达式语法的工具,e.g. see the right side of this regex101 page
    • 感谢您在这么长时间后及时回到这里!很高兴看到前瞻是要走的路——我也这么认为。一些注意事项:(1)第一个正则表达式([^\r\n])\R([^\r\n]) 可能也需要前瞻,(2)在您建议的正则表达式测试器中修改(\S.*?)\R(?=.*?\S) 之后,我不认为非贪婪修饰符(? in *?) 是必需的 - 组和前瞻将在换行符之前和之后的行上有更广泛的匹配,但也可以工作 - 而且它读起来更简单。
    • @JanŻankowski 没错,今天下午我有这个想法。我想最初我不确定. 换行符的匹配行为,所以有人担心贪婪可能会超出预期的匹配。也就是说,理论上非贪婪应该更快,因为它会更早停止,但是缺少可变长度的后视意味着非贪婪和贪婪在那里是等价的。编辑了第一个示例,暂时不考虑非贪婪者。
    【解决方案2】:
    Clipboard := RegExReplace(Clipboard, "(\S+)\R", "$1 ")
    

    【讨论】:

    • 当我运行它时,脚本会删除文本(即Clipboard 被分配了一个空字符串)
    • 是的......解决方案不正确,忽略它。它有一个不匹配的括号,但事实并非如此。问题是你可以在行尾之前有空格。我也很难用正则表达式来实现这个:)
    【解决方案3】:

    我相信这会奏效:

    text=
    (
    This is a test. 
    This 
    is a test.
    
    This is a test. 
    This is a 
    test.
    )
    MsgBox %    RegExReplace(text,"\S\K\v(?=\S)",A_Space)
    

    【讨论】:

      【解决方案4】:
      #SingleInstance force
      
      #v::
          Send ^c
          ClipWait
          ClipSaved = %clipboard%
      
          Loop
          {
              StringReplace, ClipSaved, ClipSaved, `r`n`r`n, `r`n, UseErrorLevel
              if ErrorLevel = 0  ; No more replacements needed.
                  break
          }
          Clipboard := ClipSaved
          return
      

      【讨论】:

        猜你喜欢
        • 2016-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-07
        • 1970-01-01
        相关资源
        最近更新 更多