[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[技术讨论] 關於濫用正則解析 xml 文件

本帖最后由 uhjjhjff11d 于 2019-11-16 01:53 编辑


  • 處理 xml api 顯然比正則可靠
  • xml character data 裡面的內容依照協議是不由解析器解析的,也就是說我們可以在裡面寫其他 xml,那些代碼完全忽視了這一點
  • 對於違反 xml 協議的操作,那些代碼沒有提供任何的檢查。xml 庫會拒絕一些不當的操作,這是犧牲速度換穩定,而不是庫代碼寫的爛,或者正則多麼萬能。
  • xml 庫只對 xml 文件負責,正則對所有可能的文本負責,以常識來判斷,提速 xml 庫更容易實現。
  • 修改標題:"對論壇的建議,還有關於濫用正則" -> "關於濫用正則解析 xml 文件"
  • 我從來沒說要什麼完美的代碼,那些帖子裡面使用正則的代碼確實錯誤的操作到了表示結構的部分。那些代碼連操作結構的能力都沒有,我不認為出現 bug 的原因是因為對方需求不斷的變化。
  • 我喜歡不斷的修改文章,為了避免有人覺得我逃避質疑,重述我說過的話,加上一些補充。
    錯誤的需求:代碼沒人想看,何必混倄,而且為什麼不用現成的工具。
    錯誤的技術/沒有生產力的代碼:交付代碼,把底層邏輯和上層的操作混倄,對方看不懂,看懂了也不好改。交付產品出 bug,這樣不是用了錯誤的技術嗎?
    邪道:相對正道就是邪道


相關的帖子

求PowerShell批量计算文本指定数值后替换原值
[已解决]20元修改归类并正则匹配所有属性值
[文本处理] 怎样批量计算后替换文本内容
100元人民币 求bat或Powershell处理文本内容【已解决】
5

评分人数

本帖最后由 uhjjhjff11d 于 2019-11-14 17:28 编辑

回复 22# WHY
29 樓的圖片顯示他手中的文檔是 xml沒錯。至於有沒有被他的正則匹配替換操作引入錯誤的內容,我就不知道了。其它人拿了錢,給出的代碼到了好幾版之後還是有 bug,那你要我說正則很適合搞 xml,我還真不認同。
100元人民币 求bat或Powershell处理文本内容【已解决】

  • 20 樓 26樓代碼更新。29樓 bug
  • 31 樓代碼更新,32樓 bug
  • 40 樓代碼更新,41 樓 bug,導致手機無法開機。(他不會在虛擬機上面測試嗎?)
  • 47 樓的回覆......他以為變量換名就是混倄器了......100元的代碼 vs Google 開源 project
  • 52 樓 56 樓代碼更新,59 樓 看起來匹配不能處理所有的更名
  • 60 樓代碼更新,63 樓 他還在想什麼 改名称为A~ZZZZ之间,本來就不應該這樣處理的,所以我說其他人也是誤導他居多

37樓就提到了應該直接用 api

43樓也提到了直接用 api

之前看到這些回覆就不會發帖了,因為我根本不想讀下面許多濫用正則,到處是 bug 的代碼。

TOP

本帖最后由 uhjjhjff11d 于 2019-11-9 11:13 编辑

回复 28# WHY
我猜你很会写 PowerShell 脚本,贴一个完美版让大家都学习一下吧。

你猜錯了,我不是程序員,也不是編程高手。

所谓的 bug 你多站在脚本编写者的角度看看,多数楼层的答案在需求不再变化的时候已经满足了要求,这算bug吗?

代碼把不是變量的東西也替換掉了
如果變量後面有數字就失效

回复 7# WHY 写的太棒了
有个小问题可以处理下吗 就是其中有数组时共用同一个名称是要替换成同名称的 虽然也替换成同名了 单生成的XTX文本 可以被读取 但部分功能不在
说明 混编时还是有问题


其中一段代碼。
  1. @echo off
  2. PowerShell "$h=@{};$s=[regex]::Replace([IO.File]::ReadAllText('a.txt',[Text.Encoding]::Default),'(?<=\bname=\")[^^\"]+(?=\")',{param($m);$a=$m.Value;if(!$h.ContainsKey($a)){$x=[Math]::floor($global:n/26);if(!$x){$c=''}else{$c=[char](64+[int]$x)};$h[$a]=$c+[char](65+$global:n++%%26)};$h[$a]});$s=[regex]::Replace($s, '(?^<=\")[^\"@#]*[@#][^^\"]+(?=\")',{param($m);$a=$m.Value;forEach($k In $h.Keys){$a=$a.Replace('@'+$k,'@'+$h[$k]).Replace('#'+$k,'#'+$h[$k])};$a});sc b.txt -Value $s -Enc utf8"
  3. pause
复制代码

TOP

本帖最后由 uhjjhjff11d 于 2019-11-14 17:34 编辑

回复 33# WHY
还是那句话:能够解决问题的方法,不喜欢你可以不用,甚至不相信它,但不要轻易指责它。

回复 32# WHY
拿不出完美的、比正则更好的解决方法,又极力指责“滥用正则”、“邪道”、“错误的技术”


用庫修改所有 type 節點的範例,大家自行比對哪一個好讀好改。
  1. $xmlfile = 'C:\Users\username\Documents\sample.xml'
  2. [XML]$xmlcontent = Get-Content $xmlfile
  3. function hash($string) {
  4.     new-object System.Security.Cryptography.SHA256Managed | ForEach-Object { $_.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($string)) } | ForEach-Object { $all += $_.ToString("x2") }
  5.     "varhead" + $all
  6. }
  7. $xmlcontent.SelectNodes("//*") | ForEach-Object {
  8.     if (-not ($_.Type -eq $null)){
  9.         $_.Type = hash($_.Type)
  10.     } else {
  11.         Write-Output "pass"
  12.     }
  13. }
  14. $xmlcontent.Save(".\sample2.xml")
复制代码
xml 範例(來自網絡)
  1. <?xml version="1.0"?>
  2. <PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
  3.   <Address Type="Shipping">
  4.     <Name>Ellen Adams</Name>
  5.     <Street>123 Maple Street</Street>
  6.     <City>Mill Valley</City>
  7.     <State>CA</State>
  8.     <Zip>10999</Zip>
  9.     <Country>USA</Country>
  10.   </Address>
  11.   <Address Type="Billing">
  12.     <Name>Tai Yee</Name>
  13.     <Street>8 Oak Avenue</Street>
  14.     <City>Old Town</City>
  15.     <State>PA</State>
  16.     <Zip>95819</Zip>
  17.     <Country>USA</Country>
  18.   </Address>
  19.   <DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
  20.   <Items>
  21.     <Item PartNumber="872-AA">
  22.       <ProductName>Lawnmower</ProductName>
  23.       <Quantity>1</Quantity>
  24.       <USPrice>148.95</USPrice>
  25.       <Comment>Confirm this is electric</Comment>
  26.     </Item>
  27.     <Item PartNumber="926-AA">
  28.       <ProductName>Baby Monitor</ProductName>
  29.       <Quantity>2</Quantity>
  30.       <USPrice>39.98</USPrice>
  31.       <ShipDate>1999-05-21</ShipDate>
  32.     </Item>
  33.   </Items>
  34. </PurchaseOrder>
复制代码


[url=http://bbs.bathome.net/redirect.php?goto=findpost&ptid=52856&pid=220490]60樓的代碼
  1. goto :ansi
  2. rem UTF-8 编码支持
  3. chcp 65001
  4. cls
  5. :ansi
  6. @echo off
  7. set /p "strFile=请拖入处理文本:"
  8. setlocal enabledelayedexpansion
  9. if not exist !strFile! (
  10. echo;"!strFile!" 文件不找不到!!
  11. exit /b
  12. )
  13. endlocal
  14. rem 定义用于命名的字符表
  15. set ASC=ABCDEFGHIJKLMNOPQRSTUVWXYZ
  16. set n=0
  17. rem 定义可用于命名的字符表
  18. set tab="." [ + - ^"
  19. rem 例外情况定义
  20. set exception=Extra Button
  21. set z=
  22. set o=
  23. setlocal enabledelayedexpansion
  24. for /f "tokens=1* delims==" %%a in (!strFile!) do (
  25. for /f "tokens=1,2 delims= " %%K in ("1 !z!") do (
  26. endlocal
  27. set z=%%L
  28. set s1=%%a
  29. set s2=%%b
  30. setlocal enabledelayedexpansion
  31. )
  32. if defined z for %%k in (%exception%) do (
  33. if "#!s1:</%%k>=!" neq "#!s1!" (
  34. set z=!z:~1!
  35. )
  36. )
  37. for %%k in (%exception%) do (
  38. if "!s1:<%%k=!" neq "!s1!" (
  39. if "#!s2:/>=!" equ "#!s2!" (
  40. set z=!z!y
  41. ) else (
  42. set o=o
  43. )
  44. )
  45. )
  46. if "!o!!z!!s1:~-5!" equ " name" (
  47. set s3=!s2:^"= !
  48. for /f "tokens=1 delims= " %%c in ("!s3!") do (
  49. if not defined #%%~c (
  50. call :getn !n! ss
  51. set sa=%%~c
  52. rem 保留"."后面的尾巴
  53. if "!sa:.=!" neq "!sa!" set ss=!ss!.!sa:*.=!
  54. for /f "tokens=1,2,3 delims= " %%x in ("!n! !ss! !z!") do (
  55. endlocal
  56. set $%%x=%%y囧%%~c
  57. set #%%~c=%%y
  58. set /a n+=1
  59. set z=%%z
  60. setlocal enabledelayedexpansion
  61. )
  62. )
  63. )
  64. )
  65. )
  66. set/a n-=1
  67. (
  68. for /f "tokens=1,*" %%a in (!strFile!) do (
  69. endlocal
  70. set stra=%%a
  71. set str=%%b
  72. setlocal enabledelayedexpansion
  73. if defined str (
  74. set "str=!stra! !str: =!"
  75. for /l %%1 in (0,1,%n%) do (
  76. for /f "tokens=1,2 delims=囧" %%b in ("!$%%1!") do (
  77. if "!str:%%c=!" neq "!str!" (
  78. if "!str:%%c=%%c!" equ "!str!" (
  79. set str=!str:"%%c"="%%b"!
  80. set str=!str:"@%%c"="@%%b"!
  81. set str=!str:"#%%c"="#%%b"!
  82. if "!str:*%%c=!" neq "!str!" (
  83. call :parti %%c %%b
  84. )
  85. ))
  86. )
  87. )
  88. ) else (
  89. set str=%%a
  90. )
  91. echo;!str!
  92. )
  93. ) >结果.txt
  94. start 结果.txt
  95. rem 查看有多少个更改
  96. set $
  97. pause
  98. exit /b
  99. rem 计算临名字,可加上前缀,多个,A 到 ZZZZ 多个
  100. :getn
  101. (set L=%1
  102. set M=%1
  103. set %2=)
  104. :loop
  105. set /a M=L %% 26
  106. set %2=!%2!!ASC:~%M%,1!
  107. if !M! neq !L! set /a L=L/26&goto :loop
  108. goto :eof
  109. rem 非双引号位置处理 如:#xxxx+  #xxxx[  ]  #xxxx.dir  
  110. :parti
  111. for %%a in (!tab!) do (
  112. if "!str:%1%%~a=!" neq "!str!" (
  113. if "!str:%1%%~a=%1%%~a!" equ "!str!" (
  114. set str=!str:@%1%%~a=@%2%%~a!
  115. set str=!str:#%1%%~a=#%2%%~a!
  116. if "!str:*%1=!" equ "!str!" (
  117. goto :partiE
  118. )
  119. )
  120. )
  121. )
  122. :partiE
  123. goto :eof
复制代码
那個帖子最後一個版本的代碼
  1. $global:n = 0; $Hash=@{};
  2. $str = [IO.File]::ReadAllText('manifest.xml',[Text.Encoding]::Default);
  3. #修改name属性的值,如果name属性值以music_prev或music_display或music_next等开头,或者节点名为Extra,则不修改
  4. $reg1 = '(?<=<(?!Extra)[^<>]*\sname=")(?!notice)(?!music_(?:prev|display|next|play|pause|album_cover))(?!notification_(?:icon|title|content|time|info|subtext|key|list))[^"]+(?=")';
  5. #如果command与target同时出现,command="play",则修改target属性值,
  6. $reg2 = '(?<=\starget=")[^"]+(?="[^<>]*\scommand="play)|(?<=\scommand="play[^<>]*\starget=") [^"]+(?=")';
  7. $str = [regex]::Replace($str, $reg1 + '|' + $reg2, {
  8.     param($m);
  9.     $key = $m.Value;
  10.     if( !$Hash.ContainsKey($key) ){
  11.         $x = [Math]::floor( $global:n / 26 );
  12.         if($x) { $chr1 = [char]( 64 + [int]$x ) } else { $chr1 = '' }
  13.         $Hash[$key] = $chr1 + [char]( 65 + $global:n++ % 26 );
  14.     }
  15.     $Hash[$key];
  16. })
  17. $arrKey = $Hash.Keys | sort -Desc {$_.Length};
  18. #如果属性值包含@#字符,或者属性值以 .animation或.visibility 结尾,则修改
  19. $str = [regex]::Replace($str, '(?<=")([^"@#]*[@#][^"]+|[^"]+(?:\.animation|\.visibility))(?=")', {
  20.     param($m);
  21.     $s = $m.Groups[1].Value;
  22.     forEach( $key In $arrKey ) {
  23.         $s = $s.Replace( '@' + $Key, '@' + $Hash[$Key] );
  24.         $s = $s.Replace( '#' + $Key, '#' + $Hash[$Key] );
  25.         $s = $s.Replace( $Key + '.animation', $Hash[$Key] + '.animation' );
  26.         $s = $s.Replace( $Key + '.visibility', $Hash[$Key] + '.visibility' );
  27.     }
  28.     $s;
  29. })
  30. [IO.File]::WriteAllText('manifest2.xml', $str, [Text.Encoding]::UTF8);
  31. $str = [IO.File]::ReadAllText('config.xml', [Text.Encoding]::Default);
  32. $str = [regex]::Replace($str, '(?<=\sid=")[^"]+(?=")', {param($m); if($Hash[$m.Value]){$Hash[$m.Value]}else{$m.Value}});
  33. [IO.File]::WriteAllText('config2.xml', $str, [Text.Encoding]::UTF8);
  34. echo 'Done';
  35. [Console]::ReadKey()
复制代码

TOP

本帖最后由 uhjjhjff11d 于 2019-11-14 17:33 编辑

回复 35# WHY
我该说你啥好?喜欢抬杠,又抬不到点上。
你把我写的脚本贴出来是几个意思?是想跟你的对比,让我难堪是不是?
既然贴出来了,你看都不看一眼就开始胡咧咧?
他定义 A~ZZZ 变量范围明明有目的,没看见脚本有两个xml文件吗?他想把第二个文件与第一个文件按照某种对应关系进行修改。
明白不?打脸不?疼不?不疼我再打打?
echo 範例

你觉得这个脚本咋样?是不是完胜正则万倍?

算啦吧,各回各家,各找各妈。你的帖子我不再回复。


具體回覆每一個問句

  • 我不知道
  • 既然我認為正則不適合用在這裡(至少是上層的操作),當然直接用這裡現有的代碼來對比啊。
  • 沒有什麼誰的代碼如何如何,現在是在說 api 和正則在操作 xml 誰比較有優勢
  • 你們的代碼我不想看是事實,如果我覺得有閱讀的價值,我發這個帖不是打自己的臉嗎?
  • 沒看見,但是這和幾個 xml 文件有什麼關係?
  • 明白了,但是系統的雜湊,同樣的輸入就會得到同樣的輸出,只要變量名沒有改變,多幾個 xml 文件是不會出問題的。
  • 是的,你把我臉打腫了

  • 不用了,我不喜歡被打臉
  • 不怎麼樣
  • 不是

TOP

本帖最后由 uhjjhjff11d 于 2019-11-16 01:41 编辑

回复 37# WHY
我可以重述一些內容

  • 論壇上傳文件有點問題(補充:在 edge 上允許 flash 之後還是無法上傳,firefox 和 chrome 默認都是禁止 flash 的,當然都可以啟用但是我沒去試)
  • 只需要一行 if else 就能解決的問題拿到論壇問越積越多會浪費其他人的時間 (這個是靠自覺的,寫了沒有用所以刪除)
  • 帖子的標題應該寫清楚處理特殊格式的文件,沒興趣的人就不用點進去(這個是靠自覺的,寫了沒有用所以刪除)
  • 沒註釋
  • 不太能理解在沒必要的時候為什麼要混 batch + PowerShell + .net
  • 有些帖子的代碼會把無關的文件給搞砸,而且並沒有完全解決標題要解決的問題,但是標題寫已解決


網路上很多 PowerShell 操作 xml 的影片和文檔,更好的寫法多的是。前幾樓很明顯有其他論壇的老人常常在用 xml 了,如果對 PowerShell 操作 xml 感興趣,應該去請教那些常常處理 xml 的人
我(扣除雜湊和 if else )只是寫一行代碼示範用 api 處理節點批量改名(沒需求沒興趣沒能力沒時間去寫我不感興趣的代碼),如果那寫法會把 xml 結構搞砸的話歡迎指教。

TOP

返回列表