PowerShell是否尝试找出脚本的编码?

PowerShell是否尝试找出脚本的编码?,powershell,encoding,scripting,Powershell,Encoding,Scripting,在PowerShell 7.1中执行以下简单脚本时,无论脚本的编码是Latin1还是UTF8,都会得到正确的值3 'Bär'.length 这让我感到惊讶,因为我显然错误地认为PowerShell 5.1中的默认编码是UTF16-LE,而PowerShell 7.1中的默认编码是UTF-8 因为这两个脚本都将表达式计算为3,所以我不得不得出结论,PowerShell 7.1在执行脚本时应用了一些启发式方法来推断脚本的编码 我的结论正确吗?这是否有文档记录?编码与本例无关:您调用的是string

在PowerShell 7.1中执行以下简单脚本时,无论脚本的编码是Latin1还是UTF8,都会得到正确的值3

'Bär'.length
这让我感到惊讶,因为我显然错误地认为PowerShell 5.1中的默认编码是UTF16-LE,而PowerShell 7.1中的默认编码是UTF-8

因为这两个脚本都将表达式计算为3,所以我不得不得出结论,PowerShell 7.1在执行脚本时应用了一些启发式方法来推断脚本的编码


我的结论正确吗?这是否有文档记录?

编码与本例无关:您调用的是string.Length,它被记录为返回UTF-16代码单元的数量。当您忽略组合字符和高代码点(如表情符号)时,这大致与字母相关

编码仅在隐式或显式转换为字节数组、文件或p/invoke时起作用。它不影响.Net存储支持字符串的数据的方式

说到PS1文件的编码,这取决于版本。旧版本的回退编码为encoding.ASCII,但将遵守UTF-16或UTF-8的BOM。较新版本使用UTF-8作为后备方案

在至少5.1.19041.1中,加载文件“Bär”。长度为27 42 C3 A4 72 27 2E 4C 65 6E 67 74 68并使用\Bar.ps1将导致4次打印

如果将同一文件另存为Windows-1252 27 42 E4 72 27 2E 4C 65 6E 67 74 68,则它将打印3


tl;字符串。长度总是返回UTF-16代码单元的数量。PS1文件应采用UTF-8格式,并带有BOM,以实现跨版本兼容性。

编码与这种情况无关:您正在调用string.Length,该文件记录用于返回UTF-16代码单元的数量。当您忽略组合字符和高代码点(如表情符号)时,这大致与字母相关

编码仅在隐式或显式转换为字节数组、文件或p/invoke时起作用。它不影响.Net存储支持字符串的数据的方式

说到PS1文件的编码,这取决于版本。旧版本的回退编码为encoding.ASCII,但将遵守UTF-16或UTF-8的BOM。较新版本使用UTF-8作为后备方案

在至少5.1.19041.1中,加载文件“Bär”。长度为27 42 C3 A4 72 27 2E 4C 65 6E 67 74 68并使用\Bar.ps1将导致4次打印

如果将同一文件另存为Windows-1252 27 42 E4 72 27 2E 4C 65 6E 67 74 68,则它将打印3


tl;字符串。长度总是返回UTF-16代码单元的数量。PS1文件应采用UTF-8格式,带有BOM,以实现跨版本兼容性。

我认为,如果没有BOM,PS 5采用ansi或windows-1252,而PS 7采用utf8无BOM。此文件在记事本中另存为ansi,可在PS 5中工作,但在PS 7中并不完美。就像带有特殊字符的utf8无bom文件在PS5中无法完美工作一样。utf16 ps1文件始终具有BOM或编码签名。内存中的powershell字符串始终为utf16,但除表情符号外,字符的长度被视为1。如果您有emacs,esc-Xhexl模式是一种很好的查看方式

'¿Cómo estás?'

我认为如果没有BOM表,PS5采用ansi或windows-1252,而PS7采用utf8无BOM表。此文件在记事本中另存为ansi,可在PS 5中工作,但在PS 7中并不完美。就像带有特殊字符的utf8无bom文件在PS5中无法完美工作一样。utf16 ps1文件始终具有BOM或编码签名。内存中的powershell字符串始终为utf16,但除表情符号外,字符的长度被视为1。如果您有emacs,esc-Xhexl模式是一种很好的查看方式

'¿Cómo estás?'
我的印象显然是错误的,PowerShell 5.1中的默认编码是UTF16-LE,PowerShell 7.1中的默认编码是UTF-8

需要考虑两种不同的默认字符编码:

写入文件时,各种cmdlet使用的默认输出编码包括文件、设置内容和重定向操作符>、>>

此编码在Windows PowerShell PowerShell版本(5.1之前)中的cmdlet之间差异很大,但幸运的是,现在PowerShell[Core]v6+中始终默认为BOM较少的UTF-8。有关详细信息,请参阅

注意:此编码始终与可能已从中读取数据的文件的编码无关,因为PowerShell不保留此信息,并且从不通过原始字节传递文本-文本始终由PowerShell转换为.NET[string],实例,然后再进一步处理数据

读取文件时的默认输入编码—例如,引擎读取的源代码和Get Content读取的文件,它仅适用于没有BOM表的文件,因为带有BOM表的文件始终可以正确识别

如果没有BOM表:

Windows PowerShell假定系统处于活动状态 e页面,如美国英语系统上的Windows-1252。请注意,这意味着对于非Unicode应用程序,具有不同活动系统区域设置的系统可以对给定文件进行不同的解释

PowerShell[Core]v6+更合理地采用UTF-8,它能够表示所有Unicode字符,并且其解释不依赖于系统设置

注意,这些都是固定的、确定性的假设——没有采用启发式

结果是,对于跨版本源代码,最好使用UTF-8和BOM编码,这两个版本都能正确识别

对于包含“Bär”的源代码文件。长度:

如果源代码文件的编码被正确识别,那么结果总是3,因为构造了一个.NET字符串实例[string],它在内存中总是由UTF-16代码单元[char]组成,并且给定.Length统计这些代码单元的数量。[1]

将断开的文件保留在图片之外,例如没有BOM表的UTF-16文件,或BOM表与实际编码不匹配的文件:

.Length不返回3的唯一情况是:

在Windows PowerShell中,如果文件保存为不带BOM表的UTF-8文件

由于ANSI代码页使用固定宽度的单字节编码,作为UTF-8字节序列一部分的每个字节被单独错误地解释为一个字符,并且由于带有分音符的ä拉丁文小写字母a在UTF-8、0xc3和0xa4中被编码为2个字节,因此生成的字符串有4个字符。 因此,字符串呈现为BÃr 相反,在PowerShell[Core]v6+中,基于活动ANSI或OEM代码页(例如,在Windows PowerShell中设置内容)保存的无BOM文件会导致8位范围内的所有非ASCII字符被视为无效字符,因为它们不能解释为UTF-8

所有这些无效字符都被替换为� 替换字符,-换句话说:信息丢失。 因此,字符串呈现为B�它的长度仍然是3。 [1] 单个UTF-16代码单元能够在所谓的BMP基本多语言Unicode平面中直接编码所有65K字符,但对于该平面以外的字符,成对的代码单元编码单个Unicode字符。结果是:.Length并不总是返回字符数,尤其是表情符号;e、 g.,' 我的印象显然是错误的,PowerShell 5.1中的默认编码是UTF16-LE,PowerShell 7.1中的默认编码是UTF-8

需要考虑两种不同的默认字符编码:

写入文件时,各种cmdlet使用的默认输出编码包括文件、设置内容和重定向操作符>、>>

此编码在Windows PowerShell PowerShell版本(5.1之前)中的cmdlet之间差异很大,但幸运的是,现在PowerShell[Core]v6+中始终默认为BOM较少的UTF-8。有关详细信息,请参阅

注意:此编码始终与可能已从中读取数据的文件的编码无关,因为PowerShell不保留此信息,并且从不通过原始字节传递文本-文本始终由PowerShell转换为.NET[string],实例,然后再进一步处理数据

读取文件时的默认输入编码—例如,引擎读取的源代码和Get Content读取的文件,它仅适用于没有BOM表的文件,因为带有BOM表的文件始终可以正确识别

如果没有BOM表:

Windows PowerShell采用系统的活动ANSI代码页,如美国英语系统上的Windows-1252。请注意,这意味着对于非Unicode应用程序,具有不同活动系统区域设置的系统可以对给定文件进行不同的解释

PowerShell[Core]v6+更合理地采用UTF-8,它能够表示所有Unicode字符,并且其解释不依赖于系统设置

注意,这些都是固定的、确定性的假设——没有采用启发式

结果是,对于跨版本源代码,最好使用UTF-8和BOM编码,这两个版本都能正确识别

对于包含“Bär”的源代码文件。长度:

如果源代码文件的编码被正确识别,那么结果总是3,因为构造了一个.NET字符串实例[string],它在内存中总是由UTF-16代码单元[char]组成,并且给定.Length统计这些代码单元的数量。[1]

将断开的文件保留在图片之外,例如没有BOM表的UTF-16文件,或BOM表与实际编码不匹配的文件:

.Length不返回3的唯一情况是:

在Windows PowerShell中,如果文件保存为不带BOM表的UTF-8文件

由于ANSI代码页使用固定宽度的单字节编码,作为UTF-8字节序列一部分的每个字节都被单独错误地解释为一个字符, 由于带有分音符的ä拉丁文小写字母A在UTF-8、0xc3和0xa4中编码为2个字节,因此生成的字符串有4个字符。 因此,字符串呈现为BÃr 相反,在PowerShell[Core]v6+中,基于活动ANSI或OEM代码页(例如,在Windows PowerShell中设置内容)保存的无BOM文件会导致8位范围内的所有非ASCII字符被视为无效字符,因为它们不能解释为UTF-8

所有这些无效字符都被替换为� 替换字符,-换句话说:信息丢失。 因此,字符串呈现为B�它的长度仍然是3。
[1] 单个UTF-16代码单元能够在所谓的BMP基本多语言Unicode平面中直接编码所有65K字符,但对于该平面以外的字符,成对的代码单元编码单个Unicode字符。结果是:.Length并不总是返回字符数,尤其是表情符号;e、 例如,“字符串来自一个文件,我不知道该文件的编码。因此,不知何故,PowerShell必须推断文件的编码.Right-如果PowerShell以错误的编码加载脚本文件,或者如果您的控制台设置为错误的编码,则可能会导致显示错误的字符,但这不会导致长度不同。仍然有相同数量的字符。字符串来自文件,我不知道该文件的编码。因此,不知何故,PowerShell必须推断文件的编码.Right-如果PowerShell以错误的编码加载脚本文件,或者如果您的控制台设置为错误的编码,则可能会导致显示错误的字符,但这不会导致长度不同。仍然有相同数量的字符。相关:相关:所有这些无效字符都被替换为� 替换字符,U+FFFD是我不知道的。因此,3的长度非常合理。非常感谢你的回答,请原谅我迟来接受。我很高兴,@RenéNyffenegger;我很高兴它有帮助。所有这些无效字符都被替换为� 替换字符,U+FFFD是我不知道的。因此,3的长度非常合理。非常感谢你的回答,请原谅我迟来接受。我很高兴,@RenéNyffenegger;我很高兴这有帮助。