当emacs中的值相同时,如何增加和保持先前的增量

时间:2015-11-11 08:46:50

标签: emacs

我有两列值,第二列从特定值开始,我希望第二列以1开头,只在值改变时递增,否则保持前一个增量。我可以使用宏来设置开始计数,但是如何确保相同的值保持与显示的相同?,

问题:

0,39
1,39
2,39
3,39
4,40
5,40
6,40
7,41

我想要这个:

0, 1
1, 1
2, 1
3, 1
4, 2
5, 2
6, 2
7, 3

3 个答案:

答案 0 :(得分:2)

我很想看到其他答案,所以我可以学到一些东西。

与此同时,我认为有两种主要方法:

解析列表,转换和重新插入

一种明显,优雅的方法是将CSV文件解析为列表列表(行列表,每列都是列列表),进行转换,delete-region整个缓冲区,以及插回结果。

可能你可以使用MELPA的parse-csvdashes软件包 - 前者用于CSV样式解析,后者用于partition函数。或者您可以编写定制代码来执行此操作。

逐行

对于较大的文件,上述方法可能会很慢。列表列表很大,需要大量垃圾回收。

将Emacs视为缓冲区操作库,恰好有一个文本编辑器。通常,直接在缓冲区上聚会更快,特别是对于这种类型的线性逐行转换。本着这种精神:

(defun my/stack-overflow-33646950 ()
  "Transform the current buffer for http://stackoverflow.com/questions/33646950/how-to-increment-and-keep-previous-increments-when-values-are-the-same-in-emacs"
  (interactive)
  (let ((prev-y nil)
        (band   0))
    (goto-char (point-min))
    (while (not (eobp))
      (let* ((bol  (save-excursion (beginning-of-line) (point)))
             (eol  (save-excursion (end-of-line) (point)))
             (line (buffer-substring-no-properties bol eol)))
        (pcase (mapcar #'string-to-number
                       (split-string line "," t "[ \t]+"))
          (`(,x ,y)
           (unless (eq y prev-y)
             (setq prev-y y)
             (setq band (1+ band)))
           (delete-region bol eol)
           (insert (format "%s,%s" x band))
           (goto-char (1+ eol)))
          (_ (user-error "expected <number>,<number> but found \"%s\"" line)))))))

答案 1 :(得分:1)

Regexp替换:

  • 启动regexp替换C-M-%
  • 搜索字符串\([0-9]+\)$,它与最后一个数字匹配并捕获它。
  • 替换字符串\,(format " %d" (- \#1 38)),它将捕获的组转换为整数(\#1),减去38,并格式化为小数。 \,是从lisp代码构建替换字符串的神奇之处。
  • <space>一次更换一个,或!替换所有。您可以缩小缓冲区或将区域设置为仅适用于缓冲区的子集。

还有很多其他方法可以解决这个问题,但是它们需要额外的配置和/或安装包(例如,看看键盘宏和邪恶数字)。

如果文件很大(如1000行或更大),请使用Python或其他一些脚本语言。

答案 2 :(得分:0)

Python解决方案#1:如果您的数据适合RAM并且您喜欢numpy:

import numpy
data = numpy.loadtxt('data.txt', delimiter=',')
data[:,1] -= data[0,1]-1                                
numpy.savetxt('output.txt', data, delimiter=', ', fmt='%d')

Python解决方案#2:如果您更喜欢逐行文本操作:

first = None
for line in open('data.txt'):
    v0, v1 = line.split(',')
    if first is None:
        first = int(v1)
    print '%s, %d' % (v0, int(v1)-first+1)