'pcregrep`中的选项`-N`是什么意思?请列出一些例子

时间:2015-09-04 09:04:58

标签: regex

选项-Npcregrep中的含义是什么?

我无法理解本手册。

   -N newline-type, --newline=newline-type
             The  PCRE  library  supports  five different conventions for
             indicating the ends of lines. They are the  single-character
             sequences  CR  (carriage return) and LF (linefeed), the two-
             character sequence CRLF, an "anycrlf" convention, which rec‐
             ognizes  any of the preceding three types, and an "any" con‐
             vention, in  which  any  Unicode  line  ending  sequence  is
             assumed  to  end a line. The Unicode sequences are the three
             just mentioned, plus VT (vertical tab,  U+000B),  FF  (form‐
             feed,  U+000C), NEL (next line, U+0085), LS (line separator,
             U+2028), and PS (paragraph separator, U+2029).

             When the  PCRE  library  is  built,  a  default  line-ending
             sequence  is  specified.   This  is  normally  the  standard
             sequence for the operating system. Unless  otherwise  speci‐
             fied  by  this  option, pcregrep uses the library's default.
             The possible values for this option are CR, LF,  CRLF,  ANY‐
             CRLF,  or  ANY.  This  makes  it possible to use pcregrep on
             files that have come from other environments without  having
             to  modify  their  line  endings.  If the data that is being
             scanned does not agree  with  the  convention  set  by  this
             option, pcregrep may behave in strange ways.

我已经在Google和stackoverflow中进行了搜索,但我看不到任何示例。

如何使用此选项?请参阅下面的示例。 -N只是不起作用。

$ cat /tmp/pcregrep-test
abcd
something1
something2
djfkhh

hh

$ pcregrep -Mo "abcd(.|\n)+k" /tmp/pcregrep-test
abcd
something1
something2
djfk

$ pcregrep -N ANY -Mo "abcd.+k" /tmp/pcregrep-test

$ pcregrep -N any -Mo "abcd.+k" /tmp/pcregrep-test

$ pcregrep --newline=ANY -Mo "abcd.+k" /tmp/pcregrep-test 

$ pcregrep --newline=any -Mo "abcd.+k" /tmp/pcregrep-test

$

答案

关键概念

  1. \n始终是.*的分隔符,即.永远不会包含\n
  2. 选项-N用于定义\n是什么。 -N指定的是.*的分隔符。
  3. 示例(Lorehead的原始版本)

    $ echo -e "foo\012foo\015bar\012foo baz" > pcretest.txt
    
    $ vim pcretest.txt
    foo
    foo^Mbar
    foo baz 
    
    $ pcregrep -N LF -Mon "^foo.*$" pcretest.txt > result_LF 
    
    $ vim result_LF
    1:foo
    2:foo^Mbar
    3:foo baz
    # LF as the newline, the delimiter. Three matches.
    
    $ pcregrep -N CR -Mon "^foo.*$" pcretest.txt > result_CR
    
    $ vim result_CR
    1:foo
    foo
    # CR as the newline, the delimiter. One match.
    

2 个答案:

答案 0 :(得分:1)

您还可以在NEWLINES标题下的documentation of PCRE中找到上述段落。该文档进一步解释了该标志如何影响正则表达式的解释:

  

在PCRE文档中,单词" newline"用于表示"表示换行符的字符或字符对"。 newline约定的选择会影响dot,circumflex和dollar元字符的处理,/x模式下#comments的处理,以及当CRLF是识别的行结束序列时,非匹配位置的推进 - 锚定模式。 [...]

解释文档中的每个项目:

  • 在默认模式下,.的定义排除"换行符"字符。确切的字符列表取决于此选项。

    • 如果您选择CR,则.相当于[^\r]
    • 如果选择LF,则.相当于[^\n]
    • 如果您选择CRLF,则.相当于(?:[^\r\n]|\r(?!\n)|(?<!\r)\n)
    • 如果您选择ANY-CRLF,则.相当于[^\r\n]
    • 如果选择ANY,则.等同于[^\r\n\v\f\x85\u2028\u2029],默认模式8位库除外,它等同于[^\r\n\v\f\x85](因为一个代码单元只有8-位为8位库。)

    样品运行:

    $ echo -e 'abc\ndef\rlksdf\r\nsdf' | pcregrep -N CR -Mo 'abc.*'
    abc
    def
    
    $ echo -e 'abc\ndef\rlksdf\r\nsdf' | pcregrep -N CRLF -Mo 'abc.*'
    abc
    lksdf
    
    $ echo -e 'abc\ndef\rlksdf\r\nsdf' | pcregrep -N LF -Mo 'abc.*'
    abc
    

    def在第二轮中消失,因为它被\rlksdf序列覆盖。)

  • 在多行模式下,^$是根据新行字符的定义定义的。在默认模式下,由于$可以在终止换行符之前匹配,因此该设置也会影响$可以匹配的内容。

    • 如果您选择ANY-CRLF或ANY,其中包括CR,LR和CRLF,^$将在CRLF序列之间不匹配。

      这也是文档所指的内容当换行符号是一个识别的行结束序列时,新行约定的选择会影响[...]的处理,非锚定模式的匹配位置提升。给定^多行模式和换行模式ANY-CRLF或ANY,它在CRLF之间不匹配,而是在CRLF中跳过LF之后。具有多线模式的^被视为非锚定模式,因为它不会将匹配限制为字符串的开头(请参阅PCRE_INFO_FIRSTCHARACTERFLAGS)。

  • 在自由间距模式/x中,我们可以编写以#开头并以换行符结尾的单行注释。换行设置会影响评论的结束位置。

答案 1 :(得分:1)

修改:我在下面看到您的要求。该选项确实有效,我将原始帖子作为历史解释。

$ echo -e "foo\012foo\015bar\012foo baz" > pcretest.txt 
$ more pcretest.txt
foo
bar
foo baz
$ pcregrep -N LF -Mo "^foo.*$" pcretest.txtfoo
foo
bar
foo baz
$ pcregrep -N CR -Mo "^foo.*$" pcretest.txt
foo
foo
$ pcregrep -N ANY -Mo "^foo.*$" pcretest.txt
foo
foo
foo baz

刚刚发生了什么:

ASCII字符10或八进制\012LF。 ASCII字符13或八进制\015CR。在Unix终端上,LF表示开始一个新行,而CR表示返回行的开头并覆盖之前的任何内容。

所以,我们写了foo LF foo CR bar LF foo baz。当我们将这些原始代码回显到终端时,它将它们解释为:foo,new line,foo,擦除这一行并重新开始,bar,new line,foo baz。

当我们将LF视为一行,CR视为匹配.*时,我们会得到三行foofoo CR barfoo baz。所有这些都匹配模式,但当终端尝试显示第二行时,CR告诉它用foo覆盖bar,所以它似乎在告诉我们{{ 1}}匹配模式bar。但真的,在翻译中丢失了一些东西。

当我们将^foo.*$视为行尾,并CR作为匹配LF时,我们有两行,.*foo LF foo,其中第一个匹配模式。但是当Unix终端试图显示它时,它会在bar LF foo baz处将该行分成两行。

当我们将LFCR视为一行的结尾时,有四行,LFfoofoo和{{ 1}},其中第三个与模式不匹配。

为什么PCRE会这样做:

如果您正在阅读在Windows(或MS-DOS)上创建的文件,则此处的段之间的行可能以ASCII字符barfoo baz)结尾。如果您正在读取在Unix上创建的文件,则行可能仅以CR LF10 13)结尾。如果您正在阅读在旧Apple上创建的文件,则行可能以LF10)结尾。 ISO决定通过引入自己的新方法来结束ISO-8859-1中没有人使用的线路,然后Unicode联盟做了同样的事情,从而决定帮助。

其历史原因在于,一些旧的手动电传打字机具有单独的命令以将纸卷推进一行(换行)并将打印头移回到行的开头(回车)。然后MIT和Apple都意识到,在计算机上,他们只需要一个。

PCRE希望能够理解任何这些格式。某些终端脚本实际上使用CR将光标移动到当前行的最左侧位置,例如更新文本进度条,因此您可能希望搜索13代码的那些。 / p>