1
votes

Comment diviser une chaîne contenant des retours à la ligne

Une chaîne (extraite d'un message électronique Outlook body.innerText) contient des retours à la ligne intégrés. Comment puis-je diviser ceci en un tableau de chaînes?

Je m'attendrais à ce que cette chaîne d'exemple soit divisée en un tableau de deux (2) éléments. Au lieu de cela, il devient un tableau de trois (3) éléments avec une ligne vide au milieu.

PS C:\src\t> ("This is`r`na string.".Split([Environment]::NewLine)) | % { $_ }
This is

a string.
PS C:\src\t> "This is `r`na string.".Split([Environment]::NewLine) | Out-String | Format-Hex

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   54 68 69 73 20 69 73 20 0D 0A 0D 0A 61 20 73 74  This is ....a st
00000010   72 69 6E 67 2E 0D 0A                             ring...


5 commentaires

En utilisant votre code tel quel, j'obtiens un tableau avec deux éléments. Avez-vous plusieurs retours à la ligne consécutifs dans le contenu réel de l'e-mail?


l'applet de commande Out-String ajoute des «trucs» à la sortie. ce sont généralement des choses comme cr / lf à la fin de chaque ligne. N'utilisez PAS l'applet de commande lorsque vous voulez voir ce qu'est vraiment la sortie de quelque chose. [ sourire ]


la méthode .Split () se divise sur CHAQUE CHAR dans la chaîne split-on-this, pas sur la chaîne entière. donc vous avez une scission sur le lf et sur le cr . c'est de là que vient votre ligne supplémentaire. [ grin ] la réponse de mklement0 est un moyen d'éviter ce problème.


@Lee_Dailey Notez que ce n'est plus le cas dans PowerShell v6 + (une nouvelle surcharge de méthode .NET Core qui prend désormais un séparateur [string] est désormais prioritaire) - c'est une bonne raison de toujours préférer -split sur .Split () .


@ mklement0 - merci pour le rappel [ sourire ] ... j'avais vu ça et je l'avais oublié. [ rougir ]


3 Réponses :


3
votes

Pour traiter une séquence CRLF dans son ensemble comme séparateur, il est plus simple d'utiliser le -split opérateur , qui est regex - basé:

PS> "This is `r`n`r`n a string." -split '\r?\n'
This is 
 a string.

Remarque:

  • \ r? \ n correspond à la fois aux retours à la ligne CRLF (style Windows) et LF uniquement (style Unix); utilisez \ r \ n si vous ne voulez vraiment faire correspondre que les séquences CRLF.

    • Notez l'utilisation d'une chaîne entre guillemets simples ( '...' ), de manière à transmettre la chaîne contenant l'expression rationnelle telle quelle au. Moteur NET regex; le moteur regex utilise \ comme caractère d'échappement; d'où l'utilisation de \ r et \ n .
  • L'opérateur -split de PowerShell est une alternative généralement supérieure au [string] .NET de type .Split ( ) méthode - voir cette réponse .


Quant à ce que vous avez essayé :

L'argument de séparation, [Environment] :: NewLine , sous Windows est la chaîne "` r`n ", c'est-à-dire une séquence CRLF.

  • Dans PowerShell [Core] v6 + , votre commande fonctionne , car cette chaîne dans son ensemble est considérée comme le séparateur.

  • Dans Windows PowerShell , comme Steven le souligne dans sa réponse utile , les caractères individuels - CR et LF séparément sont considérés comme des séparateurs, ce qui entraîne un élément vide supplémentaire - la chaîne vide entre le CR et le LF - dans le tableau de résultats.

Ce changement de comportement s'est produit en dehors du contrôle de PowerShell: .NET Core a introduit une nouvelle surcharge de méthode .Split () avec un type de [string] séparateur, que l'algorithme de résolution de surcharge de PowerShell sélectionne désormais par rapport à l'ancienne surcharge avec le paramètre de type [char []] .
Éviter ces changements de comportement inévitables (bien que rares) par inadvertance est une autre bonne raison de préférer l'opérateur -split natif de PowerShell au code .NET [string] > type .Split () method.


0 commentaires

3
votes

En effet, la méthode .Split () se divisera sur l'un des caractères qu'elle trouve, par exemple:

"This is`r`na string." -split "`r`n"

Sortie:

.Split([Environment]::NewLine), [Stringsplitoptions]::RemoveEmptyEntries)

L'élément supplémentaire est une chaîne vide insérée entre les 2 caractères séparés.

(merci à @ mklement0, pour avoir corrigé cela)

Donc je ne peux que supposons que cela résulte de plusieurs facteurs. Le premier [Environment] :: NewLine est à la fois les caractères CarrigeReturn & LineFeed et la ligne provenant d'Outlook utilise effectivement cette séquence de fin de ligne. Tout est normal dans Windows.

Il y a 2 solutions auxquelles je peux penser:

Option 1:

first part of a string

second part of a string


1 commentaires

Quant au fractionnement .Split () sur n'importe quel caractère: notez que cela n'est plus vrai dans PowerShell v6 + (une nouvelle surcharge de méthode .NET Core qui prend maintenant un séparateur [string] a priorité) - c'est une bonne raison de toujours préférer -split à .Split () .



0
votes

Bonjour,

Je suis un grand NooB dans PowerShell, mais ...
J'ai écrit ceci

$Result_1.Split("|")
## OUTPUT ##
This is
 a string.

 $Result_2.Split("|")
 ## OUTPUT ##
 This is
 ....a st
 ring...

J'espère que c'est de l'aide ...

PS:

Je viens de réaliser que j'ai oublié le résultat ... ..

$str_1 ="This is

a string."
$splt_1=$str_1.Split()
$cnt_1=1
foreach ($item in $splt_1) {
     $regEx="[a-zA-Z]"
     if ($item -cmatch $regEx){
          $Result_1=$Result_1+"$item "
     } elseif ($cnt_1 -eq 1) {
          $Result_1=$Result_1+"| "
          $cnt_1=$cnt_1+1
     }
}
Write-Host $Result_1
## OUTPUT ##
# This is | a string.

$str_2="
This is

....a st

ring...
"
$splt_2=$str_2.Split()
$cnt_2=1
foreach ($item in $splt_2) {
     $regEx="[a-zA-Z]"
     if ($item -cmatch $regEx){
          $cnt_2=1
          $Result_2=$Result_2+"$item "
     } elseif ($cnt_2 -eq 1) {
          $Result_2=$Result_2+"| "
          $cnt_2=$cnt_2+1
     }
}
Write-Host $Result_2
## OUTPUT ##
# | This is | ....a st | ring... |

EOF

AxelEric.


1 commentaires

Après avoir vu les 2 autres réponses qui ont résolu le problème avec un one-liner et quelques explications, qu'est-ce qui vous a fait penser que vous deviez poster cette réponse? Pourriez-vous ajouter quelques explications sur la façon dont vous résolvez le problème et pourquoi tant de lignes de code sont nécessaires pour résoudre cette tâche simple? Quels sont les avantages de votre solution?