Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Emacs,使用字符串中的replace regexp匹配两个regexp_Regex_Emacs - Fatal编程技术网

Emacs,使用字符串中的replace regexp匹配两个regexp

Emacs,使用字符串中的replace regexp匹配两个regexp,regex,emacs,Regex,Emacs,我试图使用replace regexp in string替换字符串中的两个部分,但一次只能让一个部分工作。下面是一个示例,我想删除字符串开头的#和空格,以及字符串结尾的换行符。当我将两个调用组合成一个表达式时,我做错了什么 ;; Test string (setq inputStr "## Header Stuff ") ;; This doesnt trim the newline (setq header (replace-regexp-in-string "^[#\s]*\

我试图使用
replace regexp in string
替换字符串中的两个部分,但一次只能让一个部分工作。下面是一个示例,我想删除字符串开头的
#
和空格,以及字符串结尾的换行符。当我将两个调用组合成一个表达式时,我做错了什么

;; Test string
(setq inputStr "## Header Stuff
")

;; This doesnt trim the newline
(setq header
      (replace-regexp-in-string "^[#\s]*\\|\n$" "" inputStr) )

;; Each match done separately works though
(setq header
      (replace-regexp-in-string "^[#\s]*" "" inputStr) )
(setq header
      (replace-regexp-in-string "\n$" "" header) )

header
"Header Stuff"

更新:问题似乎出在第一个表达式上,例如,这将换行符和
“S”
替换为
“X”
(替换字符串“S\\\\\n$”“X”inputStr中的regexp)
看起来
替换字符串中的regexp
与空字符串匹配的regexp有一些意外行为。下面的regexp实现了您所期望的功能(注意用
+
量词代替
*
):

原因在于
replace regexp in string
的内部实现,您可以使用
M-x find函数查找该函数。在伪代码中,它大致执行以下操作:

给定一个
regexp
、一个
replacement
和一个
string

  • l
    设置为字符串长度,将
    start
    设置为
    0
    。创建一个名为
    matches
    的空堆栈,以累积新字符串的片段

  • 只要
    start
    小于
    l
    并且
    regexp
    string
    中的某个地方匹配,请执行以下操作:

  • 提取与regexp匹配的
    string
    部分,并将其称为
    str

  • regexp
    替换为
    replacement
    ,在较短的字符串
    str
    中(这很重要)

  • 将新字符串的以下两个片段推送到
    匹配的堆栈上:

    • 字符串
      的不匹配初始部分,从
      开始
      到匹配的开始

    • 子字符串
      str
      ,其中
      regexp
      的匹配项现在已替换为
      replacement

  • start
    设置到匹配部分的末尾,然后重复

  • 最后,将
    matches
    堆栈上的字符串片段按相反顺序连接起来并返回结果

  • 原始regexp的问题发生在循环的步骤(3)中。即使regexp与完整字符串
    “###Header stuff\n”
    末尾的换行符正确匹配,但当它第二次与一个字符串
    “\n”
    匹配时,替换项的第一个分支(与空字符串匹配)优先于第二个分支,它用空字符串替换空字符串,无法删除尾随的新行

    这可以说是
    替换字符串中的regexp中的一个bug,但它也说明了regexp语义是多么棘手,尤其是当涉及空字符串时。对我来说,变通解决方案更容易阅读和理解:

    (let ((input-string "## Header Stuff
    "))
      (setq input-string (replace-regexp-in-string "\\`[#\s]*" "" input-string))
      (setq input-string (replace-regexp-in-string "\n*\\'" "" input-string))
      input-string)
    
    如果您有最新的Emacs(预测试24.4或更高版本),您还可以使用内置
    subr-x
    软件包中的
    string trim right
    功能:

    (let ((input-string "## Header Stuff
    "))
      (string-trim-right (replace-regexp-in-string "\\`[#\s]*" "" input-string)))
    


    顺便说一句,在研究这个问题时,我惊讶地发现Emacs字符串中的
    \s
    只是一种不同的空格字符书写方式。如果您希望regexp行为类似于Perl的通配符
    \s
    ,您可能希望使用
    “\\s-”
    (将任何字符与空格语法匹配),或
    “[:space:][]”

    注意
    (将regexp替换为字符串“^[\s]*\\\\\\\n$“X”inputStr
    返回结果。@Barmar我明白了,为什么“X”不是替换换行符?我不明白,这就是为什么我没有给出答案。@Barmar这一个在换行符后面放了“X”,但我不明白,
    (在字符串中替换regexp“^[\35;\ s]*\\\\\\n$\\'“X”inputStr)
    $
    匹配行尾,
    \\'
    匹配行尾。根据代码注释,这个实现似乎是为了提高效率而设计的——特别是避免在每次替换时复制整个字符串,就像更简单的实现那样。我同意这似乎不是理想的行为。如果愿意,可以将其报告为bug(
    M-x report emacs bug
    )。
    (let ((input-string "## Header Stuff
    "))
      (string-trim-right (replace-regexp-in-string "\\`[#\s]*" "" input-string)))