“Two identical strings are not equal.” 为什么?

huangapple go评论60阅读模式
英文:

Two identical strings are "not equal". Why?

问题

I'm trying to figure out why these two strings are not equal. Is there a better operator I should use?

英文:

“Two identical strings are not equal.” 为什么?

Im trying to figure out why these two strings are not equal. Is there a better operator I should use?

$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified

$storeddate = get-content C:\windows\file.txt

答案1

得分: 1

Sure, here is the translated code snippet:

$lastupdated -ne $storeddayed
True

Indeed means that the values aren't identical even their **basic properties** (display values) appear to be the same.

PowerShell is a [loosely typed programming](https://en.wikipedia.org/wiki/Strong_and_weak_typing) which lets you "conveniently" compare two values of different types. Try this:

$lastupdated.GetType()
$storeddayed.GetType()

I suspect that the `$storeddayed` variable is actually a string as the name implies that it has been stored where it has likely lost its fidelity of the actual [`datetime` structure](https://learn.microsoft.com/dotnet/api/system.datetime) as it has either been [converted automatically](https://learn.microsoft.com/powershell/scripting/lang-spec/chapter-06) or "manually" as you do in your own [answer](https://stackoverflow.com/a/76277291/1701026) with the `ToString()` method.
If you compare two different types of objects, the object on the RHS (right hand side) dictates the conversion for the comparison (this generally counts for any other operator).
This means that you might just convert the right side (or both sides) to a string (using double quotes):

"$lastupdated" -ne "$storeddayed"

Or simply swap the operands in the operation to get what you expected:

$storeddayed -ne $lastupdated

Also note that in case the operands (`$storeddayed` and `$lastupdated`) are *both* of the `datetime` structure, not all detailed [properties](https://learn.microsoft.com/dotnet/api/system.datetime#properties) are displayed by default (think of the timezone information and e.g. the `millisecond` property).

In other words, if you give the commands in one go:

$lastupdated = Get-Date()
$storeddayed = Get-Date()

They might look the same as you display them (as strings) but they actually differ in time:

$lastupdated.Millisecond
$storeddayed.Millisecond

I hope this helps!

英文:
$lastupdated -ne $storeddayed
True

Indeed means that the values aren't identical even their basic properties (display values) appear to be the same.

PowerShell is a loosely typed programming which lets you "convienently" compare two values of a different type. Try this:

$lastupdated.GetType()
$storeddayed.GetType()

I suspect that the $storeddayed variable is actually a string as the name implies that it has been stored were it is has likely lost its fidelity of the actual datetime structure as it has either been converted automaticaly or "manually" as you do in your own answer with the ToString() method.
If you compare two different types the objects. The object at the RHS (right hand side) dictates the conversation for the comparison (this generally counts for any other operator).
This means that you might just convert the right side (or both sides) to a string (using double quotes):

"$lastupdated" -ne "$storeddayed"

Or simply swap the operants in the operation to get what you expected:

$storeddayed -ne $lastupdated

Also note that in case the operants ($storeddayed and $lastupdated) are both of the datetime structure, not all detailed properties are displayed by default (think of the timezone information and e.g. the millisecond property).

In other words, if you give the commands in one go:

$lastupdated = Get-Date()
$storeddayed = Get-Date()

They might look the same as you display them (as string) but they actually differ in time:

$lastupdated.Millisecond
$storeddayed.Millisecond

答案2

得分: 1

以下是翻译的内容:

根本原因

根据您如何初始化$storeaddate...

$storeddate = get-content C:\windows\file.txt

...我会假设您的文件只包含一行文本,类似这样...

Last-Modified     Web 17, May 2023 23:27:24 GMT

...这使它成为一个[string]实例。

$lastupdated是这样初始化的:

$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified

这意味着它是一个Microsoft.PowerShell.Commands.MatchInfo对象,因为这是Select-String返回的内容。

您可以使用以下命令来检查:

$lastupdated.GetType().FullName

# Microsoft.PowerShell.Commands.MatchInfo

您还可以使用以下命令查看更多详细信息:

$lastupdated | fl *

# IgnoreCase : True
# LineNumber : 1
# Line       : Last-Modified     Web 17, May 2023 23:27:24 GMT
# Filename   : InputStream
# Path       : InputStream
# Pattern    : Last-Modified
# Context    :
# Matches    : {0}

$storeddate -ne $lastupdated 始终返回 $true 的原因是因为[string][matchinfo] 永远不相等。

解决方法

如果您想获得从Select-String返回的返回值的文本表示(即[string]),可以执行以下操作:

$lastupdated = invoke-webrequest -uri $source `
    | Out-String -Stream `
    | Select-String Last-Modified `
    | select-object -ExpandProperty "Line"
    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 提取“Line”属性的值

$lastupated

# Last-Modified     Web 17, May 2023 23:27:24 GMT

(注意select-object -ExpandProperty "Line",它从matchinfo对象中提取Line属性的值)

现在,$lastupdated 真的是一个[string],而不是一个MatchInfo,当它们相同时,您应该发现 $storeddate -ne $lastupdated 会正确返回 $false

Last-Modified 标头

尽管说了这么多,我猜您实际上真正想要的是从调用invoke-webrequest获取Last-Modified响应标头,您可以通过以下方式更轻松地获取它:

$response = invoke-webrequest -uri $source

$lastupdated = $response.Headers["Last-Modified"]

$lastupdated

# Web 17, May 2023 23:27:24 GMT

这不会受到在提取Last-Modified之前对响应进行脆弱字符串化的影响。

而且,如果您使用Last-Modified 标头来确定资源是否已更新,您可能还可以使用HEAD 方法,以避免下载整个资源内容,因为这正是您首先要避免做的,如果它已经是最新的话:

$response = invoke-webrequest `
   -Uri    "www.google.com" `
   -Method "HEAD" `
   -UseBasicParsing

$lastupdated = $response.Headers["Last-Modified"]

$lastupdated

# Web 17, May 2023 23:27:24 GMT
英文:

Root Cause

Based on how you're initialising $storeaddate...

$storeddate = get-content C:\windows\file.txt

... I'm going to assume your file has just got a single line of text with something like this in it..

Last-Modified     Web 17, May 2023 23:27:24 GMT

... which makes it a [string] instance.

Whereas $lastupdated is initialised like this:

$lastupdated = invoke-webrequest -uri $source | Out-String -Stream | Select-String Last-Modified

which means it's a Microsoft.PowerShell.Commands.MatchInfo object because that's what Select-String returns.

You can check that with this:

$lastupdated.GetType().FullName

# Microsoft.PowerShell.Commands.MatchInfo

and you can see more details with this:

$lastupdated | fl *

# IgnoreCase : True
# LineNumber : 1
# Line       : Last-Modified     Web 17, May 2023 23:27:24 GMT
# Filename   : InputStream
# Path       : InputStream
# Pattern    : Last-Modified
# Context    :
# Matches    : {0}

The reason youc $storeddate -ne $lastupdated always returns $true is because a [string] and a [matchinfo] are never equal.

Workaround

If you want to get a textual (i.e. [string]) representation of the return value from Select-String you can do this:

$lastupdated = invoke-webrequest -uri $source `
    | Out-String -Stream `
    | Select-String Last-Modified `
    | select-object -ExpandProperty "Line"
    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - extract the "Line" property value

$lastupated

# Last-Modified     Web 17, May 2023 23:27:24 GMT

(note the select-object -ExpandProperty "Line" which extracts the value of the Line property from the matchinfo object)

And now $lastupdated really is a [string] as opposed to a MatchInfo and you should find $storeddate -ne $lastupdated will correctly return $false when they're the same.

Last-Modified Header

Having said all of that, I'm going to take a bit of a leap and guess that you're really actually after the Last-Modified response header from your call to invoke-webrequest which you can get a lot easier if you do this:

$response = invoke-webrequest -uri $source

$lastupdated = $response.Headers["Last-Modified"]

$lastupdated

# Web 17, May 2023 23:27:24 GMT

which won't be affected by differences in brittle stringifying of the response before you extract the Last-Modified using select-string.

And, if you're using the Last-Modified header to decide whether a resource has been updated, you might as well use the HEAD method as well to avoid downloading the entire resource content, since that's what you're trying to avoid doing in the first place if it's already up to date:

$response = invoke-webrequest `
   -Uri    "www.google.com" `
   -Method "HEAD" `
   -UseBasicParsing

$lastupdated = $response.Headers["Last-Modified"]

$lastupdated

# Web 17, May 2023 23:27:24 GMT

答案3

得分: 0

I added the .ToString() when saving the string to a file and now my operator seems to be working.

$lastupdated.ToString() | out-file c:\windows\file.txt

英文:

I added the .ToString() when saving the string to a file and now my operator seems to be working.

$lastupdated.ToString() | out-file c:\windows\file.txt

huangapple
  • 本文由 发表于 2023年5月18日 09:58:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277261.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定