python - Perl 或 Python : Convert date from dd/mm/yyyy to yyyy-mm-dd

标签 python perl date text-processing

我需要将 CSV 文件的列中的许多日期从 dd/mm/yyyy 格式转换为 yyyy-mm-dd 格式。例如,17/01/2010 应转换为 2010-01-17。

我如何在 Perl 或 Python 中执行此操作?

最佳答案

如果保证您的数据格式正确,只包含 DD-MM-YYYY 格式的单例日期,那么这行得通:

# FIRST METHOD
my $ndate = join("-" => reverse split(m[/], $date));

这适用于持有“07/04/1776”的$date,但在“this 17/01/2010 and that 01/17/2010 there”上失败。相反,使用:

# SECOND METHOD
($ndate = $date) =~ s{
    \b
      ( \d \d   )
    / ( \d \d   )
    / ( \d {4}  )
    \b
}{$3-$2-$1}gx;

如果您更喜欢更“符合语法”的正则表达式,以便更容易维护和更新,您可以改用这个:

# THIRD METHOD
($ndate = $date) =~ s{
    (?&break)

              (?<DAY>    (?&day)    )
    (?&slash) (?<MONTH>  (?&month)  )
    (?&slash) (?<YEAR>   (?&year)   )

    (?&break)

    (?(DEFINE)
        (?<break> \b     )
        (?<slash> /      )
        (?<year>  \d {4} )
        (?<month> \d {2} )
        (?<day>   \d {2} )
    )
}{
    join "-" => @+{qw<YEAR MONTH DAY>}
}gxe;

最后,如果您有 Unicode 数据,您可能需要更加小心。

# FOURTH METHOD
($ndate = $date) =~ s{
    (?&break_before)
              (?<DAY>    (?&day)    )
    (?&slash) (?<MONTH>  (?&month)  )
    (?&slash) (?<YEAR>   (?&year)   )
    (?&break_after)

    (?(DEFINE)
        (?<slash>     /                  )
        (?<start>     \A                 )
        (?<finish>    \z                 )

        # don't really want to use \D or [^0-9] here:
        (?<break_before>
           (?<= [\pC\pP\pS\p{Space}] )
         | (?<= \A                )
        )
        (?<break_after>
            (?= [\pC\pP\pS\p{Space}]
              | \z
            )
        )
        (?<digit> \d            )
        (?<year>  (?&digit) {4} )
        (?<month> (?&digit) {2} )
        (?<day>   (?&digit) {2} )
    )
}{
    join "-" => @+{qw<YEAR MONTH DAY>}
}gxe;

您可以看到这四种方法在遇到如下示例输入字符串时的表现如何:

my $sample  = q(17/01/2010);
my @strings =  (
    $sample,  # trivial case

    # multiple case
    "this $sample and that $sample there",

    # multiple case with non-ASCII BMP code points
    # U+201C and U+201D are LEFT and RIGHT DOUBLE QUOTATION MARK
    "from \x{201c}$sample\x{201d} through\xA0$sample",

    # multiple case with non-ASCII code points
    #   from both the BMP and the SMP 
    # code point U+02013 is EN DASH, props \pP \p{Pd}
    # code point U+10179 is GREEK YEAR SIGN, props \pS \p{So}
    # code point U+110BD is KAITHI NUMBER SIGN, props \pC \p{Cf}
    "\x{10179}$sample\x{2013}\x{110BD}$sample",
);

现在让 $date 成为遍历该数组的 foreach 迭代器,我们得到以下输出:

Original is:   17/01/2010
First method:  2010-01-17
Second method: 2010-01-17
Third method:  2010-01-17
Fourth method: 2010-01-17

Original is:   this 17/01/2010 and that 17/01/2010 there
First method:  2010 there-01-2010 and that 17-01-this 17
Second method: this 2010-01-17 and that 2010-01-17 there
Third method:  this 2010-01-17 and that 2010-01-17 there
Fourth method: this 2010-01-17 and that 2010-01-17 there

Original is:   from “17/01/2010” through 17/01/2010
First method:  2010-01-2010” through 17-01-from “17
Second method: from “2010-01-17” through 2010-01-17
Third method:  from “2010-01-17” through 2010-01-17
Fourth method: from “2010-01-17” through 2010-01-17

Original is:   𐅹17/01/2010–𑂽17/01/2010
First method:  2010-01-2010–𑂽17-01-𐅹17
Second method: 𐅹2010-01-17–𑂽2010-01-17
Third method:  𐅹2010-01-17–𑂽2010-01-17
Fourth method: 𐅹2010-01-17–𑂽2010-01-17

现在假设您确实想要匹配非 ASCII 数字。例如:

   U+660  ARABIC-INDIC DIGIT ZERO
   U+661  ARABIC-INDIC DIGIT ONE
   U+662  ARABIC-INDIC DIGIT TWO
   U+663  ARABIC-INDIC DIGIT THREE
   U+664  ARABIC-INDIC DIGIT FOUR
   U+665  ARABIC-INDIC DIGIT FIVE
   U+666  ARABIC-INDIC DIGIT SIX
   U+667  ARABIC-INDIC DIGIT SEVEN
   U+668  ARABIC-INDIC DIGIT EIGHT
   U+669  ARABIC-INDIC DIGIT NINE

甚至

 U+1D7F6  MATHEMATICAL MONOSPACE DIGIT ZERO
 U+1D7F7  MATHEMATICAL MONOSPACE DIGIT ONE
 U+1D7F8  MATHEMATICAL MONOSPACE DIGIT TWO
 U+1D7F9  MATHEMATICAL MONOSPACE DIGIT THREE
 U+1D7FA  MATHEMATICAL MONOSPACE DIGIT FOUR
 U+1D7FB  MATHEMATICAL MONOSPACE DIGIT FIVE
 U+1D7FC  MATHEMATICAL MONOSPACE DIGIT SIX
 U+1D7FD  MATHEMATICAL MONOSPACE DIGIT SEVEN
 U+1D7FE  MATHEMATICAL MONOSPACE DIGIT EIGHT
 U+1D7FF  MATHEMATICAL MONOSPACE DIGIT NINE

假设您有一个等宽数字的日期,如下所示:

$date = "\x{1D7F7}\x{1D7FD}/\x{1D7F7}\x{1D7F6}/\x{1D7F8}\x{1D7F6}\x{1D7F7}\x{1D7F6}";

Perl 代码可以很好地处理它:

Original is:   𝟷𝟽/𝟷𝟶/𝟸𝟶𝟷𝟶
First method:  𝟸𝟶𝟷𝟶-𝟷𝟶-𝟷𝟽
Second method: 𝟸𝟶𝟷𝟶-𝟷𝟶-𝟷𝟽
Third method:  𝟸𝟶𝟷𝟶-𝟷𝟶-𝟷𝟽
Fourth method: 𝟸𝟶𝟷𝟶-𝟷𝟶-𝟷𝟽

我想你会发现 Python 有一个相当脑残的 Unicode 模型,它缺乏对抽象字符和字符串的支持,不管内容如何,​​这使得编写这样的东西变得非常困难。

在将子表达式的声明与其执行分离的情况下,在 Python 中编写清晰的正则表达式也很困难,因为那里不支持 (?(DEFINE)...) block 。见鬼,Python 甚至不支持 Unicode 属性。因此,它不适合 Unicode 正则表达式工作。

但是嘿,如果你认为 Python 与 Perl 相比很糟糕(确实如此),那就试试其他语言吧。对于这类工作,我还没有找到一个不差的。

如您所见,当您请求多种语言的正则表达式解决方案时,您会遇到真正的问题。首先,由于不同的正则表达式风格,解决方案很难进行比较。还因为没有其他语言可以在正则表达式的功能、表达能力和可维护性方面与 Perl 相提并论。一旦出现任意 Unicode,这可能会变得更加明显。

因此,如果您只想要 Python,那么您应该只要求它。否则,这是一场非常不公平的比赛,Python 几乎总是会输;在 Python 中正确处理这样的事情太麻烦了,更不用说正确和干净了。这要求它比它能产生的更多。

相比之下,Perl 的正则表达式在这两个方面都表现出色。

关于python - Perl 或 Python : Convert date from dd/mm/yyyy to yyyy-mm-dd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4077896/

相关文章:

html - 如何获取 Excel 中的链接以在单个浏览器选项卡中打开

perl - perl 中的内存使用情况

c - 传递目录作为参数并显示其最后修改日期

python - 使用 Selenium Python chrome webdriver 发推文

python - 2d numpy.array() 将一个字符串与所有其他字符串进行比较,并对每个字符串重复

python - 是否有内置的 python 来从多个列表创建元组?

python - 将 pandas 数据框保存为图像或 pdf 文档中的表格,并具有良好的多索引显示

perl - 将字符串(用户名)映射到 Perl 中的 UUID

ios - 此日期时间响应的正确格式是什么

r - Plotly 时间序列 - 水平绘制线