Board logo

标题: 【完结】50元求批处理——汉字信息提取 [打印本页]

作者: lxh623    时间: 2020-11-17 11:04     标题: 【完结】50元求批处理——汉字信息提取

本帖最后由 lxh623 于 2020-11-20 07:42 编辑

文本a是如下:
CB30597        [灬亠口├〡兀木]
方括号里面有些解析部件。有些可能有unicode码,有些没有。
文本IDS,如下:
U+24410        𤐐        ⿰火詹
文本dump,如下:
u6b0b   | 99:0:0:2:0:160:200:u6728-01$99:0:0:59:0:197:200:dkw-23747@1
我的想法是:
把方括号里面的解析部件,从文本IDS提取unicode码,在文本dump搜索,同时含有所有的话,(没有unicode码的,忽略)把文本a那一行写入文本b,后面加上制表符+文本dump中制表符前面的内容。多个可能,就写几行。
文本IDS中的unicode码,我也可以处理到与文本dump一样。

所有文本编码是UTF8。

谢谢!
作者: zaqmlp    时间: 2020-11-17 11:22

举例说明下处理前后的效果并打包文件发网盘
作者: lxh623    时间: 2020-11-17 15:33

回复 2# zaqmlp
大致处理之后,上传了。dump想存UTF8,怎么也保存不了。
链接:https://pan.baidu.com/s/1pc2as9CPfpTwejYLwd1Vcw
提取码:q35z

谢谢!
作者: zaqmlp    时间: 2020-11-17 17:20

以这几个为例,最后结果是什么
CB17093        [、、]
CB32631        [亠二]
CB33987        [彡同]
CB29324        [忄日一]
作者: ivor    时间: 2020-11-17 20:11

我的想法是:
把方括号里面的解析部件,从文本IDS提取unicode码,在文本dump搜索,同时含有所有的话,(没有unicode码的,忽略)把文本a那一行写入文本b,后面加上制表符+文本dump中制表符前面的内容。多个可能,就写几行。

dump制表符前面存在重复,如果全部检索不能使用字典效率会很低。
作者: WHY    时间: 2020-11-17 20:18

本帖最后由 WHY 于 2020-11-17 20:25 编辑

PowerShell 脚本,保存为 E:\Test\大藏经解析\Test.ps1
运行方法:
1. 在cmd命令提示符下,输入 PowerShell -exec Bypass -file "E:\Test\大藏经解析\Test.ps1"
2.或者,右键单击脚本,选择"使用 PowerShell 运行"
试试吧。
  1. $file1 = 'E:\Test\大藏经解析\IDS.txt';
  2. $file2 = 'E:\Test\大藏经解析\dump.txt';
  3. $file3 = 'E:\Test\大藏经解析\a.txt';
  4. $file4 = 'E:\Test\大藏经解析\b.txt';
  5. $hash1 = @{};
  6. $arr  = [IO.File]::ReadAllLines($file1) -match '^u';
  7. $count = $arr.Count;
  8. for( $i=0; $i -lt $count; $i++ ){
  9.     $m = $arr[$i].Trim() -split '\s+';
  10.     if( !$hash1.ContainsKey($m[1]) ){ $hash1[$m[1]] = $m[0]; }
  11. }
  12. $hash2 = @{};
  13. $arr  = [IO.File]::ReadAllLines($file2) -match '^u';
  14. $count = $arr.Count;
  15. for( $i=0; $i -lt $count; $i++ ){
  16.     $m = $arr[$i].Trim() -split '\s+';
  17.     if( !$hash2.ContainsKey($m[0]) ){ $hash2[$m[0]] = 1; }
  18. }
  19. $arr  = [IO.File]::ReadAllLines($file3) -match '^CB';
  20. $count = $arr.Count;
  21. $out = for( $i=0; $i -lt $count; $i++ ){
  22.     [char[]]$chs = ($arr[$i] -split '[\[\]]')[1];   #匹配中文字符
  23.     [Collections.ArrayList]$a = @();
  24.     for($j=0; $j -lt $chs.Count; $j++) {
  25.         $s = '' + $chs[$j];                 #char转string
  26.         if( !$hash1.ContainsKey($s) ){ continue; }
  27.         $key = $hash1[$s];
  28.         if( $hash2.ContainsKey($key) ){ [void]$a.Add($key); }
  29.     }
  30.     if( $a.Count -eq $chs.Count ){
  31.         $arr[$i] + "`t" + ($a -join "`t");
  32.     }
  33. }
  34. [IO.File]::WriteAllLines($file4, $out);
  35. echo 'Done';
  36. [Console]::ReadKey();
复制代码

作者: lxh623    时间: 2020-11-18 08:22

本帖最后由 lxh623 于 2020-11-18 10:10 编辑

回复 6# WHY
CB33973        [十后]        u5341        u540e
我的意思是在dump找到同时含有这两个或者几个Unicode码的行,把前面写到]+制表符后面。【这个例子好像没有】

发现一个问题,原件u3013开头的行,可以删除。

CB13270        [刂耳]        u5202        u8033
这个有结果。但是,出来几个u205dc、u5235、u3013、u265ff、u350c、u8069。去掉u3013,还有五个。
所以,要是用以搜索的有n个unicode码,dump行里面就最好限定n+1个unicode码,可能更好。
或者,出来十个,都写上。自己再来删除重复。

结果样式:(这个都可以,都需要自己调整。)
CB13270        [刂耳]        u5235
CB13270        [刂耳]        刵

谢谢!
作者: WHY    时间: 2020-11-18 20:21

本帖最后由 WHY 于 2020-11-19 10:38 编辑

回复 7# lxh623


    这样的话,a.txt的每一行都要和dump.txt的每一行进行比较,行数太多,效率肯定不会高,你试试吧。
  1. $file1 = 'E:\Test\大藏经解析\IDS.txt';
  2. $file2 = 'E:\Test\大藏经解析\dump.txt';
  3. $file3 = 'E:\Test\大藏经解析\a.txt';
  4. $file4 = 'E:\Test\大藏经解析\b.txt';
  5. #遍历 IDS.txt 每一行,加入字典
  6. $Dic1 = New-Object 'Collections.Generic.Dictionary[string, string]';
  7. $Dic3 = New-Object 'Collections.Generic.Dictionary[string, string]';
  8. $arr  = [IO.File]::ReadAllLines($file1) -match '^u';
  9. $count = $arr.Count;
  10. for( $i=0; $i -lt $count; $i++ ){
  11.     $a = $arr[$i].Trim().Split("`t ", 2, 'RemoveEmptyEntries');   #分割成2列
  12.     if( !$Dic1.ContainsKey($a[1]) ){
  13.         $Dic1.Add($a[1], $a[0]);      #Dic1:key=第2列中文字符,value=第1列unicode码
  14.     }
  15.     if( !$Dic3.ContainsKey($a[0]) ){
  16.         $Dic3.Add($a[0], $a[1]);      #Dic3:key=第1列unicode码,value=第2列中文字符
  17.     }
  18. }
  19. #遍历 dump.txt 每一行,加入字典
  20. $Dic2 = New-Object 'Collections.Generic.Dictionary[string, string]';
  21. $arr  = [IO.File]::ReadAllLines($file2) -match '^u[0-9a-f]+\s+.*u[0-9a-f]+' -notMatch '^u3013\s';  #去掉u3013开头的行
  22. $count = $arr.Count;
  23. for( $i=0; $i -lt $count; $i++ ){
  24.     $a = $arr[$i].Trim().Split("`t ", 2, 'RemoveEmptyEntries');   #分割成2列
  25.     $k = forEach( $m In [regex]::Matches($a[1], '(?i)u[0-9a-f]+') ){
  26.         $m.Groups[0].Value;
  27.     }
  28.     $key = $k -join ' ';
  29.     if( !$Dic2.ContainsKey($key) ){
  30.         $Dic2.Add($key, $a[0]);       #Dic2:key=第2列的多个unicode码,value=第1列的unicode码
  31.     }
  32. }
  33. #遍历 a.txt 每一行,如果在一行中同时匹配多个unicode码,写入b.txt
  34. $fsw = New-Object System.IO.StreamWriter($file4, $false, [Text.Encoding]::UTF8);
  35. $arr = [IO.File]::ReadAllLines($file3) -match '^CB';
  36. $count = $arr.Count;
  37. for( $i=0; $i -lt $count; $i++ ){
  38.     [char[]]$chs = $arr[$i].Split('[]')[1];   #a.txt每一行的中文字符
  39.     [Collections.ArrayList]$a = @();
  40.     for( $j=0; $j -lt $chs.Count; $j++ ){
  41.         $s = '' + $chs[$j];                   #char转string
  42.         if( $Dic1.ContainsKey($s) ){
  43.             [void]$a.Add( '(?=.*' + $Dic1[$s] + '\b)' );
  44.         } else { break; }
  45.     }
  46.     if( $a.Count -ne $chs.Count ){ continue; }
  47.     $h = @{};
  48.     $reg = $a -join '';    #正则,同时匹配多个字符串
  49.     forEach( $key In ($Dic2.Keys -match $reg) ){
  50.         if( !$h.ContainsKey($Dic2[$key]) ){
  51.             $h[$Dic2[$key]] = 1;              #哈希表赋值,用来去重复,key=Dump.txt的第一列
  52.         }
  53.     }
  54.     if( $h.Count -eq 0 ){ continue; }
  55.     $s = $h.Keys -join "`t";
  56.     $s = [regex]::Replace($s, '\S+', {param($m); $m.Value + '-' + $Dic3[$m.Value]});
  57.     echo( $arr[$i] + "`t" + $s );
  58.     $fsw.WriteLine( $arr[$i] + "`t" + $s );
  59.     $fsw.Flush();
  60. }
  61. $fsw.Dispose();
  62. echo 'Done';
  63. [Console]::ReadKey();
复制代码

作者: zaqmlp    时间: 2020-11-18 20:58

本帖最后由 zaqmlp 于 2020-11-19 13:52 编辑

bat
  1. <# :
  2. cls
  3. @echo off
  4. cd /d "%~dp0"
  5. powershell -NoProfile -ExecutionPolicy bypass "Invoke-Command -ScriptBlock ([ScriptBlock]::Create([IO.File]::ReadAllText('%~f0',[Text.Encoding]::GetEncoding('GB2312')))) -Args '%~f0'"
  6. pause
  7. exit
  8. #>
  9. $file1=".\a.txt";
  10. $file2=".\IDS.txt";
  11. $file3=".\dump.txt";
  12. $file4=".\结果.txt";
  13. $self=get-item -liter $args[0];
  14. $path=$self.Directory.FullName;
  15. $file1=$file1 -replace '^\.',$path;
  16. $file2=$file2 -replace '^\.',$path;
  17. $file3=$file3 -replace '^\.',$path;
  18. $file4=$file4 -replace '^\.',$path;
  19. if(-not (test-path -liter $file1)){write-host ('"'+$file1+'" not found');exit;};
  20. if(-not (test-path -liter $file2)){write-host ('"'+$file2+'" not found');exit;};
  21. if(-not (test-path -liter $file3)){write-host ('"'+$file3+'" not found');exit;};
  22. $enc=[Text.Encoding]::UTF8;
  23. $text1=[IO.File]::ReadAllLines($file1, $enc);
  24. $text2=[IO.File]::ReadAllLines($file2, $enc);
  25. $text3=[IO.File]::ReadAllLines($file3, $enc);
  26. write-host 'Laoding……';
  27. $dic1=New-Object 'System.Collections.Generic.Dictionary[string,string]';
  28. $dic2=New-Object 'System.Collections.Generic.Dictionary[string,string]';
  29. for($i=0;$i -lt $text2.count;$i++){
  30.     $line=$text2[$i].trim() -split '\s',2;
  31.     if(-not $dic1.ContainsKey($line[1])){$dic1.add($line[1], $line[0])};
  32.     if(-not $dic2.ContainsKey($line[0])){$dic2.add($line[0], $line[1])};
  33. };
  34. $dic3=New-Object 'System.Collections.Generic.Dictionary[string,object]';
  35. for($i=0;$i -lt $text3.count;$i++){
  36.     $line=$text3[$i].trimstart() -split '\s',2;
  37.     $m=[regex]::matches($line[1], '(?i)u[\da-f]+');
  38.     if($m.count -ge 1){
  39.         [System.Collections.ArrayList]$crr=@();
  40.         foreach($k in $m){
  41.             [void]$crr.add($k.groups[0].value);
  42.         };
  43.         $drr=@($crr|sort);
  44.         $tmpline=$drr -join ':';
  45.         if(-not $dic3.ContainsKey($tmpline)){
  46.             [System.Collections.ArrayList]$key=@();
  47.             $dic3.add($tmpline, $key);
  48.         };
  49.         if($dic3[$tmpline] -notcontains $line[0]){
  50.             [void]$dic3[$tmpline].add($line[0]);
  51.         };
  52.     };
  53. };
  54. write-host 'Searching……';
  55. $fs=New-Object System.IO.FileStream($file4, [System.IO.FileMode]::Create);
  56. $sw=New-Object System.IO.StreamWriter($fs, $enc);
  57. for($i=0;$i -lt $text1.count;$i++){
  58.     $line=$text1[$i].trim() -split '\s',2;
  59.     $m=[regex]::matches($line[1].trim('[]'),'[\ud800-\udbff][\udc00-\udfff]|[\u0000-\uffff]');
  60.     [System.Collections.ArrayList]$arr=@();
  61.     if($m.count -ge 1){
  62.         foreach($k in $m){
  63.             if($dic1.ContainsKey($k.groups[0].value)){
  64.                 [void]$arr.add($dic1[$k.groups[0].value]);
  65.             };
  66.         };
  67.     };
  68.     $line=$text1[$i];
  69.     if($arr.count -ge 1){
  70.         $err=@($arr|sort);
  71.         $tmpline=$err -join ':';$tmpline
  72.         if($dic3.ContainsKey($tmpline)){
  73.             for($j=0;$j -lt $dic3[$tmpline].count;$j++){
  74.                 if($dic2.ContainsKey($dic3[$tmpline][$j])){
  75.                     $line+=(' '+$dic3[$tmpline][$j]+'('+$dic2[$dic3[$tmpline][$j]]+')')
  76.                 };
  77.             };
  78.         };
  79.     };
  80.     write-host $line;
  81.     $sw.WriteLine($line);
  82.     $sw.Flush();
  83. };
  84. $sw.Close();
  85. $fs.Close();
复制代码

作者: lxh623    时间: 2020-11-19 10:24

很奇怪,有一个字,两位都没有找到。我手动筛选,找到了。
CB33086        [宀乙] 察
作者: lxh623    时间: 2020-11-19 10:24

帐结了,感谢两位。
作者: zaqmlp    时间: 2020-11-19 13:51

回复 10# lxh623
已修改
CB33086 [宀乙] u5be7(寧) u5bdf(察)
作者: WHY    时间: 2020-11-19 20:55

200多万行数的数据,经过筛选后117万多行,win10实测,正则匹配同时包含多个字符串的行没有for循环来的快。
思路同8楼,改成for循环。
  1. $file1 = 'E:\Test\大藏经解析\IDS.txt';
  2. $file2 = 'E:\Test\大藏经解析\dump.txt';
  3. $file3 = 'E:\Test\大藏经解析\a.txt';
  4. $file4 = 'E:\Test\大藏经解析\b.txt';
  5. #遍历 IDS.txt 每一行,加入字典
  6. $Dic1 = New-Object 'Collections.Generic.Dictionary[string, string]';
  7. $Dic3 = New-Object 'Collections.Generic.Dictionary[string, string]';
  8. $arr  = [IO.File]::ReadAllLines($file1) -match '^u';
  9. $count = $arr.Count;
  10. for( $i=0; $i -lt $count; $i++ ){
  11.     $a = $arr[$i].Trim().Split("`t ", 2, 'RemoveEmptyEntries');   #分割成2列
  12.     if( !$Dic1.ContainsKey($a[1]) ){
  13.         $Dic1.Add($a[1], $a[0]);      #Dic1:key=第2列中文字符,value=第1列unicode码
  14.     }
  15.     if( !$Dic3.ContainsKey($a[0]) ){
  16.         $Dic3.Add($a[0], $a[1]);      #Dic3:key=第1列unicode码,value=第2列中文字符
  17.     }
  18. }
  19. #遍历 dump.txt 每一行,加入字典
  20. $Dic2 = New-Object 'Collections.Generic.Dictionary[string, string]';
  21. $arr  = [IO.File]::ReadAllLines($file2) -match '^u[0-9a-f]+\s+.*u[0-9a-f]+' -notMatch '^u3013\s';  #去掉u3013开头的行
  22. $count = $arr.Count;
  23. for( $i=0; $i -lt $count; $i++ ){
  24.     $a = $arr[$i].Trim().Split("`t ", 2, 'RemoveEmptyEntries');   #分割成2列
  25.     $k = forEach( $m In [regex]::Matches($a[1], '(?i)u[0-9a-f]+') ){
  26.         $m.Groups[0].Value;
  27.     }
  28.     $key = $k -join ' ';
  29.     if( !$Dic2.ContainsKey($key) ){
  30.         $Dic2.Add($key, $a[0]);       #Dic2:key=第2列的多个unicode码,value=第1列的unicode码
  31.     }
  32. }
  33. #遍历 a.txt 每一行,如果在一行中同时匹配多个unicode码,写入b.txt
  34. $fsw = New-Object System.IO.StreamWriter($file4, $false, [Text.Encoding]::UTF8);
  35. $arr = [IO.File]::ReadAllLines($file3) -match '^CB';
  36. $count = $arr.Count;
  37. for( $i=0; $i -lt $count; $i++ ){
  38.     [char[]]$chs = $arr[$i].Split('[]')[1];   #a.txt每一行的中文字符
  39.     [Collections.ArrayList]$a = @();          #数组a,存放中文字符对应的unicode码
  40.     for( $j=0; $j -lt $chs.Count; $j++ ){
  41.         $s = '' + $chs[$j];                   #char转string
  42.         if( $Dic1.ContainsKey($s) ){
  43.             [void]$a.Add( $Dic1[$s] );
  44.         } else { break; }
  45.     }
  46.     if( $a.Count -ne $chs.Count ){ continue; }
  47.     $h = @{};                                 #哈希表,存放Dump.txt的第一列unicode码
  48.     forEach( $key In $Dic2.Keys ){
  49.         if( $h.ContainsKey($Dic2[$key]) ){ continue; }
  50.         $flag = $true;
  51.         for( $j=0; $j -lt $a.Count; $j++ ){
  52.             if( $key.indexOf($a[$j]) -lt 0 ){
  53.                 $flag = $false;
  54.                 break;
  55.             }
  56.         }
  57.         if( $flag ){ $h[$Dic2[$key]] = $true; }
  58.     }
  59.     if( $h.Count -eq 0 ){ continue; }
  60.     $s = $h.Keys -join "`t";
  61.     $s = [regex]::Replace($s, '\S+', {param($m); $m.Value + '-' + $Dic3[$m.Value]});
  62.     echo( $arr[$i] + "`t" + $s );
  63.     $fsw.WriteLine( $arr[$i] + "`t" + $s );
  64.     $fsw.Flush();
  65. }
  66. $fsw.Dispose();
  67. echo 'Done';
  68. [Console]::ReadKey();
复制代码

作者: WHY    时间: 2020-11-21 15:44

仔细想想好像不对,8楼正则为啥比for循环还慢?
因为漏掉了一个限定符^,造成过度回溯。
46行改成:
  1. [void]$a.Add( '(?=^.*' + $Dic1[$s] + '\b)' );
复制代码
终于正常了。MARK备查。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2