<p>正如您标记的<code>sed</code>,这里有一个命令应该以一种非常有效和可移植的方式来完成这项工作,但是它有点不可读。。。你知道吗</p>
<pre><code>sed -n '1p;s/^"\{0,1\}\([0-9]\+\)\(\.[0-9]*\)\{0,1\}"\{0,1\}\(,"\(0[0-9]\|1[0-2]\)-\([0-2][0-9]\|3[01]\)-2[0-9]\{3\}",\)"\{0,1\}\([^"]*\)"\{0,1\}$/\1\3"\6"/p' file
</code></pre>
<p>它的作用是:</p>
<ol>
<li>打印标题,即第一行(<code>1p</code>)</li>
<li>在所有行上尝试替换(<code>s</code>)命令,并且仅当替换成功时才打印结果(因此仅当行与搜索模式匹配时)<code>s/…/…/p</code>。你知道吗</li>
</ol>
<p>关于替换模式<code>\1\3"\6"</code>,每个转义的数字都指向相应的捕获组(<code>\(…\)</code>;请记住,根据开始<code>\(</code>标记出现的顺序为这些组分配了一个数字)。具体来说:</p>
<ol>
<li><p><code>\1</code>表示前导数(<code>[0-9]\+</code>),有或没有(<code>\{0,1\}</code>)以下三件事:</p>
<ul>
<li>领先的<code>"</code></li>
<li>后面的小数部分<code>\.[0-9]*</code></li>
<li>以及以下<code>"</code></li>
</ul></li>
<li><p><code>\3</code>指的是包含在<code>"</code>周围的日期(<code>"\(0[0-9]\|1[0-2]\)-\([0-2][0-9]\|3[01]\)-2[0-9]\{3\}"</code>,<em>注意我在这个正则表达式中是不准确的,因为它也会匹配不存在的日期,比如2月31日</em>);</p></li>
<li><p><code>"\6"</code>引用(并把它放在<code>"</code>之间)到最后的字母数字字符串,我对它几乎没有任何假设(<code>[^"]*</code>)。</p></li>
</ol>
<p>这应该与日期匹配得更好一些(除了2月29日总是匹配,无论年份如何):</p>
<pre><code>sed -n '1p;s/^"\{0,1\}\([0-9]\+\)\(\.[0-9]*\)\{0,1\}"\{0,1\}\(,"\(\(0[0-9]\|1[0-2]\)-[0-2][0-9]\|\(0[469]\|11\)-30\|\(0[13578]\|1[02]\)-31\)-2[0-9]\{3\}",\)"\{0,1\}\([^"]*\)"\{0,1\}$/\1\3"\8"/p' file
</code></pre>