返回列表 发帖

[文本处理] [已解决]如何使用文本工具进行整行去重、首列排序

本帖最后由 77七 于 2023-6-5 13:25 编辑

请教各位老师、大佬:
如何使用gawk或sed或grep等专业文本处理工具  对文本进行以下处理
1.按整行进行去重(如 第一行、第三行相同,则去除第三行);
2.仅对第一列进行排序(第一列相同的所有行保持原有的上下顺序)

文本 编码ansi 数万行 含有多列(空格分隔) 含有数字、汉字、符号,不含引号、叹号;
批处理 编码ansi
如 1.txt
江苏 盐城
江苏 苏州 宿迁
浙江 杭州
江苏 南京
江苏 盐城
江苏 苏州
安徽 合肥COPY
20230605 13:25 重新修改 1.txt
浙江 杭州
江苏 盐城
江苏 苏州 宿迁
江苏 南京
江苏 盐城
江苏 苏州
安徽 合肥COPY


希望几秒内处理完成,结果直接覆盖,或者得到 2.txt
2.txt
20230605 13:19 修改
utf-8编码的1.txt sort排序及手动处理结果:
江苏 盐城
江苏 苏州 宿迁
江苏 南京
江苏 苏州
浙江 杭州
安徽 合肥COPY

ansi编码的1.txt sort排序及手动处理结果:
安徽 合肥
江苏 盐城
江苏 苏州 宿迁
江苏 南京
江苏 苏州
浙江 杭州COPY

如上,排序了江苏、浙江、安徽;去除了重复行(第二个 江苏 盐城);
江苏 盐城;江苏 苏州 宿迁;江苏 南京;江苏 苏州; 的上下顺序不变。

谢谢!
补充说明:
上述2.txt结果是我错误的对utf-8编码的1.txt经过sort排序后,手动加工形成的。
像江苏、浙江、安徽的上下顺序,不影响实际使用。
1

评分人数

    • Batcher: 感谢给帖子标题标注[已解决]字样PB + 2
bat小白,请多指教!谢谢!

本帖最后由 buyiyang 于 2023-6-3 21:14 编辑
gawk "{a[$1][FNR]=$0;if (!($1 in order)) {order[length(order) + 1] = $1}} END {for (i = 1; i <= length(order); i++) {n = asorti(a[order[i]], b);for (j = 1; j <= n;j++) {if (!(a[order[i]][b[j]] in s)) {print a[order[i]][b[j]];s[a[order[i]][b[j]]] = 1}}}}" 1.txt > 2.txtCOPY
1

评分人数

    • 77七: 乐于助人技术 + 1

TOP

回复 2# buyiyang


   谢谢大佬,测试正确,非常感谢!
bat小白,请多指教!谢谢!

TOP

试了试,纯P也能处理,确实要慢许多。

TOP

gawk "{if(!c[$0]++){if(!f[$1]++)b[++n]=$1;a[$1][++m[$1]]=$0}}END{for(i=1;i<=n;i++)for(j=1;j<=m[b[i]];j++)print(a[b[i]][j])}" 1.txt >2.txtCOPY
1

评分人数

    • 77七: 乐于助人技术 + 1

TOP

回复 4# qixiaobin0715


   感谢大佬关注!因为文本是不断变化的,又是几万行,经常需要处理,就没有考虑纯批处理。现在试了一下,我发现了一个知识点,批处理的sort命令 对 1楼的文本保存为ansi 和utf-8 的排序结果居然是不一样的。
bat小白,请多指教!谢谢!

TOP

回复 5# terse


   感谢大佬帮助!测试结果正确。
bat小白,请多指教!谢谢!

TOP

本帖最后由 qixiaobin0715 于 2023-6-5 09:36 编辑

回复 6# 77七
想到第三方也基本上隐性的使用临时文件,如果用纯P的话,在特定位置使用临时文件是不是效率要高一些,因为没有测试文本测试,结果不知如何:
@echo off
(for /f "tokens=1*" %%i in (1.txt) do (
    if not defined _"%%i" (
        set _"%%i"=true
        findstr /lb "%%i " 1.txt>temp
        for /f "delims=" %%a in (temp) do (
            if not defined _"%%a" (
                set _"%%a"=true
                echo,%%a
            )
        )
    )
))>2.txt
del temp
pauseCOPY

TOP

本帖最后由 77七 于 2023-6-5 12:17 编辑

回复 8# qixiaobin0715


   谢谢大佬,使用 http://www.bathome.net/redirect.php?goto=findpost&;ptid=12081&pid=76757 测试代码用时53分钟。这个耗时代码可能有点问题,结果少了一个0。文本有5万3千行。
bat小白,请多指教!谢谢!

TOP

本帖最后由 77七 于 2023-6-5 17:12 编辑

回复 2# buyiyang


   大佬,能不能帮我再修改一下,实际使用中,我发现脚本没有对首列进行排序,仅仅是将首列相同的行排在了一起。
1楼的2.txt的结果,是我错误使用批处理的sort命令,对utf-8编码的1.txt排序了江苏、浙江、安徽后,手动调整第二列及以后列 顺序后形成的,和1.txt中的江苏、浙江、安徽行首次出现的上下顺序相同,属于巧合。如果sort ansi编码的1.txt文本,安徽是排在第一个的。
可能让您造成了一定程度的误解,不好意思。
我希望它们有某一种顺序就行,就像批处理中的 sort 排序utf-8 或ansi ,正逆序也都可以。


可能用数字描述更准确,实际使用中首列数字、汉字、字母都有。以下仅演示排序。
处理前
2 3
1 5
2 1
1 8
3 0
处理后
1 5
1 8
2 3
2 1
3 0COPY

谢谢大佬,terse大佬已经帮助我解决了问题。
bat小白,请多指教!谢谢!

TOP


用变量是否已被定义来判断目标数据‘有无’,的确是纯P的一款利器,但受限于cmd总内存卡在64MB,有时可能也会打爆cmd,例如用其对应数万+行数据时... 参见》http://www.bathome.net/thread-29022-1-1.html

本帖的另一趣点是文本行去重。看过国内外有关网站的很多老帖,用纯P解决文本行去重的经典招数,还是那个 awk 句式,简洁漂亮高效!
awk.exe "!existLines[$0]++" inF.txt>outF.txt
虽然其算法用纯P或vbs或js均可实现,但动态编码与静态编码之比的运行效率显然是立见高下...

TOP

回复 11# aloha20200628


   谢谢老师指点!gawk去重确实很好用,但是我主要是想解决首列排序的问题。
bat小白,请多指教!谢谢!

TOP

如果使用gawk去重,使用批处理排序首列,我的思路是这样的,将行号添加到第二列前面,然后sort “第一列行号第二列”,能排序首列,并且不改变首列相同行的上下顺序。只是一直 set 效率非常低。
@echo off
gawk "!existLines[$0]++" 1.txt>2.txt
setlocal enabledelayedexpansion
for /f "tokens=1-2* delims=: " %%a in ('type "2.txt" ^|findstr /n .*') do (
echo %%a
set n=00000000%%a
set "#%%b#!n:~-7!=%%c"
)
(for /f "tokens=1-2* delims=#=" %%a in ('set # ^|sort') do (
echo %%a %%c
))>3.txt
endlocal
pauseCOPY
bat小白,请多指教!谢谢!

TOP

回复 9# 77七
纯P看来是不行。建议发一个测试的文本,以供对此类问题感兴趣的同仁练习用。

TOP

回复 14# qixiaobin0715


   实际文本也很简单,就两三列简短的数据,使用随机数可以创建一个类似的。
@echo off
setlocal enabledelayedexpansion
(for /l %%l in (1,1,50000) do (
set n=!random!
set m=!random!
echo !n! !m!
))>1.txtCOPY
bat小白,请多指教!谢谢!

TOP

返回列表