我有两列值,第二列从特定值开始,我希望第二列以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
答案 0 :(得分:2)
我很想看到其他答案,所以我可以学到一些东西。
与此同时,我认为有两种主要方法:
一种明显,优雅的方法是将CSV文件解析为列表列表(行列表,每列都是列列表),进行转换,delete-region
整个缓冲区,以及插回结果。
可能你可以使用MELPA的parse-csv
和dashes
软件包 - 前者用于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替换:
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)