Board logo

标题: [问题求助] PowerShell把hash表定义还原回字面字符串 [打印本页]

作者: 5i365    时间: 2022-3-31 17:35     标题: PowerShell把hash表定义还原回字面字符串

此贴由 另一贴引出 http://www.bathome.net/thread-62168-1-1.html

下面的代码, 输出的结果是: hash表对象的属性,即蓝色字, 我想输出hash对象的定义的字符串,即红色字,

我找到了【hash表对象定义还原回字符串】的下面关键代码, 有两种,效果相同, 但是还差首和尾的定义, 怎么接上? 【三行代码的结果也有瑕疵,值没有被双引号引起来】
$hash.GetEnumerator() | %{
$_.key + "=" + $_.Value
}

----------------------------------上面是用枚举器的方法,下面是用遍历键值的方法
foreach ($key in $hash.keys) {
$key + "=" + $hash[$key]

}

感觉从正则匹配的地方生成可能更简单,
或可能还有更好的思路和方法, 请求路过高手支招, 提前感谢!

-----------------------------------------------------------------------------------------------------------------------------

Name                           Value
----                           -----
日本                             "在东京"
美国                             "在纽约"
南非                             "在刚果"

------------------------------------------------------------------
$hash = [ordered]@{

日本 = "在东京"


美国 = "在纽约"


南非 = "在刚果"

}
  1. $s = @"
  2. 岁月难得沉默
  3. 秋风厌倦漂泊
  4. 夕阳赖着不走
  5. 挂在墙头舍不得我
  6. 昔日伊人耳边话
  7. 已和潮声向东流
  8. 再回首
  9. #开始
  10.       黄种人"在东京", //日本
  11.              白人"在纽约", //美国
  12. "在刚果",//南非
  13.         黑人//印度
  14. #结束
  15. 往事也随枫叶一片片落
  16. 爱已走到尽头
  17. 恨也放弃承诺
  18. 命运自认幽默
  19. 想法太多由不得我
  20. 壮志凌云几分酬
  21. 知己难逢几人留
  22. "@
  23. $txt = $s -split '\n' -join "|"
  24. $pattern1 = "#开始(.*)#结束"
  25. $pattern2 = '("\w+"),\s?//(\w+)'
  26. $hash = [ordered]@{ }
  27. if ($txt -match $pattern1)
  28. {
  29.         $target = $matches[1].split('|')
  30. }
  31. foreach ($line in $target)
  32. {
  33.         if ($line -match $pattern2)
  34.         {
  35.                 $hash[$matches[2]] = $matches[1]
  36.         }
  37. }
  38. $hash
复制代码

作者: went    时间: 2022-3-31 20:12

用-f格式化就很好操作
  1. $s = @'
  2. 岁月难得沉默
  3. 秋风厌倦漂泊
  4. 夕阳赖着不走
  5. 挂在墙头舍不得我
  6. 昔日伊人耳边话
  7. 已和潮声向东流
  8. 再回首
  9. #开始
  10.       黄种人"在东京", //日本
  11.              白人"在纽约", //美国
  12. "在刚果",//南非
  13.         黑人//印度
  14. #结束
  15. 往事也随枫叶一片片落
  16. 爱已走到尽头
  17. "在刚f果",//南非
  18. 恨也放弃承诺
  19. 命运自认幽默
  20. 想法太多由不得我
  21. 壮志凌云几分酬
  22. 知己难逢几人留
  23. '@
  24. $hash = [ordered]@{}
  25. if($s -match '(?s)#开始(.*?)#结束'){
  26.     [regex]::Matches($Matches[1],'(?m)"(.+?)",\s*//(.+?)$') | foreach { $hash.($_.Groups[2].Value) = $_.Groups[1].Value }
  27. }
  28. $hash.Keys | foreach { '{0} = "{1}"' -f $_,$hash[$_] }
复制代码

作者: 5i365    时间: 2022-3-31 21:23

本帖最后由 5i365 于 2022-3-31 21:24 编辑

回复 2# went


  大侠牛X, 确实好理解多了, 怎样生成下面格式的字面值?  我是想生成下面的字面值, 然后存到变量$h中, 后面想显示的时候, 直接放出$h变量
$hash = [ordered]@{
    日本 = "在东京"

    美国 = "在纽约"

    南非 = "在刚果"

}
作者: 5i365    时间: 2022-3-31 21:36

本帖最后由 5i365 于 2022-3-31 21:53 编辑

回复 2# went


   我自己改成下面这样, 会多一个空行, 另外感觉太绕
  1. $hash.Keys | foreach { '{0} = "{1}"' -f $_, $hash[$_] } | Out-String | tee -var mid | Out-Null
  2. $start = '$hash = [ordered]@{'
  3. $end = '}'
  4. $h = @"
  5. $start
  6. $mid
  7. $end
  8. "@
  9. $h
复制代码

作者: went    时间: 2022-3-31 21:54

&{
    代码块
}
可以把整个代码块的输出转换为一个字符串
  1. $hash = [ordered]@{}
  2. if($s -match '(?s)#开始(.*?)#结束'){
  3.     [regex]::Matches($Matches[1],'(?m)"(.+?)",\s*//(.+?)$') | foreach { $hash.($_.Groups[2].Value) = $_.Groups[1].Value }
  4. }
  5. $h =
  6. &{
  7.     '$hash = [ordered]@{'
  8.     $hash.Keys | foreach { '{0}{1} = "{2}"' -f "`t",$_,$hash[$_] }
  9.     '}'
  10. }
  11. $h
复制代码

作者: 5i365    时间: 2022-3-31 21:57

回复 5# went


大侠实在太牛X了, 精干高效,炉火纯青!!
作者: went    时间: 2022-3-31 22:01

本帖最后由 went 于 2022-3-31 22:05 编辑

纠正一下
&{
    代码块
} 转换为Object数组

&{
    代码块
} | Out-String 转换为字符串
作者: 5i365    时间: 2022-4-1 07:21

本帖最后由 5i365 于 2022-4-1 07:24 编辑

回复 7# went


   感谢大侠提醒, gettype看了一下, 确实如此, 另外大侠能解惑一下您正则中的符号的含义吗?
for_flr 大侠写的正则如下, 我能理解,
$pattern1 = "#开始(.*)#结束"
$pattern2 = '("\w+"),\s?//(\w+)'

--------------------------------------------------
您写的正则如下
'(?s)#开始(.*?)#结束'
'(?m)"(.+?)",\s*//(.+?)$'

--------------------------------------------------
量词+或*后加了? 应该是匹配尽可能的少
但是正则前都多了括号(?s)和(?m)
(?m)我好像在哪里看到过, 说的是匹配多行, 但是(?s)这个参数没找到相关资料, ps官方的MSDN也没找到,  
大侠能解释一下它的含义吗? 能引用一个资料出处就好了, 再次感谢.
放上官方PS的正则链接供大家参考
https://docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_regular_expressions?view=powershell-7.2
作者: went    时间: 2022-4-1 11:32

这里面有关于单行和多行匹配的详细介绍
https://docs.microsoft.com/zh-cn ... -expression-options
作者: 5i365    时间: 2022-4-1 16:38

本帖最后由 5i365 于 2022-4-1 19:21 编辑

回复 9# went

非常感谢大侠的指引!!!原来是单行模式, 这样就不用 像 for_flr 大侠代码那样, 先用 | 拼接了, 方便了很多

刚又入了一个坑, 我把要处理的文本外置存为了s.txt, 再次执行后, =号后面换行了, 结果如下!

$hash = [ordered]@{

日本
= "在东京"

美国
= "在纽约"

南非
= "在刚果"
}



  1. $s = gc s.txt -enc UTF8 -raw
  2. $hash = [ordered]@{ }
  3. if ($s -match '(?s)#开始(.*?)#结束')
  4. {
  5.         [regex]::Matches($Matches[1], '(?m)"(.+?)",\s*//(.+?)$') |
  6.         foreach { $hash.($_.Groups[2].Value) = $_.Groups[1].Value }
  7. }
  8. $h = &{
  9.         '$hash = [ordered]@{'
  10.         $hash.Keys | foreach { '{0}{1} = "{2}"' -f "`t", $_, $hash[$_] }
  11.         '}'
  12. }
  13. $h
复制代码

作者: went    时间: 2022-4-1 19:32

回复 10# 5i365


    我运行没问题
作者: 5i365    时间: 2022-4-1 20:49

本帖最后由 5i365 于 2022-4-1 20:51 编辑

回复 11# went


我在powershell studio 里, 显示换行了, 但是我在powershell ISE里, 显示是好的, 但是定向后, 也换行了,
$h > "C:\Users\Administrator\Desktop\aaa.txt"
s.txt 下载 https://send.cm/d/9oH1
  1. $s = gc "C:\Users\Administrator\Desktop\s.txt" -enc UTF8 -raw
  2. $s -match '(?s)#开始(.*?)#结束'
  3. $matches[0]
  4. $hash = [ordered]@{ }
  5. if ($s -match '(?s)#开始(.*?)#结束')
  6. {
  7. [regex]::Matches($Matches[1], '(?m)"(.+?)",\s*//(.+?)$') |
  8. foreach { $hash.($_.Groups[2].Value) = $_.Groups[1].Value }
  9. }
  10. $h = &{
  11. '$hash = [ordered]@{'
  12. $hash.Keys | foreach { '{0}{1} = "{2}"' -f "`t", $_, $hash[$_] }
  13. '}'
  14. }
  15. $h>"C:\Users\Administrator\Desktop\aaa.txt"
复制代码

作者: went    时间: 2022-4-1 21:14

本帖最后由 went 于 2022-4-1 21:16 编辑

正则改一下,把末尾的换行符去掉
  1. '(?m)"(.+?)",\s*//(\S+?)\s$'
复制代码
  1. '(?m)"(.+?)",\s*//\s*(.+?)\s*$'
复制代码

作者: 5i365    时间: 2022-4-1 21:20

回复 13# went


   大侠牛X,  显示和输出都没换行了.
正则真是字符串处理的万金油啊,!!!




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