正则表达式:使用re.sub将连字符替换为短划线

3

我正在使用一个小函数来循环遍历文件,以便将任何连字符 - 替换为 en-dash (alt + 0150)。

我使用的函数为相关问题的解决方案 (如何自动替换多个文件中文本内容内的字符?) 添加了一些正则表达式的特性。

def mychanger(fileName):
  with open(fileName,'r') as file:
    str = file.read()
    str = str.decode("utf-8")
    str = re.sub(r"[^{]{1,4}(-)","–", str).encode("utf-8")
  with open(fileName,'wb') as file:
    file.write(str)

我使用正则表达式[^{]{1,4}(-),因为实际上是在latex回归表中进行搜索,我只想替换数字周围出现的连字符。

明确一点:我想要替换除了真正的latex代码(如\cmidrule(lr){2-4})外的所有连字符。

  • 在这种情况下,有一个{接近(在3-4个字符内)连字符左侧。当然,这个连字符不应该被改成en-dash,否则latex代码会出错。

  • 我认为排除条件的左部分很重要,以编写正确的正则表达式。实际上,在回归表中可以有像-0.062\sym{***}这样的东西(即在连字符紧右边的{),在这种情况下我确实想替换连字符。

我的表格中的典型行是

variable    &   -2.061\sym{***}&       4.032\sym{**}   &       1.236         \\
            &      (-2.32)         &   (-2.02)         &      (-0.14)    

然而,我的正则表达式似乎不正确。例如,(-1.2) 将被替换为 –1.2,省略了括号。
这里有什么问题呢? 谢谢!

1
请展示所有您不希望发生替换的情况。 - Tim Biegeleisen
1
你能提供一份数据样本以及它在哪里出现了不匹配或错误匹配吗? - zwer
嗨,谢谢!@TimBiegeleisen @zwer 只能想到像\cmidrule(lr){2-8}这样的情况,其中有一个{靠近连字符并在其左侧。确实,在回归表中,您可以有像-0.062\sym{***}这样的内容。 - ℕʘʘḆḽḘ
1
@Noobie 我尝试在下面给出一个答案。虽然不够简洁,但让我们试着迭代优化,直到找到解决你实际问题的方法。 - Tim Biegeleisen
2个回答

2
我可以提供以下两个步骤的替换方案:
str = "-1 Hello \cmidrule(lr){2-4} range 1-5 other stuff a-5"
str = re.sub(r"((?:^|[^{])\d+)-(\d+[^}])","\\1$\\2", str).encode("utf-8")
str = re.sub(r"(^|[^0-9])-(\d+)","\\1$\\2", str).encode("utf-8")
print(str)

第一个替换目标是所有不属于LaTex形式{1-9}的范围,即不包含在花括号内的范围。第二个替换目标是所有以非数字或字符串开头的数字。

演示


太棒了!!但是这适用于短划线吗?(不是美元符号)最终我想要使用短划线而不是连字符。谢谢!!! - ℕʘʘḆḽḘ
1
@Noobie,由于某些编码问题,我无法让演示使用 en dash 正常工作。只需将美元符号替换为 en dash 即可解决。但是,出于演示目的,我认为美元符号使替换更清晰、更易读。 - Tim Biegeleisen
1
这是一个Python编码问题,我在这方面帮不上太多忙。 - Tim Biegeleisen
1
@Noobie 请看这里:https://dev59.com/jHRC5IYBdhLWcg3wJNqf - Tim Biegeleisen
1
@Noobie 你需要在这里付出一些努力。我给了你一个看起来有效的模式,你可以处理剩下的部分。 - Tim Biegeleisen
显示剩余5条评论

1

re.sub替换整个匹配项。在这种情况下,包括您的-之前的非{字符。您可以将该部分用括号括起来创建一个\1组,并将其包含在替换中(您也不需要在周围加括号):

re.sub(r"([^{]{1,4})-",r"\1–", str)

1
它在我的Python3 REPL中可以工作。你能解释一下你的意思吗,@TimBiegeleisen? - Adam S
我认为@TimBiegeleisen想表达的意思是这并不能替代连字符,这正确吗? - ℕʘʘḆḽḘ
1
应该是(我用X替换了ASCII连字符以突出重点):`In [18]: str = "(-1.2)"In [19]: re.sub(r"([^{]{1,4})-",r"\1X", str) Out[19]: '(X1.2)'` - Adam S
感谢Adam的帮助。但是re.sub(r"([^{]{1,4})-",r"\1X", '-0.079\sym{***}')会得到'-0.079\\sym{***}',这将破坏Latex代码。 - ℕʘʘḆḽḘ
1
这将替换LaTEX代码。在此处查看演示。我认为正确的正则表达式会比这个答案复杂得多。 - Tim Biegeleisen
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接