【问题标题】:What's the clearest way to replace trailing backslash \ with \n?用 \n 替换尾随反斜杠 \ 的最清晰方法是什么?
【发布时间】:2011-01-14 16:31:39
【问题描述】:

我想要java中的多行字符串,所以我寻求一个简单的预处理器来将C风格的多行转换为带有文字'\n'的单行。

之前:

    System.out.println("convert trailing backslashes\
this is on another line\
\
\
above are two blank lines\
But don't convert non-trailing backslashes, like: \"\t\" and \'\\\'");

之后:

     System.out.println("convert trailing backslashes\nthis is on another line\n\n\nabove are two blank lines\nBut don't convert non-trailing backslashes, like: \"\t\" and \'\\\'");

我认为sed 会做得很好,但是 sed 是基于行的,因此在 sed 中替换 '\' 和它后面的换行符(有效地连接两行)不是很自然。我将sredden79's oneliner 改编为以下内容 - 它有效,很聪明,但不清楚:

sed ':a { $!N; s/\\\n/\\n/; ta }'

替换为escaped literal backslashnewlineescaped literal backslashn:a 是一个标签,ta 是 goto 标签,如果替代品找到匹配项; $ 表示最后一行,$! 则相反(即除最后一行之外的所有行)。 N 表示将下一行附加到模式空间(从而使\n 字符可见。)

编辑这里是保持编译器错误行号等准确的变体:它将每个扩展行转换为"..."+\n(并正确处理字符串的第一行和最后一行):

sed ':a { $!N; s/\\\n/\\n"+\n"/; ta }'

给予:

    System.out.println("convert trailing backslashes\n"+
"this is on another line\n"+
"\n"+
"\n"+
"above are two blank lines\n"+
"But don't convert non-trailing backslashes, like: \"\t\" and \'\\\'");

编辑 实际上,最好有 Perl/Python 风格的多行代码,其中它以一行上的特殊代码开始和结束(我认为是 python 的“”)。

有没有更简单、更理智、更清晰的方法(可能不使用 sed)?

【问题讨论】:

  • 如果你这样做,你会扼杀你的工具支持。突然没有 IDE 会正确地进行语法高亮,调试器将显示与您的(原始)源文件不同的行号......请记住,编译器(在编译时)会将与 + 连接的文字字符串连接在一起,所以只需关闭字符串,写一个+,然后在下一行打开它会去掉预处理器并保持你的工具支持完好无损。 FWIW。

标签: perl sed awk


【解决方案1】:

有没有更简单、更理智、更清晰的方法。

忘记预处理器,忍受限制,抱怨它(这样它可能会在 Java 7 或 8 中得到修复),然后use an IDE to ease the pain

其他替代方案(我想太麻烦了,但总比弄乱编译过程好):

  • 使用支持 here-docs 的基于 JVM 的语言
  • 将字符串外部化为资源文件

【讨论】:

  • 谢谢 1. IDE 的想法很酷,但对编辑没有帮助(编辑、添加、在多行连接字符串的行之间移动很痛苦——这就是我以前使用的方法)。 2. 外部化到资源文件是我现在所做的——但我认为将它与它相关的源代码放在一起更简单、更易于管理。 3. 一个全新的 JVM 语言来解决这个问题确实看起来很麻烦,但是......它已经被调试过,并且有工具支持,语法突出显示等,所以你的想法有一个有趣的优雅!当然,可以将 sed 脚本本身视为一种“JVM 语言”。
【解决方案2】:

perl 单行代码:

perl -0777 -pe 's/\\\n/\\n/g'

这将在命令行上读取标准输入或以它命名的文件,并将输出写入标准输出。

如果您使用的是支持过滤的编辑器,例如 vi 或 emacs,只需通过上述命令过滤您的文本即可:

如果您使用的是 Windows 并且不得不担心\r

C:\> perl -0777 -pe "s/\\\r?\n/\\n/g"

虽然我认为 win32 Perl 自己处理 \r 所以这可能是不必要的。

-0777 选项是定义行或记录分隔符的-0(零)选项的特例。在这种情况下,这意味着我们不需要任何分隔符,因此将整个文件作为单个字符串读取。

-pe 选项是-p(逐行处理并打印结果)和-e(下一个参数是(一行)要执行的程序)的组合

【讨论】:

    【解决方案3】:

    根据您的要求编写的 perl 脚本。

    while (<>) {
        chomp;
        print $_;
        if (/\\$/) {
            print "n";
        } else {
            print "\n";
        }
    }
    

    【讨论】:

      【解决方案4】:
      sed 's/\x5c\x5c$/\x22\x5c\x5cn\x22/'
      

      反斜杠和双引号的十六进制分别是 \x5c 和 \x22 - 它需要被转义,所以 \x5c 加倍并且 $ 锚定到行尾。

      根据 OP 评论再次更新:

      sed "{:a;N;\$!b a};s/\x5c\x5c\n/\x5c\x5cn/g" 
      

      :a 创建一个标签,N 将一行添加到模式空间,b a 分支回到标签 :a 除非它的最后一行 $!;

      在全部加载后 - 单行替换将所有出现的换行符 \n 替换为文字 '\n',使用十六进制 ascii 代码 \x5c 作为反斜杠。

      【讨论】:

      • 这不加入行(并添加引号,这是不想要的)。在问题中给出的示例上尝试一下,然后比较结果以了解我的意思。
      • 我想我回答得太快了,我在回答中添加了更新。 Sed 对换行符终止的字符串进行操作,因此您无法修改跨度,除非您在模式空间中将它们全局化。
      • 这看起来与问题本身已经存在的 sed 解决方案非常相似。此外,您可以转义反斜杠,它比十六进制更具可读性。但是您似乎知道 sed 的方式 - 也许您可以提出一个更清晰的版本(这是实际问题)。但是我不确定是否有一个,仅仅是因为需要连接线(或者按照您的描述将它们放在模式空间中)。也许只是在两个阶段的管道中进行,第一个加入所有内容,第二个进行实际匹配?无论如何,请通读整个问题并完成它!
      • 很明显,如果您了解 sed,就没有多余的东西 - 让不太了解 sed 的人也能阅读,而且通常,您可以在任何地方发表评论需要使用对那些不太熟悉相应软件工具的术语的人来说可能看起来很神秘的结构。我使用十六进制是因为我刚刚完成了一个重命名工具,它使用 sed alot 替换文件名中的特殊字符,如果你想要一个像样的重命名工具,你可以在这里查看:scriptsandoneliners.blogspot.com/2014/12/…
      • 这个问题要求最清晰,而不是最快。这个答案在所有行上用文字 \n 替换换行符,而不仅仅是那些带有反斜杠的行。
      猜你喜欢
      • 2017-02-25
      • 2012-04-14
      • 2012-06-16
      • 1970-01-01
      • 1970-01-01
      • 2016-12-01
      • 2013-04-10
      • 1970-01-01
      相关资源
      最近更新 更多