Está en la página 1de 681

Contents

Tipos base
Sistema de tipos comunes
Conversión de tipos en .NET
Tablas de conversión de tipos
Aplicación de formato a tipos
Cadenas con formato numérico estándar
Cadenas con formato numérico personalizado
Cadenas con formato de fecha y hora estándar
Cadenas con formato de fecha y hora personalizado
Cadenas de formato TimeSpan estándar
Cadenas de formato TimeSpan personalizado
Cadenas de formato de enumeración
Formatos compuestos
Efectuar operaciones de formato
Procedimiento para rellenar un número con ceros a la izquierda
Procedimiento para extraer el día de la semana de una fecha concreta
Procedimiento para definir y usar proveedores de formato numérico
personalizado
Procedimiento para valores de fecha y hora de ida y vuelta
Procedimiento para mostrar milisegundos en los valores de fecha y hora
Procedimiento para mostrar fechas en calendarios no gregorianos
Manipulación de cadenas
Procedimientos recomendados para el uso de cadenas
Operaciones básicas de cadenas
Creación de cadenas
Recortado y eliminación de caracteres
Rellenado de cadenas
Comparar cadenas
Cambio de mayúsculas y minúsculas
Uso de la clase StringBuilder
Procedimiento para realizar manipulaciones de cadena básicas
Expresiones regulares en .NET
Lenguaje de expresiones regulares - Referencia rápida
Escapes de carácter
Clases de caracteres
Delimitadores
Construcciones de agrupamiento
Cuantificadores
Construcciones de referencia inversa
Construcciones de alternancia
Sustituciones
Opciones de expresiones regulares
Construcciones misceláneas
Procedimientos recomendados con expresiones regulares
El modelo de objetos de expresión regular
Detalles del comportamiento de expresiones regulares
Retroceso
Compilar y volver a utilizar
Seguridad para subprocesos
Ejemplos de expresiones regulares
Ejemplo: Buscar etiquetas HREF
Ejemplo: Cambiar formatos de fecha
Procedimiento para extraer un protocolo y un número de puerto de una
dirección URL
Procedimiento para quitar caracteres no válidos de una cadena
Cómo comprobar si las cadenas tienen un formato de correo electrónico válido
Codificación de caracteres de .NET
Análisis de cadenas
Análisis de cadenas numéricas
Análisis de cadenas de fecha y hora
Analizar otras cadenas
Trabajar con tipos base en .NET
31/10/2019 • 2 minutes to read • Edit Online

Esta sección describe las operaciones de tipo base .NET, incluidas operaciones comunes, de conversión y formato.

En esta sección
Conversión de tipos en .NET Framework
Se describe cómo convertir de un tipo a otro.
Aplicación de formato a tipos
Se describe cómo dar formato a cadenas mediante los especificadores de formato de cadena.
Manipular cadenas
Se describe cómo manipular y dar formato a cadenas.
Parsing Strings
Se describe cómo convertir cadenas en tipos de .NET Framework.

Secciones relacionadas
Sistema de tipos comunes
Se describen los tipos que usa .NET Framework.
Fechas, horas y zonas horarias
Describe cómo trabajar con zonas horarias y conversiones de la zona horaria en aplicaciones que tienen en cuenta
la zona horaria.
Sistema de tipos comunes
13/01/2020 • 46 minutes to read • Edit Online

Common Type System define cómo se declaran, usan y administran los tipos en Common Language Runtime. Es
también una parte importante de la compatibilidad en tiempo de ejecución con la integración entre lenguajes. El
sistema de tipos común realiza las funciones siguientes:
Establece un marco de trabajo que ayuda a permitir la integración entre lenguajes, la seguridad de tipos y la
ejecución de código de alto rendimiento.
Proporciona un modelo orientado a objetos que admite la implementación completa de muchos lenguajes
de programación.
Define reglas que deben seguir los lenguajes, lo que ayuda a garantizar que los objetos escritos en distintos
lenguajes puedan interactuar unos con otros.
Proporciona una biblioteca que contiene los tipos de datos primitivos (como Boolean, Byte, Char, Int32 y
UInt64) que se emplean en el desarrollo de aplicaciones.
Este tema contiene las siguientes secciones:
Tipos de .NET
Definiciones de tipo
Miembros de tipos
Características de los miembros de tipos

Tipos de .NET
Todos los tipos de .NET son tipos de valor o tipos de referencia.
Los tipos de valor son tipos de datos cuyos objetos se representan mediante el valor real del objeto. Si se asigna
una instancia de un tipo de valor a una variable, esa variable obtiene una copia reciente del valor.
Los tipos de referencia son tipos de datos cuyos objetos se representan mediante una referencia (similar a un
puntero) al valor real del objeto. Si se asigna un tipo de referencia a una variable, esa variable hace referencia (o
apunta) al valor original. No se realiza ninguna copia.
Common Type System en .NET admite las cinco categorías de tipos siguientes:
Clases
Estructuras
Enumeraciones
Interfaces
Delegados
Clases
Una clase es un tipo de referencia que se puede derivar directamente de otra clase y que se deriva implícitamente
de System.Object. La clase define las operaciones que un objeto (que es una instancia de la clase) puede realizar
(métodos, eventos o propiedades) y los datos que el objeto contiene (campos). Aunque una clase suele incluir una
definición y una implementación (a diferencia, por ejemplo, de las interfaces, que solo contienen una definición sin
implementación), puede tener uno o varios miembros sin implementación.
En la tabla siguiente se describen algunas de las características que una clase puede tener. Cada lenguaje
compatible con el motor en tiempo de ejecución proporciona una forma de indicar que una clase o un miembro de
clase tiene una o varias de estas características. En cambio, puede que no estén disponibles todas estas
características en los lenguajes de programación orientados a .NET.

CARACTERÍSTICA DESCRIPCIÓN

sealed Especifica que no se puede derivar otra clase de este tipo.

implementa Indica que la clase utiliza una o varias interfaces


proporcionando implementaciones de miembros de la interfaz.

abstract Indica que no se pueden crear instancias de la clase. Para


utilizarla se debe derivar de ella otra clase.

hereda Indica que las instancias de la clase se pueden utilizar en


cualquier lugar en que se especifique la clase base. Una clase
derivada que hereda de una clase base puede usar la
implementación de cualquier miembro público proporcionado
por la clase base o la clase derivada puede invalidar la
implementación de los miembros públicos con su propia
implementación.

exported o not exported Indica si una clase está visible fuera del ensamblado en el que
se define. Esta característica se aplica únicamente a las clases
de nivel superior y no a las clases anidadas.

NOTE
Una clase también puede estar anidada en una estructura o clase primaria. Las clases anidadas tienen también características
de miembro. Para obtener más información, consulte Tipos anidados.

Los miembros de clase que no tienen implementación son miembros abstractos. Una clase que tiene uno o varios
miembros abstractos es abstracta y no se pueden crear nuevas instancias de ella. Algunos lenguajes destinados al
motor en tiempo de ejecución permiten marcar una clase como abstracta incluso aunque no tenga ningún
miembro abstracto. Se puede usar una clase abstracta cuando se desea encapsular un conjunto básico de
funcionalidad que las clases derivadas pueden heredar o invalidar según corresponda. Las clases que no son
abstractas se conocen como clases concretas.
Una clase puede implementar cualquier número de interfaces pero puede heredar solo de una clase base además
de la clase System.Object, de la que todas las clases heredan implícitamente. Todas las clases deben tener al menos
un constructor, que inicializa nuevas instancias de la clase. Si no se define explícitamente un constructor, la mayoría
de los compiladores proporcionarán automáticamente un constructor sin parámetros.
Estructuras
Una estructura es un tipo de valor que se deriva implícitamente de System.ValueType, que a su vez se deriva de
System.Object. Una estructura es muy útil para representar valores cuyos requisitos de memoria son reducidos y
para pasar valores como parámetros por valor a los métodos que tienen parámetros fuertemente tipados. En .NET,
todos los tipos de datos primitivos (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte,
Single, UInt16, UInt32 y UInt64) se definen como estructuras.
Al igual que las clases, las estructuras definen datos (los campos de la estructura) y las operaciones que se pueden
realizar con esos datos (los métodos de la estructura). Esto significa que se puede llamar a los métodos en las
estructuras, incluso a los métodos virtuales definidos en las clases System.Object y System.ValueType, y a cualquier
método definido en el propio tipo de valor. Es decir, las estructuras pueden tener campos, propiedades y eventos,
así como métodos estáticos y no estáticos. Se pueden crear instancias de las estructuras, pasarlas como
parámetros, almacenarlas como variables locales o almacenarlas en un campo de otro tipo de valor o tipo de
referencia. Las estructuras también pueden implementar interfaces.
Los tipos de valor también difieren de las clases en varios aspectos. En primer lugar, aunque heredan
implícitamente de System.ValueType, no pueden heredar directamente de ningún tipo. De manera similar, todos los
tipos de valor están sellados, lo que quiere decir que de ellos no se puede derivar ningún otro tipo. Tampoco
necesitan constructores.
Para cada tipo de valor, Common Language Runtime proporciona un tipo correspondiente al que se ha aplicado la
conversión boxing, que es una clase que tiene el mismo estado y comportamiento que el tipo de valor. A una
instancia de un tipo de valor se le aplica la conversión boxing cuando se pasa a un método que acepta un
parámetro de tipo System.Object. Se le aplica la conversión unboxing (es decir, se vuelve a convertir la instancia de
una clase en una instancia de un tipo de valor) cuando se devuelve el control de una llamada a un método que
acepta un tipo de valor como parámetro por referencia. En el caso de algunos lenguajes, se debe usar una sintaxis
especial cuando se necesita el tipo al que se haya aplicado la conversión boxing, mientras que otros emplean el tipo
automáticamente cuando es necesario. Cuando se define un tipo de valor, se definen los dos tipos: al que se ha
aplicado la conversión boxing y al que se ha aplicado la conversión unboxing.
Enumeraciones
Una enumeración (enum) es un tipo de valor que hereda directamente de System.Enum y proporciona nombres
alternativos para los valores de un tipo primitivo subyacente. Un tipo de enumeración tiene un nombre, un tipo
subyacente que debe ser uno de los tipos de enteros con o sin signo integrados (como Byte, Int32 o UInt64) y un
conjunto de campos. Los campos son campos literales estáticos, cada uno de los cuales representa una constante.
El mismo valor se puede asignar a varios campos. Cuando esto sucede, se debe marcar uno de los valores como
valor de enumeración primario para la reflexión y la conversión de cadenas.
Se puede asignar un valor del tipo subyacente a una enumeración y viceversa, y no es necesario que el motor en
tiempo de ejecución realice una conversión. Se puede crear una instancia de una enumeración y llamar a los
métodos de System.Enum, además de llamar a cualquier método definido en el tipo subyacente de la enumeración.
Sin embargo, algunos lenguajes no permiten pasar una enumeración como parámetro cuando se necesita una
instancia del tipo subyacente (o viceversa).
A las enumeraciones se les aplican las restricciones siguientes:
No pueden definir sus propios métodos.
No pueden implementar interfaces.
No pueden definir propiedades ni eventos.
No pueden ser genéricas, a menos que sean genéricas solo porque están anidadas dentro de un tipo
genérico. Es decir, una enumeración no puede tener parámetros de tipo propios.

NOTE
Los tipos anidados (incluidas las enumeraciones) creados con Visual Basic, C# y C++ incluyen los parámetros de tipo
de todos los tipos genéricos envolventes, por lo que son genéricos aunque no tengan parámetros de tipo propios.
Para obtener más información, vea la sección "Tipos anidados" en el tema de referencia del método
Type.MakeGenericType.

El atributo FlagsAttribute indica una clase especial de enumeración denominada campo de bits. El motor en tiempo
de ejecución no distingue entre enumeraciones tradicionales y campos de bits, pero el lenguaje podría hacerlo.
Cuando se hace esta distinción, se pueden utilizar operadores bit a bit en estos campos de bits, para generar
valores sin nombre, pero no en las enumeraciones. Normalmente, las enumeraciones se utilizan para listas de
elementos únicos, como los días de la semana, los nombres de países o regiones, etc. Los campos de bits se
utilizan, en general, para listas de calidades o cantidades que pueden producirse en combinaciones, como
Red And Big And Fast .

En el ejemplo siguiente se muestra cómo utilizar los campos de bits y las enumeraciones tradicionales.

using System;
using System.Collections.Generic;

// A traditional enumeration of some root vegetables.


public enum SomeRootVegetables
{
HorseRadish,
Radish,
Turnip
}

// A bit field or flag enumeration of harvesting seasons.


[Flags]
public enum Seasons
{
None = 0,
Summer = 1,
Autumn = 2,
Winter = 4,
Spring = 8,
All = Summer | Autumn | Winter | Spring
}

public class Example


{
public static void Main()
{
// Hash table of when vegetables are available.
Dictionary<SomeRootVegetables, Seasons> AvailableIn = new Dictionary<SomeRootVegetables, Seasons>();

AvailableIn[SomeRootVegetables.HorseRadish] = Seasons.All;
AvailableIn[SomeRootVegetables.Radish] = Seasons.Spring;
AvailableIn[SomeRootVegetables.Turnip] = Seasons.Spring |
Seasons.Autumn;

// Array of the seasons, using the enumeration.


Seasons[] theSeasons = new Seasons[] { Seasons.Summer, Seasons.Autumn,
Seasons.Winter, Seasons.Spring };

// Print information of what vegetables are available each season.


foreach (Seasons season in theSeasons)
{
Console.Write(String.Format(
"The following root vegetables are harvested in {0}:\n",
season.ToString("G")));
foreach (KeyValuePair<SomeRootVegetables, Seasons> item in AvailableIn)
{
// A bitwise comparison.
if (((Seasons)item.Value & season) > 0)
Console.Write(String.Format(" {0:G}\n",
(SomeRootVegetables)item.Key));
}
}
}
}
// The example displays the following output:
// The following root vegetables are harvested in Summer:
// HorseRadish
// The following root vegetables are harvested in Autumn:
// The following root vegetables are harvested in Autumn:
// Turnip
// HorseRadish
// The following root vegetables are harvested in Winter:
// HorseRadish
// The following root vegetables are harvested in Spring:
// Turnip
// Radish
// HorseRadish
Imports System.Collections.Generic

' A traditional enumeration of some root vegetables.


Public Enum SomeRootVegetables
HorseRadish
Radish
Turnip
End Enum

' A bit field or flag enumeration of harvesting seasons.


<Flags()> Public Enum Seasons
None = 0
Summer = 1
Autumn = 2
Winter = 4
Spring = 8
All = Summer Or Autumn Or Winter Or Spring
End Enum

' Entry point.


Public Class Example
Public Shared Sub Main()
' Hash table of when vegetables are available.
Dim AvailableIn As New Dictionary(Of SomeRootVegetables, Seasons)()

AvailableIn(SomeRootVegetables.HorseRadish) = Seasons.All
AvailableIn(SomeRootVegetables.Radish) = Seasons.Spring
AvailableIn(SomeRootVegetables.Turnip) = Seasons.Spring Or _
Seasons.Autumn

' Array of the seasons, using the enumeration.


Dim theSeasons() As Seasons = {Seasons.Summer, Seasons.Autumn, _
Seasons.Winter, Seasons.Spring}

' Print information of what vegetables are available each season.


For Each season As Seasons In theSeasons
Console.WriteLine(String.Format( _
"The following root vegetables are harvested in {0}:", _
season.ToString("G")))
For Each item As KeyValuePair(Of SomeRootVegetables, Seasons) In AvailableIn
' A bitwise comparison.
If(CType(item.Value, Seasons) And season) > 0 Then
Console.WriteLine(" " + _
CType(item.Key, SomeRootVegetables).ToString("G"))
End If
Next
Next
End Sub
End Class
' The example displays the following output:
' The following root vegetables are harvested in Summer:
' HorseRadish
' The following root vegetables are harvested in Autumn:
' Turnip
' HorseRadish
' The following root vegetables are harvested in Winter:
' HorseRadish
' The following root vegetables are harvested in Spring:
' Turnip
' Radish
' HorseRadish

Interfaces
Una interfaz define un contrato que especifica una relación de lo que se puede hacer o una relación de lo que se
tiene. Las interfaces se utilizan a menudo para implementar una funcionalidad, como comparar y ordenar
(interfaces IComparable e IComparable<T>), comprobar la igualdad (interfaz IEquatable<T>) o enumerar los
elementos de una colección (interfaces IEnumerable e IEnumerable<T>). Las interfaces pueden tener propiedades,
métodos y eventos, que son todos miembros abstractos; es decir, aunque la interfaz define los miembros y sus
firmas, deja que el tipo encargado de implementar la interfaz defina la funcionalidad de cada miembro de la
interfaz. Esto significa que cualquier clase o estructura que implemente una interfaz debe proporcionar definiciones
de los miembros abstractos declarados en la interfaz. Una interfaz puede necesitar que cualquier clase o estructura
que implemente una interfaz implemente también otras interfaces.
A las interfaces se les aplican las restricciones siguientes:
Una interfaz se puede declarar con cualquier tipo de accesibilidad, pero los miembros de la interfaz deben
tener todos accesibilidad pública.
Las interfaces no pueden definir constructores
Las interfaces no pueden definir campos.
Las interfaces solo pueden definir miembros de instancia. No pueden definir miembros estáticos.
Cada lenguaje debe proporcionar reglas para asignar una implementación a la interfaz que necesita el miembro, ya
que varias interfaces pueden declarar un miembro con la misma firma y esos miembros pueden tener
implementaciones independientes.
Delegados
Los delegados son tipos de referencia con una finalidad similar a la de los punteros a función de C++. Se usan para
los controladores de eventos y las funciones de devolución de llamada en .NET. A diferencia de los punteros a
función, los delegados son seguros, se pueden comprobar y proporcionan seguridad de tipos. Un tipo de delegado
puede representar cualquier método de instancia o método estático que tenga una firma compatible.
Un parámetro de un delegado es compatible con el parámetro correspondiente de un método si el tipo del
parámetro del delegado es más restrictivo que el del método, porque así se garantiza que el argumento que se
pase al delegado también se podrá pasar de forma segura al método.
De forma similar, el tipo de valor devuelto de un delegado es compatible con el tipo de valor devuelto de un
método si el del método es más restrictivo que el del delegado, porque así se garantiza que el tipo de valor
devuelto por el método se puede convertir con seguridad al tipo de valor devuelto del delegado.
Por ejemplo, un delegado que tiene un parámetro de tipo IEnumerable y un tipo de valor devuelto Object puede
representar un método que tiene un parámetro de tipo Object y un valor devuelto de tipo IEnumerable. Para
obtener más información y un código de ejemplo, vea Delegate.CreateDelegate(Type, Object, MethodInfo).
Se dice que un delegado está enlazado al método que representa. Además de estar enlazado al método, un
delegado puede estar enlazado a un objeto. El objeto representa el primer parámetro del método y se pasa al
método cada vez que se invoca el delegado. Si el método es un método de instancia, el objeto enlazado se pasa
como el parámetro this implícito ( Me en Visual Basic); si el método es estático, el objeto se pasa como primer
parámetro formal del método y la firma del delegado debe coincidir con los parámetros restantes. Para obtener
más información y un código de ejemplo, vea System.Delegate.
Todos los delegados heredan de System.MulticastDelegate, que hereda de System.Delegate. Los lenguajes C#,
Visual Basic y C++ no permiten que se herede de estos tipos. En su lugar, proporcionan palabras clave para
declarar los delegados.
Dado que los delegados heredan de MulticastDelegate, un delegado tiene una lista de invocación, que es una lista
de métodos que representa el delegado y que se ejecutan cuando se llama al delegado. Todos los métodos de la
lista reciben los argumentos proporcionados cuando se invoca al delegado.
NOTE
El valor devuelto no se define para los delegados que tienen más de un método en su lista de invocación, aunque el delegado
tenga un tipo de valor devuelto.

En muchos casos, como en el de los métodos de devolución de llamada, un delegado solo representa un método y
las únicas acciones que se deben llevar a cabo son la creación y la invocación del delegado.
Por lo que se refiere a los delegados que representan varios métodos, .NET proporciona métodos de las clases de
delegado Delegate y MulticastDelegate para operaciones tales como agregar un método a una lista de invocación
del delegado (el método Delegate.Combine), quitar un método (el método Delegate.Remove) y obtener la lista de
invocación (el método Delegate.GetInvocationList).

NOTE
No es preciso usar estos métodos para los delegados de controladores de eventos en C#, C++ ni Visual Basic, ya que estos
lenguajes proporcionan sintaxis para agregar y quitar controladores de eventos.

Definiciones de tipos
Una definición de tipo incluye lo siguiente:
Los atributos definidos en el tipo.
La accesibilidad del tipo (visibilidad).
El nombre del tipo.
El tipo base del tipo.
Las interfaces que implementa el tipo.
Las definiciones de todos los miembros del tipo
Atributos
Los atributos proporcionan metadatos adicionales definidos por el usuario . Normalmente, se emplean para
almacenar información adicional sobre un tipo en su ensamblado o para modificar el comportamiento de un
miembro de tipo en tiempo de diseño o en tiempo de ejecución.
Los atributos son clases que heredan de System.Attribute. Los lenguajes que admiten el uso de atributos tienen su
propia sintaxis para aplicar atributos a un elemento del lenguaje. Los atributos se pueden aplicar a casi cualquier
elemento del lenguaje; los elementos específicos a los que se puede aplicar un atributo los define la clase
AttributeUsageAttribute aplicada a esa clase de atributos.
Accesibilidad a tipos
Todos los tipos tienen un modificador que rige su accesibilidad desde otros tipos. En la tabla siguiente se describen
las accesibilidades a tipos que admite el motor en tiempo de ejecución.

ACCESIBILIDAD DESCRIPCIÓN

public Todos los ensamblados pueden tener acceso al tipo.

ensamblado El tipo sólo es accesible desde su ensamblado.

La accesibilidad de un tipo anidado depende de su dominio de accesibilidad, que viene determinado por la
accesibilidad declarada del miembro y el dominio de accesibilidad del tipo contenedor inmediato. Sin embargo, el
dominio de accesibilidad de un tipo anidado no puede superar al del tipo contenedor.
El dominio de accesibilidad de un miembro anidado M declarado en un tipo T dentro de un programa P se
define de la manera siguiente (teniendo en cuenta que el propio miembro M puede ser un tipo):
Si la accesibilidad declarada de M es public , el dominio de accesibilidad de M es el dominio de
accesibilidad de T .
Si la accesibilidad declarada de M es protected internal , el dominio de accesibilidad de M es la
intersección del dominio de accesibilidad de T con el texto de programa de P y el texto de programa de
cualquier tipo derivado de T declarado fuera de P .
Si la accesibilidad declarada de M es protected , el dominio de accesibilidad de M es la intersección del
dominio de accesibilidad de T con el texto de programa de T y cualquier tipo derivado de T .
Si la accesibilidad declarada de M es internal , el dominio de accesibilidad de M es la intersección del
dominio de accesibilidad de T con el texto de programa de P .
Si la accesibilidad declarada de M es private , el dominio de accesibilidad de M es el texto de programa de
T .

Nombres de tipo
El sistema de tipos común sólo impone dos restricciones en los nombres:
Todos los nombres se codifican como cadenas de caracteres Unicode (de 16 bits).
Los nombres no pueden tener un valor incrustado (de 16 bits) de 0x0000.
Sin embargo, la mayoría de los lenguajes imponen restricciones adicionales sobre los nombres de tipo. Todas las
comparaciones se realizan byte a byte, por lo que distinguen entre mayúsculas y minúsculas y son independientes
de la configuración regional.
Aunque un tipo puede hacer referencia a tipos de otros módulos y ensamblados, es preciso que se defina
íntegramente en un solo módulo de .NET. (Sin embargo, según la compatibilidad del compilador, se puede dividir
en varios archivos de código fuente.) Los nombres de tipo solo tienen que ser únicos dentro de un espacio de
nombres. Para identificar íntegramente un tipo, su nombre debe calificarse con el espacio de nombres que contiene
la implementación del tipo.
Tipos base e interfaces
Un tipo puede heredar valores y comportamientos de otro. El sistema de tipos común no permite que los tipos
hereden de más de un tipo base.
Un tipo puede implementar cualquier número de interfaces. Para implementar una interfaz, un tipo debe
implementar todos los miembros virtuales de la interfaz. Un tipo derivado puede implementar un método virtual,
que se puede invocar estática o dinámicamente.

Miembros de tipos
El motor en tiempo de ejecución permite definir miembros de tipos, que especifican el comportamiento y el estado
de los tipos. Los miembros de tipos incluyen lo siguiente:
Campos
Propiedades
Métodos
Constructores
Eventos
Tipos anidados
Campos
Un campo describe y contiene parte del estado del tipo. Los campos pueden ser de cualquier tipo que admita el
motor en tiempo de ejecución. Normalmente, los campos son de tipo private o protected , por lo que son
accesibles únicamente desde la clase o desde una clase derivada. Si el valor de un campo se puede modificar desde
fuera de su tipo, se suele emplear un descriptor de acceso set de una propiedad. Los campos expuestos
públicamente suelen ser de solo lectura y pueden ser de dos tipos:
Constantes, cuyo valor se asigna en tiempo de diseño. Se trata de miembros estáticos de una clase, aunque
no se definen mediante la palabra clave static ( Shared en Visual Basic).
Variables de solo lectura, cuyos valores se pueden asignar en el constructor de clase.
En el ejemplo siguiente se muestran estos dos usos de los campos de solo lectura.

using System;

public class Constants


{
public const double Pi = 3.1416;
public readonly DateTime BirthDate;

public Constants(DateTime birthDate)


{
this.BirthDate = birthDate;
}
}

public class Example


{
public static void Main()
{
Constants con = new Constants(new DateTime(1974, 8, 18));
Console.Write(Constants.Pi + "\n");
Console.Write(con.BirthDate.ToString("d") + "\n");
}
}
// The example displays the following output if run on a system whose current
// culture is en-US:
// 3.1416
// 8/18/1974
Public Class Constants
Public Const Pi As Double = 3.1416
Public ReadOnly BirthDate As Date

Public Sub New(birthDate As Date)


Me.BirthDate = birthDate
End Sub
End Class

Public Module Example


Public Sub Main()
Dim con As New Constants(#8/18/1974#)
Console.WriteLine(Constants.Pi.ToString())
Console.WriteLine(con.BirthDate.ToString("d"))
End Sub
End Module
' The example displays the following output if run on a system whose current
' culture is en-US:
' 3.1416
' 8/18/1974

Propiedades
Una propiedad identifica un valor o un estado del tipo y define los métodos para obtener o establecer el valor de la
propiedad. Las propiedades pueden ser tipos primitivos, colecciones de tipos primitivos, tipos definidos por el
usuario o colecciones de tipos definidos por el usuario. Las propiedades se usan a menudo para que la interfaz
pública de un tipo se mantenga independiente de la representación real del tipo. De este modo, las propiedades
pueden reflejar valores que no están almacenados directamente en la clase (por ejemplo, cuando una propiedad
devuelve un valor calculado) o realizar la validación antes de que se asignen valores a campos privados. En el
ejemplo siguiente se muestra el último modelo.

using System;

public class Person


{
private int m_Age;

public int Age


{
get { return m_Age; }
set {
if (value < 0 || value > 125)
{
throw new ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.");
}
else
{
m_Age = value;
}
}
}
}
Public Class Person
Private m_Age As Integer

Public Property Age As Integer


Get
Return m_Age
End Get
Set
If value < 0 Or value > 125 Then
Throw New ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.")
Else
m_Age = value
End If
End Set
End Property
End Class

Además de incluir la propiedad propiamente dicha, el Lenguaje Intermedio de Microsoft (MSIL ) de un tipo que
contiene una propiedad de lectura incluye un método get_ propertyname y el lenguaje MSIL de un tipo que
contiene una propiedad de escritura incluye un método set_ propertyname.
Métodos
Un método describe las operaciones que están disponibles en el tipo. La firma de un método especifica los tipos
permitidos de todos sus parámetros y de su valor devuelto.
Aunque la mayoría de los métodos definen el número exacto de los parámetros necesarios para las llamadas a
métodos, algunos admiten un número de parámetros que es variable. El último parámetro declarado de estos
métodos se marca con el atributo ParamArrayAttribute. Normalmente, los compiladores de lenguaje proporcionan
una palabra clave, como params en C# y ParamArray en Visual Basic, que hace que sea innecesario el uso explícito
de ParamArrayAttribute.
Constructores
Un constructor es un tipo de método especial que crea nuevas instancias de una clase o una estructura. Al igual
que cualquier otro método, un constructor puede incluir parámetros; sin embargo, los constructores no tienen
ningún valor devuelto (es decir, devuelven void ).
Si el código fuente de una clase no define explícitamente un constructor, el compilador incluye un constructor sin
parámetros. Sin embargo, si el código fuente de una clase define solo constructores parametrizados, los
compiladores de Visual Basic y C# no generan un constructor sin parámetros.
Si el código fuente de una estructura define constructores, estos deben tener parámetros; una estructura no puede
definir un constructor sin parámetros y los compiladores no generan constructores sin parámetros para las
estructuras u otros tipos de valor. Todos los tipos de valor tienen un constructor sin parámetros implícito. Common
Language Runtime implementa este constructor, que inicializa todos los campos de la estructura en sus valores
predeterminados.
Events
Un evento define un incidente al que se puede responder, así como los métodos para suscribirse a un evento,
anular la suscripción y generar el evento. Los eventos se usan con frecuencia para informar a otros tipos de
cambios de estado. Para más información, vea Eventos.
Tipos anidados
Un tipo anidado es un tipo que es un miembro de algún otro tipo. Los tipos anidados deben estar estrechamente
acoplados a su tipo contenedor y no deben ser útiles como tipos de uso general. Los tipos anidados son útiles
cuando el tipo declarativo utiliza y crea instancias del tipo anidado y el uso de dicho tipo anidado no se expone en
miembros públicos.
Los tipos anidados resultan confusos para algunos desarrolladores y no deben estar públicamente visibles a menos
que haya una razón de peso. En una biblioteca bien diseñada, los desarrolladores rara vez deberían tener que
utilizar tipos anidados para crear instancias de objetos o declarar variables.

Características de los miembros de tipos


Common Type System permite que los miembros de tipos tengan diversas características; sin embargo, no es
necesario que los lenguajes admitan todas estas características. En la siguiente tabla se describen las características
de los miembros.

CARACTERÍSTICA SE PUEDE APLICAR A DESCRIPCIÓN

abstract Métodos, propiedades y eventos El tipo no proporciona la


implementación del método. Los tipos
que heredan o implementan métodos
abstractos deben proporcionar una
implementación para el método. La
única excepción es que el tipo derivado
sea un tipo abstracto. Todos lo métodos
abstractos son virtuales.

private, family, assembly, family y Todas Define la accesibilidad del miembro:


assembly, family o assembly, o public
private
Solo es accesible desde el mismo tipo
que el miembro o desde un tipo
anidado.

family
Accesible desde el mismo tipo que el
miembro y desde tipos derivados que
heredan de él.

ensamblado
Accesible sólo en el ensamblado en que
está definido el tipo.

family y assembly
Accesible sólo desde los tipos que estén
calificados para el acceso de familia y
ensamblado.

family o assembly
Accesible sólo desde los tipos que
califican el acceso de familia o
ensamblado.

public
Accesible desde cualquier tipo.

final Métodos, propiedades y eventos El método virtual no puede ser


reemplazado en un tipo derivado.

initialize-only Campos El valor sólo se puede inicializar y no se


puede escribir en él después de la
inicialización.
CARACTERÍSTICA SE PUEDE APLICAR A DESCRIPCIÓN

instancia Campos, métodos, propiedades y Si un miembro no está marcado como


eventos static (C# y C++), Shared (Visual
Basic), virtual (C# y C++) u
Overridable (Visual Basic), es un
miembro de instancia (no hay palabra
clave de la instancia). En la memoria
habrá tantas copias de estos miembros
como objetos que los utilicen.

Literal Campos El valor asignado al campo es un valor


fijo, conocido en tiempo de compilación,
de un tipo de valor integrado. Los
campos literales, a veces, se conocen
como constantes.

newslot u override Todas Define cómo interactúa el miembro con


los miembros heredados que tienen la
misma firma:

newslot
Oculta los miembros heredados que
tienen la misma firma.

override
Reemplaza la definición de un método
virtual heredado.

El valor predeterminado es newslot.

estático Campos, métodos, propiedades y El miembro pertenece al tipo en que


eventos está definido, no a una instancia
particular del tipo. El miembro existe
incluso si no se ha creado ninguna
instancia del tipo y lo comparten todas
las instancias del tipo.

virtual Métodos, propiedades y eventos Un tipo derivado puede implementar el


método, que se puede invocar estática
o dinámicamente. Si se usa la invocación
dinámica, el tipo de la instancia que
hace la llamada en tiempo de ejecución
(en lugar del tipo conocido en tiempo
de compilación) determina a qué
implementación del método se llama.
Para invocar un método virtual de
manera estática, es posible que haya
que convertir la variable en un tipo que
use la versión deseada del método.

Sobrecarga
Cada miembro de tipo tiene una firma única. Las firmas de método están formadas por el nombre del método y
una lista de parámetros (el orden y los tipos de los argumentos del método). Se pueden definir varios métodos con
el mismo nombre dentro un tipo, siempre y cuando sus firmas sean distintas. Cuando se definen dos o más
métodos con el mismo nombre se dice que el método está sobrecargado. Por ejemplo, en System.Char, se
reemplaza el método IsDigit. Un método toma un argumento de tipo Char. El otro método toma un argumento de
tipo String y un argumento de tipo Int32.
NOTE
El tipo de valor devuelto no se considera parte de la firma de un método. Es decir, no se pueden sobrecargar los métodos si
solo difieren en el tipo de valor devuelto.

Heredar, reemplazar y ocultar miembros


Un tipo derivado hereda todos los miembros de su tipo base, es decir, estos miembros se definen en el tipo
derivado y están disponibles para él. El comportamiento o cualidades de los miembros heredados se puede
modificar de dos maneras:
Un tipo derivado puede ocultar un miembro heredado definiendo un nuevo miembro con la misma firma.
Esto puede hacerse para convertir un miembro público en privado o para definir un nuevo comportamiento
para un método heredado que está marcado como final .
Un tipo derivado puede reemplazar a un método virtual heredado. El método de reemplazo proporciona
una nueva definición del método que se invocará según el tipo del valor en tiempo de ejecución y no el tipo
de la variable conocido en tiempo de compilación. Un método puede invalidar un método virtual
únicamente si el método virtual no está marcado como final y el nuevo método es, al menos, tan accesible
como el método virtual.

Vea también
Explorador de API de .NET
Common Language Runtime
Conversión de tipos en .NET
Conversión de tipos en .NET Framework
25/11/2019 • 42 minutes to read • Edit Online

Cada valor tiene un tipo asociado, que define atributos como la cantidad de espacio asignado al valor, el intervalo
de valores posibles que puede tener y los miembros que ofrece. Muchos valores se pueden expresar como más de
un tipo. Por ejemplo, el valor 4 se puede expresar como un entero o como un valor de punto flotante. La
conversión de tipo crea un valor en un nuevo tipo que es equivalente al valor de un tipo antiguo, pero no conserva
necesariamente la identidad (o valor exacto) del objeto original.
.NET Framework admite automáticamente las conversiones siguientes:
Conversión de una clase derivada a una clase base. Esto significa, por ejemplo, que una instancia de
cualquier clase o estructura se puede convertir en una instancia de tipo Object. Esta conversión no requiere
un operador de conversión.
Conversión de una clase base a la clase derivada original. En C#, esta conversión requiere un operador de
conversión. En Visual Basic, requiere el operador CType si Option Strict está activado.
Conversión de un tipo que implementa una interfaz a un objeto de interfaz que representa esa interfaz. Esta
conversión no requiere un operador de conversión.
Conversión de un objeto de interfaz al tipo original que implementa esa interfaz. En C#, esta conversión
requiere un operador de conversión. En Visual Basic, requiere el operador CType si Option Strict está
activado.
Además de estas conversiones automáticas, .NET Framework proporciona varias características que admiten la
conversión de tipos personalizada. Entre ellas se incluyen las siguientes:
El operador Implicit , que define las conversiones de ampliación disponibles entre los tipos. Para obtener
más información, consulte la sección Conversión implícita con el operador Implicit.
El operador Explicit , que define las conversiones de restricción disponibles entre los tipos. Para obtener
más información, consulte la sección Conversión explícita con el operador Explicit.
La interfaz IConvertible, que define las conversiones en cada uno de los tipos de datos base de .NET
Framework. Para obtener más información, vea Interfaz IConvertible.
La clase Convert, que proporciona un conjunto de métodos que implementan los métodos de la interfaz
IConvertible. Para obtener más información, vea la sección Clase Convert.
La clase TypeConverter, que es una clase base que se puede extender para admitir la conversión de un tipo
concreto en cualquier otro tipo. Para obtener más información, vea Clase TypeConverter.

Conversión implícita con el operador Implicit


Las conversiones de ampliación implican la creación de un nuevo valor a partir del valor de un tipo existente que
tiene un intervalo más restrictivo o una lista de miembros más restringida que el tipo de destino. Las conversión
de ampliación no pueden producir ninguna pérdida de datos (aunque pueden producir una pérdida de precisión).
Puesto que no se pueden perder datos, los compiladores pueden administrar la conversión de manera implícita o
transparente, sin que sea necesario el uso de un método de conversión explícito o de un operador de conversión.
NOTE
Aunque el código que realiza una conversión implícita puede llamar a un método de conversión o usar un operador de
conversión, los compiladores que admiten las conversiones implícitas no necesitan usarlos.

Por ejemplo, el tipo Decimal admite conversiones implícitas a partir de valores Byte, Char, Int16, Int32, Int64,
SByte, UInt16, UInt32 y UInt64. En el ejemplo siguiente se muestran algunas de estas conversiones implícitas al
asignar valores a una variable Decimal.

byte byteValue = 16;


short shortValue = -1024;
int intValue = -1034000;
long longValue = 1152921504606846976;
ulong ulongValue = UInt64.MaxValue;

decimal decimalValue;

decimalValue = byteValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
byteValue.GetType().Name, decimalValue);

decimalValue = shortValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
shortValue.GetType().Name, decimalValue);

decimalValue = intValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
intValue.GetType().Name, decimalValue);

decimalValue = longValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
longValue.GetType().Name, decimalValue);

decimalValue = ulongValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
longValue.GetType().Name, decimalValue);
// The example displays the following output:
// After assigning a Byte value, the Decimal value is 16.
// After assigning a Int16 value, the Decimal value is -1024.
// After assigning a Int32 value, the Decimal value is -1034000.
// After assigning a Int64 value, the Decimal value is 1152921504606846976.
// After assigning a Int64 value, the Decimal value is 18446744073709551615.
Dim byteValue As Byte = 16
Dim shortValue As Short = -1024
Dim intValue As Integer = -1034000
Dim longValue As Long = CLng(1024^6)
Dim ulongValue As ULong = ULong.MaxValue

Dim decimalValue As Decimal

decimalValue = byteValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
byteValue.GetType().Name, decimalValue)

decimalValue = shortValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
shortValue.GetType().Name, decimalValue)

decimalValue = intValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
intValue.GetType().Name, decimalValue)

decimalValue = longValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
longValue.GetType().Name, decimalValue)

decimalValue = ulongValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
longValue.GetType().Name, decimalValue)
' The example displays the following output:
' After assigning a Byte value, the Decimal value is 16.
' After assigning a Int16 value, the Decimal value is -1024.
' After assigning a Int32 value, the Decimal value is -1034000.
' After assigning a Int64 value, the Decimal value is 1152921504606846976.
' After assigning a Int64 value, the Decimal value is 18446744073709551615.

Si un compilador de un lenguaje determinado admite operadores personalizados, también puede definir


conversiones implícitas en sus propios tipos personalizados. En el ejemplo siguiente se proporciona una
implementación parcial de un tipo de datos de byte con signo denominado ByteWithSign que usa la
representación de signo y magnitud. Admite la conversión implícita de valores Byte y SByte a valores
ByteWithSign .
public struct ByteWithSign
{
private SByte signValue;
private Byte value;

public static implicit operator ByteWithSign(SByte value)


{
ByteWithSign newValue;
newValue.signValue = (SByte) Math.Sign(value);
newValue.value = (byte) Math.Abs(value);
return newValue;
}

public static implicit operator ByteWithSign(Byte value)


{
ByteWithSign newValue;
newValue.signValue = 1;
newValue.value = value;
return newValue;
}

public override string ToString()


{
return (signValue * value).ToString();
}
}

Public Structure ByteWithSign


Private signValue As SByte
Private value As Byte

Public Overloads Shared Widening Operator CType(value As SByte) As ByteWithSign


Dim newValue As ByteWithSign
newValue.signValue = CSByte(Math.Sign(value))
newValue.value = CByte(Math.Abs(value))
Return newValue
End Operator

Public Overloads Shared Widening Operator CType(value As Byte) As ByteWithSign


Dim NewValue As ByteWithSign
newValue.signValue = 1
newValue.value = value
Return newValue
End Operator

Public Overrides Function ToString() As String


Return (signValue * value).ToString()
End Function
End Structure

A continuación, el código de cliente puede declarar una variable ByteWithSign y asignarle valores Byte y SByte sin
realizar ninguna conversión explícita ni emplear ningún operador de conversión, como se muestra en el ejemplo
siguiente.

SByte sbyteValue = -120;


ByteWithSign value = sbyteValue;
Console.WriteLine(value);
value = Byte.MaxValue;
Console.WriteLine(value);
// The example displays the following output:
// -120
// 255
Dim sbyteValue As SByte = -120
Dim value As ByteWithSign = sbyteValue
Console.WriteLine(value.ToString())
value = Byte.MaxValue
Console.WriteLine(value.ToString())
' The example displays the following output:
' -120
' 255

Conversión explícita con el operador Explicit


Las conversiones de restricción implican la creación de un nuevo valor a partir del valor de un tipo existente que
tiene un intervalo mayor o una lista de miembros mayor que el tipo de destino. Puesto que una conversión de
restricción puede producir una pérdida de datos, los compiladores suelen necesitar que la conversión se haga
explícita a través de una llamada a un método de conversión o a un operador de conversión. Es decir, la conversión
se debe administrar explícitamente en el código de desarrollo.

NOTE
La finalidad principal de solicitar un método de conversión o un operador de conversión para las conversiones de restricción
es que el desarrollador sea consciente de la posibilidad de que se pierdan datos o de que se produzca una excepción
OverflowException, para que se pueda administrar en el código. Sin embargo, algunos compiladores pueden ser menos
exigentes con este requisito. Por ejemplo, en Visual Basic, si Option Strict está desactivado (la configuración
predeterminada), el compilador de Visual Basic intenta realizar las conversiones de restricción implícitamente.

Por ejemplo, los tipos de datos UInt32, Int64 y UInt64 tienen intervalos que superan el del tipo de datos Int32,
como se muestra en la tabla siguiente.

TIPO COMPARACIÓN CON EL INTERVALO DE INT32

Int64 Int64.MaxValue es mayor que Int32.MaxValue, y


Int64.MinValue es menor que (tiene un intervalo negativo
mayor que) Int32.MinValue.

UInt32 UInt32.MaxValue es mayor que Int32.MaxValue.

UInt64 UInt64.MaxValue es mayor que Int32.MaxValue.

Para administrar estas conversiones de restricción, .NET Framework permite que los tipos definan un operador
Explicit . A continuación, los compiladores de lenguaje individuales pueden implementar este operador usando
su propia sintaxis o se puede llamar a un miembro de la clase Convert para realizar la conversión. (Para obtener
más información sobre la clase Convert, vea Clase Convert más adelante en este tema). En el ejemplo siguiente se
muestra el uso de las características de lenguaje para administrar la conversión explícita de estos valores enteros,
que potencialmente están fuera del intervalo, a valores Int32.
long number1 = int.MaxValue + 20L;
uint number2 = int.MaxValue - 1000;
ulong number3 = int.MaxValue;

int intNumber;

try {
intNumber = checked((int) number1);
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number1.GetType().Name, intNumber);
}
catch (OverflowException) {
if (number1 > int.MaxValue)
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number1, int.MaxValue);
else
Console.WriteLine("Conversion failed: {0} is less than {1}.",
number1, int.MinValue);
}

try {
intNumber = checked((int) number2);
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number2.GetType().Name, intNumber);
}
catch (OverflowException) {
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number2, int.MaxValue);
}

try {
intNumber = checked((int) number3);
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number3.GetType().Name, intNumber);
}
catch (OverflowException) {
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number1, int.MaxValue);
}

// The example displays the following output:


// Conversion failed: 2147483667 exceeds 2147483647.
// After assigning a UInt32 value, the Integer value is 2147482647.
// After assigning a UInt64 value, the Integer value is 2147483647.
Dim number1 As Long = Integer.MaxValue + 20L
Dim number2 As UInteger = Integer.MaxValue - 1000
Dim number3 As ULong = Integer.MaxValue

Dim intNumber As Integer

Try
intNumber = CInt(number1)
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number1.GetType().Name, intNumber)
Catch e As OverflowException
If number1 > Integer.MaxValue Then
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number1, Integer.MaxValue)
Else
Console.WriteLine("Conversion failed: {0} is less than {1}.\n",
number1, Integer.MinValue)
End If
End Try

Try
intNumber = CInt(number2)
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number2.GetType().Name, intNumber)
Catch e As OverflowException
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number2, Integer.MaxValue)
End Try

Try
intNumber = CInt(number3)
Console.WriteLine("After assigning a {0} value, the Integer value is {1}.",
number3.GetType().Name, intNumber)
Catch e As OverflowException
Console.WriteLine("Conversion failed: {0} exceeds {1}.",
number1, Integer.MaxValue)
End Try
' The example displays the following output:
' Conversion failed: 2147483667 exceeds 2147483647.
' After assigning a UInt32 value, the Integer value is 2147482647.
' After assigning a UInt64 value, the Integer value is 2147483647.

Las conversiones explícitas pueden producir resultados diferentes en los distintos lenguajes y estos resultados
pueden diferir del valor devuelto por el método Convert correspondiente. Por ejemplo, si el valor Double
12.63251 se convierte en Int32, el método CInt de Visual Basic y el método Convert.ToInt32(Double) de .NET
Framework redondean el valor Double para devolver un valor de 13, pero el operador (int) de C# trunca
Double para devolver un valor de 12. De manera similar, el operador (int) de C# no admite la conversión de
booleano a entero, pero el método CInt de Visual Basic convierte un valor de true en -1. Por otra parte, el
método Convert.ToInt32(Boolean) convierte un valor de true en 1.
La mayoría de los compiladores permiten realizar conversiones explícitas de manera comprobada o no
comprobada. Cuando se realiza una conversión comprobada, se produce una excepción OverflowException si el
valor del tipo que se va a convertir está fuera del intervalo del tipo de destino. Si se realiza una conversión no
comprobada en las mismas condiciones, es posible que la conversión no produzca una excepción, pero no se
podrá determinar con exactitud cuál será el comportamiento y se puede obtener como resultado un valor
incorrecto.
NOTE
En C#, las conversiones comprobadas se pueden realizar usando la palabra clave checked junto con un operador de
conversión o especificando la opción del compilador /checked+ . Por el contrario, las conversiones no comprobadas se
pueden realizar utilizando la palabra clave unchecked junto con el operador de conversión de tipo o especificando la opción
del compilador /checked- . De forma predeterminada, las conversiones explícitas no se comprueban. En Visual Basic, para
realizar conversiones comprobadas, se puede desactivar la casilla Quitar comprobaciones de desbordamiento con
enteros en el cuadro de diálogo Configuración de compilador avanzada del proyecto o especificando la opción de
compilador /removeintchecks- . Por el contrario, para realizar conversiones no comprobadas, se puede activar la casilla
Quitar comprobaciones de desbordamiento con enteros en el cuadro de diálogo Configuración de compilador
avanzada del proyecto o especificando la opción de compilador /removeintchecks+ . De forma predeterminada, las
conversiones explícitas se comprueban.

En el siguiente ejemplo de C# se usan las palabras clave checked y unchecked para mostrar la diferencia de
comportamiento cuando un valor que está fuera del intervalo de Byte se convierte en Byte. La conversión
comprobada produce una excepción, pero la conversión no comprobada asigna Byte.MaxValue a la variable Byte.

int largeValue = Int32.MaxValue;


byte newValue;

try {
newValue = unchecked((byte) largeValue);
Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
largeValue.GetType().Name, largeValue,
newValue.GetType().Name, newValue);
}
catch (OverflowException) {
Console.WriteLine("{0} is outside the range of the Byte data type.",
largeValue);
}

try {
newValue = checked((byte) largeValue);
Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
largeValue.GetType().Name, largeValue,
newValue.GetType().Name, newValue);
}
catch (OverflowException) {
Console.WriteLine("{0} is outside the range of the Byte data type.",
largeValue);
}
// The example displays the following output:
// Converted the Int32 value 2147483647 to the Byte value 255.
// 2147483647 is outside the range of the Byte data type.

Si un compilador de un lenguaje determinado admite operadores sobrecargados personalizados, también puede


definir conversiones explícitas en sus propios tipos personalizados. En el ejemplo siguiente se proporciona una
implementación parcial de un tipo de datos de byte con signo denominado ByteWithSign que usa la
representación de signo y magnitud. Admite la conversión explícita de valores Int32 y UInt32 a valores
ByteWithSign .
public struct ByteWithSign
{
private SByte signValue;
private Byte value;

private const byte MaxValue = byte.MaxValue;


private const int MinValue = -1 * byte.MaxValue;

public static explicit operator ByteWithSign(int value)


{
// Check for overflow.
if (value > ByteWithSign.MaxValue || value < ByteWithSign.MinValue)
throw new OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.",
value));

ByteWithSign newValue;
newValue.signValue = (SByte) Math.Sign(value);
newValue.value = (byte) Math.Abs(value);
return newValue;
}

public static explicit operator ByteWithSign(uint value)


{
if (value > ByteWithSign.MaxValue)
throw new OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.",
value));

ByteWithSign newValue;
newValue.signValue = 1;
newValue.value = (byte) value;
return newValue;
}

public override string ToString()


{
return (signValue * value).ToString();
}
}
Public Structure ByteWithSign
Private signValue As SByte
Private value As Byte

Private Const MaxValue As Byte = Byte.MaxValue


Private Const MinValue As Integer = -1 * Byte.MaxValue

Public Overloads Shared Narrowing Operator CType(value As Integer) As ByteWithSign


' Check for overflow.
If value > ByteWithSign.MaxValue Or value < ByteWithSign.MinValue Then
Throw New OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.",
value))
End If

Dim newValue As ByteWithSign

newValue.signValue = CSByte(Math.Sign(value))
newValue.value = CByte(Math.Abs(value))
Return newValue
End Operator

Public Overloads Shared Narrowing Operator CType(value As UInteger) As ByteWithSign


If value > ByteWithSign.MaxValue Then
Throw New OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.",
value))
End If

Dim NewValue As ByteWithSign

newValue.signValue = 1
newValue.value = CByte(value)
Return newValue
End Operator

Public Overrides Function ToString() As String


Return (signValue * value).ToString()
End Function
End Structure

A continuación, el código de cliente puede declarar una variable ByteWithSign y asignarle valores de tipo Int32 y
UInt32 si las asignaciones incluyen un operador de conversión o un método de conversión, como se muestra en el
ejemplo siguiente.
ByteWithSign value;

try {
int intValue = -120;
value = (ByteWithSign) intValue;
Console.WriteLine(value);
}
catch (OverflowException e) {
Console.WriteLine(e.Message);
}

try {
uint uintValue = 1024;
value = (ByteWithSign) uintValue;
Console.WriteLine(value);
}
catch (OverflowException e) {
Console.WriteLine(e.Message);
}
// The example displays the following output:
// -120
// '1024' is out of range of the ByteWithSign data type.

Dim value As ByteWithSign

Try
Dim intValue As Integer = -120
value = CType(intValue, ByteWithSign)
Console.WriteLine(value)
Catch e As OverflowException
Console.WriteLine(e.Message)
End Try

Try
Dim uintValue As UInteger = 1024
value = CType(uintValue, ByteWithSign)
Console.WriteLine(value)
Catch e As OverflowException
Console.WriteLine(e.Message)
End Try
' The example displays the following output:
' -120
' '1024' is out of range of the ByteWithSign data type.

La interfaz IConvertible
Para admitir la conversión de cualquier tipo en un tipo base de Common Language Runtime, .NET Framework
proporciona la interfaz IConvertible. El tipo que se está implementando debe proporcionar lo siguiente:
Un método que devuelva el objeto TypeCode del tipo que se está implementando.
Métodos para convertir el tipo que se está implementando en cada uno de los tipos base de Common
Language Runtime (Boolean, Byte, DateTime, Decimal, Double, etc.).
Un método de conversión generalizado para convertir una instancia del tipo que se está implementando en
otro tipo concreto. Las conversiones que no se admiten deben iniciar una excepción InvalidCastException.
Cada uno de los tipos base de Common Language Runtime (es decir, Boolean, Byte, Char, DateTime, Decimal,
Double, Int16, Int32, Int64, SByte, Single, String, UInt16, UInt32y UInt64), así como los tipos DBNull y Enum,
implementan la interfaz IConvertible. Sin embargo, se trata de implementaciones de interfaz explícitas; solo se
puede llamar al método de conversión mediante una variable de la interfaz IConvertible, como se muestra en el
ejemplo siguiente. Este ejemplo convierte un valor Int32 en su valor Char equivalente.

int codePoint = 1067;


IConvertible iConv = codePoint;
char ch = iConv.ToChar(null);
Console.WriteLine("Converted {0} to {1}.", codePoint, ch);

Dim codePoint As Integer = 1067


Dim iConv As IConvertible = codePoint
Dim ch As Char = iConv.ToChar(Nothing)
Console.WriteLine("Converted {0} to {1}.", codePoint, ch)

El requisito de llamar al método de conversión en su interfaz, en lugar de en el tipo que se está implementando,
hace que las implementaciones de interfaz explícitas resulten relativamente costosas. En su lugar, se recomienda
llamar al miembro adecuado de la clase Convert para convertir entre los tipos base de Common Language
Runtime. Para obtener más información, consulte la próxima sección, Clase Convert.

NOTE
Además de la interfaz IConvertible y la clase Convert proporcionadas por .NET Framework, cada lenguaje puede
proporcionar también maneras de realizar conversiones. Por ejemplo, C# utiliza operadores de conversión, mientras que
Visual Basic utiliza funciones de conversión implementadas por el compilador como CType , CInt y DirectCast .

En su mayor parte, la interfaz IConvertible está diseñada para admitir la conversión entre los tipos base de .NET
Framework. Sin embargo, la interfaz también puede implementarse por un tipo personalizado con el fin de
admitir la conversión de ese tipo a otros tipos personalizados. Para obtener más información, consulte la sección
Conversiones personalizadas con el método ChangeType más adelante en este tema.

Clase Convert
Aunque se puede llamar a la implementación de la interfaz IConvertible de cada tipo base para realizar una
conversión de tipo, llamar a los métodos de la clase System.Convert es la manera recomendada de convertir de un
tipo base en otro de una manera independiente del lenguaje. Además, se puede usar el método
Convert.ChangeType(Object, Type, IFormatProvider) para convertir de un tipo personalizado concreto a otro tipo.
Conversiones entre los tipos base
La clase Convert proporciona una manera independiente del lenguaje de realizar conversiones entre los tipos base
y está disponible para todos los lenguajes cuyo destino es Common Language Runtime. Ofrece un conjunto
completo de métodos tanto para conversiones de ampliación como de restricción e inicia una excepción
InvalidCastException para las conversiones que no se admiten (como la conversión de un valor DateTime a un
valor entero). Las conversiones de restricción se realizan en un contexto comprobado y se inicia una excepción
OverflowException si se produce un error en la conversión.

IMPORTANT
Puesto que la clase Convert incluye métodos para efectuar la conversión directa e inversa de cada tipo base, elimina la
necesidad de llamar a la implementación de interfaz explícita IConvertible de cada tipo base.

En el ejemplo siguiente se muestra el uso de la clase System.Convert para realizar varias conversiones de
restricción y ampliación entre los tipos base de .NET Framework.
// Convert an Int32 value to a Decimal (a widening conversion).
int integralValue = 12534;
decimal decimalValue = Convert.ToDecimal(integralValue);
Console.WriteLine("Converted the {0} value {1} to " +
"the {2} value {3:N2}.",
integralValue.GetType().Name,
integralValue,
decimalValue.GetType().Name,
decimalValue);
// Convert a Byte value to an Int32 value (a widening conversion).
byte byteValue = Byte.MaxValue;
int integralValue2 = Convert.ToInt32(byteValue);
Console.WriteLine("Converted the {0} value {1} to " +
"the {2} value {3:G}.",
byteValue.GetType().Name,
byteValue,
integralValue2.GetType().Name,
integralValue2);

// Convert a Double value to an Int32 value (a narrowing conversion).


double doubleValue = 16.32513e12;
try {
long longValue = Convert.ToInt64(doubleValue);
Console.WriteLine("Converted the {0} value {1:E} to " +
"the {2} value {3:N0}.",
doubleValue.GetType().Name,
doubleValue,
longValue.GetType().Name,
longValue);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert the {0:E} value {1}.",
doubleValue.GetType().Name, doubleValue);
}

// Convert a signed byte to a byte (a narrowing conversion).


sbyte sbyteValue = -16;
try {
byte byteValue2 = Convert.ToByte(sbyteValue);
Console.WriteLine("Converted the {0} value {1} to " +
"the {2} value {3:G}.",
sbyteValue.GetType().Name,
sbyteValue,
byteValue2.GetType().Name,
byteValue2);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert the {0} value {1}.",
sbyteValue.GetType().Name, sbyteValue);
}
// The example displays the following output:
// Converted the Int32 value 12534 to the Decimal value 12,534.00.
// Converted the Byte value 255 to the Int32 value 255.
// Converted the Double value 1.632513E+013 to the Int64 value 16,325,130,000,000.
// Unable to convert the SByte value -16.
' Convert an Int32 value to a Decimal (a widening conversion).
Dim integralValue As Integer = 12534
Dim decimalValue As Decimal = Convert.ToDecimal(integralValue)
Console.WriteLine("Converted the {0} value {1} to the {2} value {3:N2}.",
integralValue.GetType().Name,
integralValue,
decimalValue.GetType().Name,
decimalValue)

' Convert a Byte value to an Int32 value (a widening conversion).


Dim byteValue As Byte = Byte.MaxValue
Dim integralValue2 As Integer = Convert.ToInt32(byteValue)
Console.WriteLine("Converted the {0} value {1} to " +
"the {2} value {3:G}.",
byteValue.GetType().Name,
byteValue,
integralValue2.GetType().Name,
integralValue2)

' Convert a Double value to an Int32 value (a narrowing conversion).


Dim doubleValue As Double = 16.32513e12
Try
Dim longValue As Long = Convert.ToInt64(doubleValue)
Console.WriteLine("Converted the {0} value {1:E} to " +
"the {2} value {3:N0}.",
doubleValue.GetType().Name,
doubleValue,
longValue.GetType().Name,
longValue)
Catch e As OverflowException
Console.WriteLine("Unable to convert the {0:E} value {1}.",
doubleValue.GetType().Name, doubleValue)
End Try

' Convert a signed byte to a byte (a narrowing conversion).


Dim sbyteValue As SByte = -16
Try
Dim byteValue2 As Byte = Convert.ToByte(sbyteValue)
Console.WriteLine("Converted the {0} value {1} to " +
"the {2} value {3:G}.",
sbyteValue.GetType().Name,
sbyteValue,
byteValue2.GetType().Name,
byteValue2)
Catch e As OverflowException
Console.WriteLine("Unable to convert the {0} value {1}.",
sbyteValue.GetType().Name, sbyteValue)
End Try
' The example displays the following output:
' Converted the Int32 value 12534 to the Decimal value 12,534.00.
' Converted the Byte value 255 to the Int32 value 255.
' Converted the Double value 1.632513E+013 to the Int64 value 16,325,130,000,000.
' Unable to convert the SByte value -16.

En algunos casos, en especial al efectuar conversiones directas e inversas de valores de punto flotante, una
conversión puede conllevar una pérdida de precisión, aunque no se inicie una excepción OverflowException. En el
ejemplo siguiente se muestra esta pérdida de precisión. En el primer caso, un valor Decimal tiene menos precisión
(menos dígitos significativos) cuando se convierte en el tipo Double. En el segundo caso, un valor Double se
redondea de 42,72 a 43 para completar la conversión.
double doubleValue;

// Convert a Double to a Decimal.


decimal decimalValue = 13956810.96702888123451471211m;
doubleValue = Convert.ToDouble(decimalValue);
Console.WriteLine("{0} converted to {1}.", decimalValue, doubleValue);

doubleValue = 42.72;
try {
int integerValue = Convert.ToInt32(doubleValue);
Console.WriteLine("{0} converted to {1}.",
doubleValue, integerValue);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert {0} to an integer.",
doubleValue);
}
// The example displays the following output:
// 13956810.96702888123451471211 converted to 13956810.9670289.
// 42.72 converted to 43.

Dim doubleValue As Double

' Convert a Double to a Decimal.


Dim decimalValue As Decimal = 13956810.96702888123451471211d
doubleValue = Convert.ToDouble(decimalValue)
Console.WriteLine("{0} converted to {1}.", decimalValue, doubleValue)

doubleValue = 42.72
Try
Dim integerValue As Integer = Convert.ToInt32(doubleValue)
Console.WriteLine("{0} converted to {1}.",
doubleValue, integerValue)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to an integer.",
doubleValue)
End Try
' The example displays the following output:
' 13956810.96702888123451471211 converted to 13956810.9670289.
' 42.72 converted to 43.

Para obtener una tabla en la que se muestra una lista de conversiones de restricción y ampliación admitidas por la
clase Convert, vea Tablas de conversiones de tipos.
Conversiones personalizadas con el método ChangeType
Además de admitir las conversiones en cada uno de los tipos base, la clase Convert se puede usar para convertir
un tipo personalizado en uno o varios tipos predefinidos. El método Convert.ChangeType(Object, Type,
IFormatProvider), que a su vez contiene una llamada al método IConvertible.ToType del parámetro value , realiza
esta conversión. Esto significa que el objeto representado por el parámetro value debe proporcionar una
implementación de la interfaz IConvertible.

NOTE
Dado que los métodos Convert.ChangeType(Object, Type) y Convert.ChangeType(Object, Type, IFormatProvider) utilizan un
objeto Type para especificar el tipo de destino al que se convierte value , se pueden utilizar para realizar una conversión
dinámica a un objeto cuyo tipo se desconoce en tiempo de compilación. Sin embargo, observe que la implementación de
IConvertible de value aún debe admitir esta conversión.

En el ejemplo siguiente se muestra una posible implementación de la interfaz IConvertible que permite convertir
un objeto TemperatureCelsius en un objeto TemperatureFahrenheit y viceversa. En el ejemplo se define una clase
base, Temperature , que implementa la interfaz IConvertible e invalida el método Object.ToString. Cada una de las
clases derivadas TemperatureCelsius y TemperatureFahrenheit invalida los métodos ToType y ToString de la
clase base.

using System;

public abstract class Temperature : IConvertible


{
protected decimal temp;

public Temperature(decimal temperature)


{
this.temp = temperature;
}

public decimal Value


{
get { return this.temp; }
set { this.temp = value; }
}

public override string ToString()


{
return temp.ToString(null as IFormatProvider) + "º";
}

// IConvertible implementations.
public TypeCode GetTypeCode() {
return TypeCode.Object;
}

public bool ToBoolean(IFormatProvider provider) {


throw new InvalidCastException(String.Format("Temperature-to-Boolean conversion is not supported."));
}

public byte ToByte(IFormatProvider provider) {


if (temp < Byte.MinValue || temp > Byte.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the Byte data type.", temp));
else
return (byte) temp;
}

public char ToChar(IFormatProvider provider) {


throw new InvalidCastException("Temperature-to-Char conversion is not supported.");
}

public DateTime ToDateTime(IFormatProvider provider) {


throw new InvalidCastException("Temperature-to-DateTime conversion is not supported.");
}

public decimal ToDecimal(IFormatProvider provider) {


return temp;
}

public double ToDouble(IFormatProvider provider) {


return (double) temp;
}

public short ToInt16(IFormatProvider provider) {


if (temp < Int16.MinValue || temp > Int16.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the Int16 data type.", temp));
else
return (short) Math.Round(temp);
}

public int ToInt32(IFormatProvider provider) {


public int ToInt32(IFormatProvider provider) {
if (temp < Int32.MinValue || temp > Int32.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the Int32 data type.", temp));
else
return (int) Math.Round(temp);
}

public long ToInt64(IFormatProvider provider) {


if (temp < Int64.MinValue || temp > Int64.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the Int64 data type.", temp));
else
return (long) Math.Round(temp);
}

public sbyte ToSByte(IFormatProvider provider) {


if (temp < SByte.MinValue || temp > SByte.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the SByte data type.", temp));
else
return (sbyte) temp;
}

public float ToSingle(IFormatProvider provider) {


return (float) temp;
}

public virtual string ToString(IFormatProvider provider) {


return temp.ToString(provider) + "°";
}

// If conversionType is implemented by another IConvertible method, call it.


public virtual object ToType(Type conversionType, IFormatProvider provider) {
switch (Type.GetTypeCode(conversionType))
{
case TypeCode.Boolean:
return this.ToBoolean(provider);
case TypeCode.Byte:
return this.ToByte(provider);
case TypeCode.Char:
return this.ToChar(provider);
case TypeCode.DateTime:
return this.ToDateTime(provider);
case TypeCode.Decimal:
return this.ToDecimal(provider);
case TypeCode.Double:
return this.ToDouble(provider);
case TypeCode.Empty:
throw new NullReferenceException("The target type is null.");
case TypeCode.Int16:
return this.ToInt16(provider);
case TypeCode.Int32:
return this.ToInt32(provider);
case TypeCode.Int64:
return this.ToInt64(provider);
case TypeCode.Object:
// Leave conversion of non-base types to derived classes.
throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.",
conversionType.Name));
case TypeCode.SByte:
return this.ToSByte(provider);
case TypeCode.Single:
return this.ToSingle(provider);
case TypeCode.String:
IConvertible iconv = this;
return iconv.ToString(provider);
case TypeCode.UInt16:
return this.ToUInt16(provider);
case TypeCode.UInt32:
return this.ToUInt32(provider);
case TypeCode.UInt64:
return this.ToUInt64(provider);
return this.ToUInt64(provider);
default:
throw new InvalidCastException("Conversion not supported.");
}
}

public ushort ToUInt16(IFormatProvider provider) {


if (temp < UInt16.MinValue || temp > UInt16.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the UInt16 data type.", temp));
else
return (ushort) Math.Round(temp);
}

public uint ToUInt32(IFormatProvider provider) {


if (temp < UInt32.MinValue || temp > UInt32.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the UInt32 data type.", temp));
else
return (uint) Math.Round(temp);
}

public ulong ToUInt64(IFormatProvider provider) {


if (temp < UInt64.MinValue || temp > UInt64.MaxValue)
throw new OverflowException(String.Format("{0} is out of range of the UInt64 data type.", temp));
else
return (ulong) Math.Round(temp);
}
}

public class TemperatureCelsius : Temperature, IConvertible


{
public TemperatureCelsius(decimal value) : base(value)
{
}

// Override ToString methods.


public override string ToString()
{
return this.ToString(null);
}

public override string ToString(IFormatProvider provider)


{
return temp.ToString(provider) + "°C";
}

// If conversionType is a implemented by another IConvertible method, call it.


public override object ToType(Type conversionType, IFormatProvider provider) {
// For non-objects, call base method.
if (Type.GetTypeCode(conversionType) != TypeCode.Object) {
return base.ToType(conversionType, provider);
}
else
{
if (conversionType.Equals(typeof(TemperatureCelsius)))
return this;
else if (conversionType.Equals(typeof(TemperatureFahrenheit)))
return new TemperatureFahrenheit((decimal) this.temp * 9 / 5 + 32);
else
throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.",
conversionType.Name));
}
}
}

public class TemperatureFahrenheit : Temperature, IConvertible


{
public TemperatureFahrenheit(decimal value) : base(value)
{
}
// Override ToString methods.
public override string ToString()
{
return this.ToString(null);
}

public override string ToString(IFormatProvider provider)


{
return temp.ToString(provider) + "°F";
}

public override object ToType(Type conversionType, IFormatProvider provider)


{
// For non-objects, call base methood.
if (Type.GetTypeCode(conversionType) != TypeCode.Object) {
return base.ToType(conversionType, provider);
}
else
{
// Handle conversion between derived classes.
if (conversionType.Equals(typeof(TemperatureFahrenheit)))
return this;
else if (conversionType.Equals(typeof(TemperatureCelsius)))
return new TemperatureCelsius((decimal) (this.temp - 32) * 5 / 9);
// Unspecified object type: throw an InvalidCastException.
else
throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.",
conversionType.Name));
}
}
}

Public MustInherit Class Temperature


Implements IConvertible

Protected temp As Decimal

Public Sub New(temperature As Decimal)


Me.temp = temperature
End Sub

Public Property Value As Decimal


Get
Return Me.temp
End Get
Set
Me.temp = Value
End Set
End Property

Public Overrides Function ToString() As String


Return temp.ToString() & "º"
End Function

' IConvertible implementations.


Public Function GetTypeCode() As TypeCode Implements IConvertible.GetTypeCode
Return TypeCode.Object
End Function

Public Function ToBoolean(provider As IFormatProvider) As Boolean Implements IConvertible.ToBoolean


Throw New InvalidCastException(String.Format("Temperature-to-Boolean conversion is not supported."))
End Function

Public Function ToByte(provider As IFormatProvider) As Byte Implements IConvertible.ToByte


If temp < Byte.MinValue Or temp > Byte.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the Byte data type.", temp))
Else
Else
Return CByte(temp)
End If
End Function

Public Function ToChar(provider As IFormatProvider) As Char Implements IConvertible.ToChar


Throw New InvalidCastException("Temperature-to-Char conversion is not supported.")
End Function

Public Function ToDateTime(provider As IFormatProvider) As DateTime Implements IConvertible.ToDateTime


Throw New InvalidCastException("Temperature-to-DateTime conversion is not supported.")
End Function

Public Function ToDecimal(provider As IFormatProvider) As Decimal Implements IConvertible.ToDecimal


Return temp
End Function

Public Function ToDouble(provider As IFormatProvider) As Double Implements IConvertible.ToDouble


Return CDbl(temp)
End Function

Public Function ToInt16(provider As IFormatProvider) As Int16 Implements IConvertible.ToInt16


If temp < Int16.MinValue Or temp > Int16.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the Int16 data type.", temp))
End If
Return CShort(Math.Round(temp))
End Function

Public Function ToInt32(provider As IFormatProvider) As Int32 Implements IConvertible.ToInt32


If temp < Int32.MinValue Or temp > Int32.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the Int32 data type.", temp))
End If
Return CInt(Math.Round(temp))
End Function

Public Function ToInt64(provider As IFormatProvider) As Int64 Implements IConvertible.ToInt64


If temp < Int64.MinValue Or temp > Int64.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the Int64 data type.", temp))
End If
Return CLng(Math.Round(temp))
End Function

Public Function ToSByte(provider As IFormatProvider) As SByte Implements IConvertible.ToSByte


If temp < SByte.MinValue Or temp > SByte.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the SByte data type.", temp))
Else
Return CSByte(temp)
End If
End Function

Public Function ToSingle(provider As IFormatProvider) As Single Implements IConvertible.ToSingle


Return CSng(temp)
End Function

Public Overridable Overloads Function ToString(provider As IFormatProvider) As String Implements


IConvertible.ToString
Return temp.ToString(provider) & " °C"
End Function

' If conversionType is a implemented by another IConvertible method, call it.


Public Overridable Function ToType(conversionType As Type, provider As IFormatProvider) As Object
Implements IConvertible.ToType
Select Case Type.GetTypeCode(conversionType)
Case TypeCode.Boolean
Return Me.ToBoolean(provider)
Case TypeCode.Byte
Return Me.ToByte(provider)
Case TypeCode.Char
Return Me.ToChar(provider)
Case TypeCode.DateTime
Case TypeCode.DateTime
Return Me.ToDateTime(provider)
Case TypeCode.Decimal
Return Me.ToDecimal(provider)
Case TypeCode.Double
Return Me.ToDouble(provider)
Case TypeCode.Empty
Throw New NullReferenceException("The target type is null.")
Case TypeCode.Int16
Return Me.ToInt16(provider)
Case TypeCode.Int32
Return Me.ToInt32(provider)
Case TypeCode.Int64
Return Me.ToInt64(provider)
Case TypeCode.Object
' Leave conversion of non-base types to derived classes.
Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _
conversionType.Name))
Case TypeCode.SByte
Return Me.ToSByte(provider)
Case TypeCode.Single
Return Me.ToSingle(provider)
Case TypeCode.String
Return Me.ToString(provider)
Case TypeCode.UInt16
Return Me.ToUInt16(provider)
Case TypeCode.UInt32
Return Me.ToUInt32(provider)
Case TypeCode.UInt64
Return Me.ToUInt64(provider)
Case Else
Throw New InvalidCastException("Conversion not supported.")
End Select
End Function

Public Function ToUInt16(provider As IFormatProvider) As UInt16 Implements IConvertible.ToUInt16


If temp < UInt16.MinValue Or temp > UInt16.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the UInt16 data type.", temp))
End If
Return CUShort(Math.Round(temp))
End Function

Public Function ToUInt32(provider As IFormatProvider) As UInt32 Implements IConvertible.ToUInt32


If temp < UInt32.MinValue Or temp > UInt32.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the UInt32 data type.", temp))
End If
Return CUInt(Math.Round(temp))
End Function

Public Function ToUInt64(provider As IFormatProvider) As UInt64 Implements IConvertible.ToUInt64


If temp < UInt64.MinValue Or temp > UInt64.MaxValue Then
Throw New OverflowException(String.Format("{0} is out of range of the UInt64 data type.", temp))
End If
Return CULng(Math.Round(temp))
End Function
End Class

Public Class TemperatureCelsius : Inherits Temperature : Implements IConvertible


Public Sub New(value As Decimal)
MyBase.New(value)
End Sub

' Override ToString methods.


Public Overrides Function ToString() As String
Return Me.ToString(Nothing)
End Function

Public Overrides Function ToString(provider As IFormatProvider ) As String


Return temp.ToString(provider) + "°C"
End Function
End Function

' If conversionType is a implemented by another IConvertible method, call it.


Public Overrides Function ToType(conversionType As Type, provider As IFormatProvider) As Object
' For non-objects, call base method.
If Type.GetTypeCode(conversionType) <> TypeCode.Object Then
Return MyBase.ToType(conversionType, provider)
Else
If conversionType.Equals(GetType(TemperatureCelsius)) Then
Return Me
ElseIf conversionType.Equals(GetType(TemperatureFahrenheit))
Return New TemperatureFahrenheit(CDec(Me.temp * 9 / 5 + 32))
' Unspecified object type: throw an InvalidCastException.
Else
Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _
conversionType.Name))
End If
End If
End Function
End Class

Public Class TemperatureFahrenheit : Inherits Temperature : Implements IConvertible


Public Sub New(value As Decimal)
MyBase.New(value)
End Sub

' Override ToString methods.


Public Overrides Function ToString() As String
Return Me.ToString(Nothing)
End Function

Public Overrides Function ToString(provider As IFormatProvider ) As String


Return temp.ToString(provider) + "°F"
End Function

Public Overrides Function ToType(conversionType As Type, provider As IFormatProvider) As Object


' For non-objects, call base methood.
If Type.GetTypeCode(conversionType) <> TypeCode.Object Then
Return MyBase.ToType(conversionType, provider)
Else
' Handle conversion between derived classes.
If conversionType.Equals(GetType(TemperatureFahrenheit)) Then
Return Me
ElseIf conversionType.Equals(GetType(TemperatureCelsius))
Return New TemperatureCelsius(CDec((MyBase.temp - 32) * 5 / 9))
' Unspecified object type: throw an InvalidCastException.
Else
Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _
conversionType.Name))
End If
End If
End Function
End Class

En el ejemplo siguiente se muestran varias llamadas a estas implementaciones de IConvertible para convertir los
objetos TemperatureCelsius en objetos TemperatureFahrenheit y viceversa.
TemperatureCelsius tempC1 = new TemperatureCelsius(0);
TemperatureFahrenheit tempF1 = (TemperatureFahrenheit) Convert.ChangeType(tempC1,
typeof(TemperatureFahrenheit), null);
Console.WriteLine("{0} equals {1}.", tempC1, tempF1);
TemperatureCelsius tempC2 = (TemperatureCelsius) Convert.ChangeType(tempC1, typeof(TemperatureCelsius), null);
Console.WriteLine("{0} equals {1}.", tempC1, tempC2);
TemperatureFahrenheit tempF2 = new TemperatureFahrenheit(212);
TemperatureCelsius tempC3 = (TemperatureCelsius) Convert.ChangeType(tempF2, typeof(TemperatureCelsius), null);
Console.WriteLine("{0} equals {1}.", tempF2, tempC3);
TemperatureFahrenheit tempF3 = (TemperatureFahrenheit) Convert.ChangeType(tempF2,
typeof(TemperatureFahrenheit), null);
Console.WriteLine("{0} equals {1}.", tempF2, tempF3);
// The example displays the following output:
// 0°C equals 32°F.
// 0°C equals 0°C.
// 212°F equals 100°C.
// 212°F equals 212°F.

Dim tempC1 As New TemperatureCelsius(0)


Dim tempF1 As TemperatureFahrenheit = CType(Convert.ChangeType(tempC1, GetType(TemperatureFahrenheit),
Nothing), TemperatureFahrenheit)
Console.WriteLine("{0} equals {1}.", tempC1, tempF1)
Dim tempC2 As TemperatureCelsius = CType(Convert.ChangeType(tempC1, GetType(TemperatureCelsius), Nothing),
TemperatureCelsius)
Console.WriteLine("{0} equals {1}.", tempC1, tempC2)
Dim tempF2 As New TemperatureFahrenheit(212)
Dim tempC3 As TEmperatureCelsius = CType(Convert.ChangeType(tempF2, GEtType(TemperatureCelsius), Nothing),
TemperatureCelsius)
Console.WriteLine("{0} equals {1}.", tempF2, tempC3)
Dim tempF3 As TemperatureFahrenheit = CType(Convert.ChangeType(tempF2, GetType(TemperatureFahrenheit),
Nothing), TemperatureFahrenheit)
Console.WriteLine("{0} equals {1}.", tempF2, tempF3)
' The example displays the following output:
' 0°C equals 32°F.
' 0°C equals 0°C.
' 212°F equals 100°C.
' 212°F equals 212°F.

Clase TypeConverter
.NET Framework también permite definir un convertidor de tipos para un tipo personalizado extendiendo la clase
System.ComponentModel.TypeConverter y asociando el convertidor de tipos al tipo mediante un atributo
System.ComponentModel.TypeConverterAttribute. En la tabla siguiente se resaltan las diferencias entre este
enfoque y la implementación de la interfaz IConvertible para un tipo personalizado.

NOTE
Se puede proporcionar compatibilidad en tiempo de diseño para un tipo personalizado sólo si se ha definido un convertidor
de tipos para éste.

CONVERSIÓN MEDIANTE TYPECONVERTER CONVERSIÓN MEDIANTE ICONVERTIBLE

Se implementa para un tipo personalizado derivando una Se implementa mediante un tipo personalizado para realizar la
clase independiente de TypeConverter. Esta clase derivada se conversión. Un usuario del tipo invoca un método de
asocia al tipo personalizado aplicando un atributo conversión de IConvertible para el tipo.
TypeConverterAttribute.
CONVERSIÓN MEDIANTE TYPECONVERTER CONVERSIÓN MEDIANTE ICONVERTIBLE

Se puede utilizar en tiempo de diseño y en tiempo de Sólo se puede utilizar en tiempo de ejecución.
ejecución.

Usa la reflexión; por tanto, es más lenta que la conversión No utiliza la reflexión.
mediante IConvertible.

Permite realizar conversiones bidireccionales; es decir, Permite convertir un tipo personalizado en otros tipos de
convertir el tipo personalizado en otros tipos de datos y datos, pero no otros tipos de datos en el tipo personalizado.
convertir otros tipos de datos en el tipo personalizado. Por
ejemplo, un objeto TypeConverter definido para MyType
permite conversiones de MyType a String y de String a
MyType .

Para obtener más información sobre cómo usar convertidores de tipos para realizar conversiones, vea
System.ComponentModel.TypeConverter.

Vea también
System.Convert
IConvertible
Tablas de conversión de tipos
Tablas de conversión de tipos en .NET
04/11/2019 • 3 minutes to read • Edit Online

Una conversión de ampliación se produce cuando se convierte un valor de un tipo a otro tipo que es de igual o
mayor tamaño. Una conversión de restricción se produce cuando se convierte un valor de un tipo a otro tipo que
es de un tamaño menor. En las tablas de este tema se muestran los comportamientos de ambos tipos de
conversiones.

conversiones de ampliación
En la tabla siguiente se describen las conversiones de ampliación que pueden realizarse sin pérdida de
información.

TIPO SE PUEDE CONVERTIR SIN PÉRDIDA DE DATOS A

Byte UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double,


Decimal

SByte Int16, Int32, Int64, Single, Double, Decimal

Int16 Int32, Int64, Single, Double, Decimal

UInt16 UInt32, Int32, UInt64, Int64, Single, Double, Decimal

Char UInt16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal

Int32 Int64, Double, Decimal

UInt32 Int64, UInt64, Double, Decimal

Int64 Decimal

UInt64 Decimal

Single Double

Algunas conversiones de ampliación a Single o Double pueden provocar una pérdida de precisión. En la tabla
siguiente se describen las conversiones de ampliación que a veces se traducen en una pérdida de información.

TIPO SE PUEDE CONVERTIR A

Int32 Single

UInt32 Single

Int64 Single, Double

UInt64 Single, Double


TIPO SE PUEDE CONVERTIR A

Decimal Single, Double

conversiones de restricción
Una conversión de restricción a Single o Double puede provocar una pérdida de información. Si el tipo de destino
no puede expresar correctamente la magnitud del origen, el tipo resultante se establece en la constante
PositiveInfinity o NegativeInfinity . PositiveInfinity resulta al dividir un número positivo por cero y también
se devuelve cuando el valor de Single o Double supera el valor del campo MaxValue . NegativeInfinity resulta al
dividir un número negativo por cero y también se devuelve cuando el valor de Single o Double cae por debajo del
valor del campo MinValue . Una conversión de Double a Single podría dar lugar a PositiveInfinity o
NegativeInfinity .

Una conversión de restricción también puede traducirse en una pérdida de información para otros tipos de datos.
Pero se inicia OverflowException si el valor de un tipo que se va a convertir está fuera del intervalo especificado
por los campos MaxValue y MinValue del tipo de destino y el tiempo de ejecución comprueba la conversión para
asegurarse de que el valor del tipo de destino no supera su MaxValue o MinValue . Las conversiones que se
realizan con la clase System.Convert siempre se comprueban de esta manera.
En la tabla siguiente se enumeran las conversiones que inician OverflowException con System.Convert o cualquier
conversión comprobada si el valor del tipo que se va a convertir está fuera del intervalo definido del tipo
resultante.

TIPO SE PUEDE CONVERTIR A

Byte SByte

SByte Byte, UInt16, UInt32, UInt64

Int16 Byte, SByte, UInt16

UInt16 Byte, SByte, Int16

Int32 Byte, SByte, Int16, UInt16,UInt32

UInt32 Byte, SByte, Int16, UInt16, Int32

Int64 Byte, SByte, Int16, UInt16, Int32,UInt32,UInt64

UInt64 Byte, SByte, Int16, UInt16, Int32, UInt32, Int64

Decimal Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64

Single Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64

Double Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64

Vea también
System.Convert
Conversión de tipos en .NET
Tipos de formato en .NET
22/01/2020 • 62 minutes to read • Edit Online

Aplicar formato es el proceso de convertir una instancia de una clase, una estructura o un valor de enumeración
en su representación de cadena, a menudo para que la cadena resultante se pueda mostrar a los usuarios o
deserializar para restaurar el tipo de datos original. Esta conversión puede plantear varios desafíos:
La forma en que se almacenan internamente los valores no refleja necesariamente la manera en que los
usuarios desean verlos. Por ejemplo, un número de teléfono podría almacenarse con el formato
8009999999, que no es fácil de usar. Se debería mostrar en su lugar como 800-999-9999. Consulte la
sección Cadenas de formato personalizado para obtener un ejemplo en el que da formato a un número
de esta forma.
A veces, la conversión de un objeto en su representación de cadena no es intuitiva. Por ejemplo, no está
claro cómo debe aparecer la representación de cadena de un objeto Temperature o un objeto Person.
Para obtener un ejemplo en el que se da formato a un objeto Temperature de varias formas, consulte la
sección Cadenas de formato estándar .
A menudo, los valores requieren un formato dependiente de la referencia cultural. Por ejemplo, en una
aplicación en la que se usan números para reflejar los valores monetarios, las cadenas numéricas deben
incluir el símbolo de divisa, el separador de grupo (que en la mayoría de las referencias culturales es el
separador de miles) y el símbolo decimal correspondientes a la referencia cultural actual. Para ver un
ejemplo, consulte la sección Formato según la referencia cultural con proveedores de formato.
Puede que una aplicación muestre el mismo valor de diferentes maneras. Por ejemplo, es posible que
una aplicación represente un miembro de enumeración mostrando una representación de cadena de su
nombre o mostrando su valor subyacente. Para obtener un ejemplo en el que se da formato a un
miembro de la enumeración DayOfWeek de maneras diferentes, consulte la sección Cadenas de formato
estándar .

NOTE
La aplicación de formato convierte el valor de un tipo en una representación de cadena. El análisis es lo contrario que la
aplicación de formato. Una operación de análisis crea una instancia de un tipo de datos a partir de su representación de
cadena. Para información sobre cómo convertir cadenas en otros tipos de datos, vea Analizar cadenas en .NET.

.NET proporciona compatibilidad de formato enriquecida que permite a los desarrolladores hacer frente a estos
requisitos.

Formato en .NET
El mecanismo básico para aplicar formato es la implementación predeterminada del método Object.ToString,
que se explica en la sección Formato predeterminado mediante el método ToString más adelante en este tema.
Pero .NET proporciona varias formas de modificar y extender su compatibilidad de formato predeterminado.
Entre ellas se incluyen las siguientes:
Invalidar el método Object.ToString para definir una representación de cadena personalizada del valor de
un objeto. Para obtener más información, consulte la sección Invalidación del método ToString más
adelante en este tema.
Definir especificadores de formato que permitan que la representación de cadena del valor de un objeto
adopte varios formatos. Por ejemplo, el especificador de formato "X" en la siguiente instrucción convierte
un entero en la representación de cadena de un valor hexadecimal.

int integerValue = 60312;


Console.WriteLine(integerValue.ToString("X")); // Displays EB98.

Dim integerValue As Integer = 60312


Console.WriteLine(integerValue.ToString("X")) ' Displays EB98.

Para obtener más información sobre los especificadores de formato, vea la sección Método ToString y
cadenas de formato .
Usar proveedores de formato para aprovechar las convenciones de formato de una referencia cultural
concreta. Por ejemplo, la instrucción siguiente muestra un valor de divisa usando las convenciones de
formato de la referencia cultural en-US.

double cost = 1632.54;


Console.WriteLine(cost.ToString("C",
new System.Globalization.CultureInfo("en-US")));
// The example displays the following output:
// $1,632.54

Dim cost As Double = 1632.54


Console.WriteLine(cost.ToString("C", New System.Globalization.CultureInfo("en-US")))
' The example displays the following output:
' $1,632.54

Para obtener más información sobre cómo aplicar formato con proveedores de formato, consulte la
sección Proveedores de formato.
Implementar la interfaz IFormattable para admitir tanto la conversión de cadenas con la clase Convert
como formatos compuestos. Para obtener más información, vea la sección Interfaz IFormattable .
Usar formatos compuestos para incrustar la representación de cadena de un valor en una cadena más
larga. Para obtener más información, vea la sección Formatos compuestos .
Implementar ICustomFormatter y IFormatProvider para proporcionar una solución de formato
personalizado completa. Para obtener más información, vea la sección Formato personalizado con
ICustomFormatter .
En las secciones siguientes se examinan estos métodos para convertir un objeto en su representación de
cadena.

Formato predeterminado mediante el método ToString


Cada tipo derivado de System.Object hereda automáticamente un método ToString sin parámetros, que
devuelve el nombre del tipo de forma predeterminada. En el ejemplo siguiente se ilustra el método ToString
predeterminado. Se define una clase denominada Automobile que no tiene ninguna implementación. Cuando
se crea una instancia de la clase y se llama a su método ToString , se muestra el nombre de su tipo. Observe
que en el ejemplo no se llama explícitamente al método ToString . El método Console.WriteLine(Object) llama
implícitamente al método ToString del objeto pasado como argumento.
using System;

public class Automobile


{
// No implementation. All members are inherited from Object.
}

public class Example


{
public static void Main()
{
Automobile firstAuto = new Automobile();
Console.WriteLine(firstAuto);
}
}
// The example displays the following output:
// Automobile

Public Class Automobile


' No implementation. All members are inherited from Object.
End Class

Module Example
Public Sub Main()
Dim firstAuto As New Automobile()
Console.WriteLine(firstAuto)
End Sub
End Module
' The example displays the following output:
' Automobile

WARNING
A partir de Windows 8.1, Windows Runtime incluye una interfaz IStringable con un solo método, IStringable.ToString, que
ofrece compatibilidad con el formato predeterminado. Sin embargo, es recomendable que los tipos administrados no
implementen la interfaz IStringable . Para obtener más información, vea la sección "Windows Runtime y la interfaz
IStringable " de la página de referencia Object.ToString.

Puesto que todos los tipos distintos de las interfaces se derivan de Object, esta funcionalidad se proporciona
automáticamente a sus clases o estructuras personalizadas. Si bien, la funcionalidad que ofrece el método
ToString predeterminado es limitada: Aunque identifica el tipo, no proporciona ninguna información sobre una
instancia del tipo. Para proporcionar una representación de cadena de un objeto que proporciona información
sobre ese objeto, debe invalidar el método ToString .

NOTE
Las estructuras heredan de ValueType, que a su vez se deriva de Object. Aunque ValueType invalida Object.ToString, su
implementación es idéntica.

Invalidación del método ToString


La presentación del nombre de un tipo suele tener un uso limitado y no permite a los consumidores de sus tipos
diferenciar una instancia de otra. Sin embargo, puede invalidar el método ToString para proporcionar una
representación más útil del valor de un objeto. En el ejemplo siguiente se define un objeto Temperature y se
invalida su método ToString para mostrar la temperatura en grados centígrados.
using System;

public class Temperature


{
private decimal temp;

public Temperature(decimal temperature)


{
this.temp = temperature;
}

public override string ToString()


{
return this.temp.ToString("N1") + "°C";
}
}

public class Example


{
public static void Main()
{
Temperature currentTemperature = new Temperature(23.6m);
Console.WriteLine("The current temperature is " +
currentTemperature.ToString());
}
}
// The example displays the following output:
// The current temperature is 23.6°C.

Public Class Temperature


Private temp As Decimal

Public Sub New(temperature As Decimal)


Me.temp = temperature
End Sub

Public Overrides Function ToString() As String


Return Me.temp.ToString("N1") + "°C"
End Function
End Class

Module Example
Public Sub Main()
Dim currentTemperature As New Temperature(23.6d)
Console.WriteLine("The current temperature is " +
currentTemperature.ToString())
End Sub
End Module
' The example displays the following output:
' The current temperature is 23.6°C.

En .NET, el método ToString de cada tipo de valor primitivo se ha invalidado para que se muestre el valor del
objeto en lugar de su nombre. En la tabla siguiente se muestra la invalidación para cada tipo primitivo. Observe
que la mayoría de los métodos invalidados llaman a otra sobrecarga del método ToString y le pasan el
especificador de formato "G", que define el formato general de su tipo, y un objeto IFormatProvider que
representa la referencia cultural actual.

TIPO INVALIDACIÓN DE TOSTRING

Boolean Devuelve Boolean.TrueString o Boolean.FalseString.


TIPO INVALIDACIÓN DE TOSTRING

Byte Llama a
Byte.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Byte correspondiente a la
referencia cultural actual.

Char Devuelve el carácter como una cadena.

DateTime Llama a
DateTime.ToString("G",
DatetimeFormatInfo.CurrentInfo)
para dar formato al valor de fecha y hora correspondiente a
la referencia cultural actual.

Decimal Llama a
Decimal.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Decimal correspondiente a
la referencia cultural actual.

Double Llama a
Double.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Double correspondiente a
la referencia cultural actual.

Int16 Llama a
Int16.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Int16 correspondiente a la
referencia cultural actual.

Int32 Llama a
Int32.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Int32 correspondiente a la
referencia cultural actual.

Int64 Llama a
Int64.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Int64 correspondiente a la
referencia cultural actual.

SByte Llama a
SByte.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo SByte correspondiente a la
referencia cultural actual.

Single Llama a
Single.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo Single correspondiente a la
referencia cultural actual.

UInt16 Llama a
UInt16.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo UInt16 correspondiente a
la referencia cultural actual.
TIPO INVALIDACIÓN DE TOSTRING

UInt32 Llama a
UInt32.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo UInt32 correspondiente a
la referencia cultural actual.

UInt64 Llama a
UInt64.ToString("G", NumberFormatInfo.CurrentInfo)
para dar formato al valor de tipo UInt64 correspondiente a
la referencia cultural actual.

Método ToString y cadenas de formato


Recurrir al método ToString predeterminado o invalidar ToString resulta apropiado cuando un objeto tiene
una única representación de cadena. Sin embargo, el valor de un objeto tiene a menudo varias representaciones.
Por ejemplo, una temperatura puede expresarse en grados Fahrenheit, grados centígrados o grados Kelvin. De
manera similar, el valor entero 10 puede representarse de numerosas maneras; por ejemplo, 10, 10,0, 1,0e01 o
$10,00.
Para que un valor pueda tener varias representaciones de cadena, .NET usa cadenas de formato. Una cadena de
formato es una cadena que contiene uno o varios especificadores de formato predefinidos, que son caracteres
individuales o grupos de caracteres que definen cómo el método ToString debe dar formato a su salida. A
continuación, se pasa la cadena de formato como un parámetro al método ToString del objeto, por lo que
determina cómo debe mostrarse la representación de cadena del valor de ese objeto.
Todos los tipos numéricos, de fecha y hora, y de enumeración de .NET admiten un conjunto predefinido de
especificadores de formato. Las cadenas de formato también se pueden emplear para definir varias
representaciones de cadena de los tipos de datos definidos por una aplicación.
Cadenas de formato estándar
Una cadena de formato estándar contiene un único especificador de formato, que es un carácter alfabético que
define la representación de cadena del objeto al que se aplica, junto con un especificador de precisión opcional
que afecta a cuántos dígitos se muestran en la cadena de resultado. Si el especificador de precisión se omite o
no se admite, un especificador de formato estándar es equivalente a una cadena de formato estándar.
.NET define un conjunto de especificadores de formato estándar para todos los tipos numéricos, de fecha y
hora, y de enumeración. Por ejemplo, cada una de estas categorías admite un especificador de formato estándar
"G", que define una representación de cadena general de un valor de ese tipo.
Las cadenas de formato estándar para los tipos de enumeración controlan directamente la representación de
cadena de un valor. Las cadenas de formato que se pasan al método ToString de un valor de enumeración
determinan si el valor se muestra con su nombre de cadena (especificadores de formato "G" y "F"), su valor
integral subyacente (especificador de formato "D") o su valor hexadecimal (especificador de formato "X"). En el
ejemplo siguiente se muestra el uso de cadenas de formato estándar para dar formato a un valor de
enumeración DayOfWeek .
DayOfWeek thisDay = DayOfWeek.Monday;
string[] formatStrings = {"G", "F", "D", "X"};

foreach (string formatString in formatStrings)


Console.WriteLine(thisDay.ToString(formatString));
// The example displays the following output:
// Monday
// Monday
// 1
// 00000001

Dim thisDay As DayOfWeek = DayOfWeek.Monday


Dim formatStrings() As String = {"G", "F", "D", "X"}

For Each formatString As String In formatStrings


Console.WriteLine(thisDay.ToString(formatString))
Next
' The example displays the following output:
' Monday
' Monday
' 1
' 00000001

Para información sobre las cadenas de formato de enumeración, vea Enumeration Format Strings.
Las cadenas de formato estándar para tipos numéricos normalmente definen una cadena de resultado cuya
apariencia exacta está controlada por uno o más valores de propiedad. Por ejemplo, el especificador de formato
"C" da formato a un número como un valor de divisa. Al llamar al método ToString con el especificador de
formato "C" como único parámetro, se usan los siguientes valores de propiedad del objeto NumberFormatInfo
de la referencia cultural actual para definir la representación de cadena del valor numérico:
La propiedad CurrencySymbol , que especifica el símbolo de divisa de la referencia cultural actual.
La propiedad CurrencyNegativePattern o CurrencyPositivePattern , que devuelve un entero que
determina lo siguiente:
La posición del símbolo de divisa.
Si los valores negativos se indican mediante un signo negativo inicial, un signo negativo final o
paréntesis.
Si aparece un espacio entre el valor numérico y el símbolo de divisa.
La propiedad CurrencyDecimalDigits , que define el número de dígitos fraccionarios en la cadena de
resultado.
La propiedad CurrencyDecimalSeparator , que define el símbolo del separador decimal en la cadena de
resultado.
La propiedad CurrencyGroupSeparator , que define el símbolo del separador de grupo.
La propiedad CurrencyGroupSizes , que define el número de dígitos de cada grupo que hay a la
izquierda del decimal.
La propiedad NegativeSign , que determina el signo negativo usado en la cadena de resultado si no se
emplean paréntesis para indicar valores negativos.
Además, las cadenas de formato numérico pueden incluir un especificador de precisión. El significado de este
especificador depende de la cadena de formato con la que se usa, pero suele indicar el número total de dígitos o
el número de dígitos fraccionarios que deben aparecer en la cadena de resultado. Por ejemplo, en el ejemplo
siguiente se usa la cadena numérica estándar "X4" y un especificador de precisión para crear un valor de cadena
que tiene cuatro dígitos hexadecimales.

byte[] byteValues = { 12, 163, 255 };


foreach (byte byteValue in byteValues)
Console.WriteLine(byteValue.ToString("X4"));
// The example displays the following output:
// 000C
// 00A3
// 00FF

Dim byteValues() As Byte = { 12, 163, 255 }


For Each byteValue As Byte In byteValues
Console.WriteLine(byteValue.ToString("X4"))
Next
' The example displays the following output:
' 000C
' 00A3
' 00FF

Para más información sobre las cadenas de formato numérico estándar, vea Standard Numeric Format Strings.
Las cadenas de formato estándar para valores de fecha y hora son alias de las cadenas de formato
personalizado almacenadas por una propiedad DateTimeFormatInfo determinada. Por ejemplo, al llamar al
método ToString de un valor de fecha y hora con el especificador de formato "D" se muestran la fecha y la
hora usando la cadena de formato personalizado que está almacenada en la propiedad
DateTimeFormatInfo.LongDatePattern de la referencia cultural actual. (Para obtener más información sobre las
cadenas de formato personalizado, vea la próxima sección). En el ejemplo siguiente se ilustra esta relación.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
DateTime date1 = new DateTime(2009, 6, 30);
Console.WriteLine("D Format Specifier: {0:D}", date1);
string longPattern = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern;
Console.WriteLine("'{0}' custom format string: {1}",
longPattern, date1.ToString(longPattern));
}
}
// The example displays the following output when run on a system whose
// current culture is en-US:
// D Format Specifier: Tuesday, June 30, 2009
// 'dddd, MMMM dd, yyyy' custom format string: Tuesday, June 30, 2009
Imports System.Globalization

Module Example
Public Sub Main()
Dim date1 As Date = #6/30/2009#
Console.WriteLine("D Format Specifier: {0:D}", date1)
Dim longPattern As String = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern
Console.WriteLine("'{0}' custom format string: {1}", _
longPattern, date1.ToString(longPattern))
End Sub
End Module
' The example displays the following output when run on a system whose
' current culture is en-US:
' D Format Specifier: Tuesday, June 30, 2009
' 'dddd, MMMM dd, yyyy' custom format string: Tuesday, June 30, 2009

Para más información sobre las cadenas de formato de fecha y hora estándar, vea Standard Date and Time
Format Strings.
También se pueden emplear las cadenas de formato estándar para definir la representación de cadena de un
objeto definido por la aplicación generado por el método ToString(String) del objeto. Puede definir los
especificadores de formato estándar concretos que su objeto admite y determinar si distinguen entre
mayúsculas y minúsculas o no. Su implementación del método ToString(String) debe aceptar lo siguiente:
Un especificador de formato "G" que representa un formato personalizado o común del objeto. La
sobrecarga sin parámetros del método ToString del objeto debe llamar a su sobrecarga de
ToString(String) y pasarle la cadena de formato estándar "G".

Compatibilidad con un especificador de formato que sea igual a una referencia nula ( Nothing en Visual
Basic). Un especificador de formato que es igual a una referencia nula debe considerarse equivalente al
especificador de formato "G".
Por ejemplo, una clase Temperature puede almacenar internamente la temperatura en grados centígrados y
usar especificadores de formato para representar el valor del objeto Temperature en grados centígrados, grados
Fahrenheit y grados Kelvin. Esto se muestra en el ejemplo siguiente.

using System;

public class Temperature


{
private decimal m_Temp;

public Temperature(decimal temperature)


{
this.m_Temp = temperature;
}

public decimal Celsius


{
get { return this.m_Temp; }
}

public decimal Kelvin


{
get { return this.m_Temp + 273.15m; }
}

public decimal Fahrenheit


{
get { return Math.Round(((decimal) (this.m_Temp * 9 / 5 + 32)), 2); }
}

public override string ToString()


public override string ToString()
{
return this.ToString("C");
}

public string ToString(string format)


{
// Handle null or empty string.
if (String.IsNullOrEmpty(format)) format = "C";
// Remove spaces and convert to uppercase.
format = format.Trim().ToUpperInvariant();

// Convert temperature to Fahrenheit and return string.


switch (format)
{
// Convert temperature to Fahrenheit and return string.
case "F":
return this.Fahrenheit.ToString("N2") + " °F";
// Convert temperature to Kelvin and return string.
case "K":
return this.Kelvin.ToString("N2") + " K";
// return temperature in Celsius.
case "G":
case "C":
return this.Celsius.ToString("N2") + " °C";
default:
throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
}
}
}

public class Example


{
public static void Main()
{
Temperature temp1 = new Temperature(0m);
Console.WriteLine(temp1.ToString());
Console.WriteLine(temp1.ToString("G"));
Console.WriteLine(temp1.ToString("C"));
Console.WriteLine(temp1.ToString("F"));
Console.WriteLine(temp1.ToString("K"));

Temperature temp2 = new Temperature(-40m);


Console.WriteLine(temp2.ToString());
Console.WriteLine(temp2.ToString("G"));
Console.WriteLine(temp2.ToString("C"));
Console.WriteLine(temp2.ToString("F"));
Console.WriteLine(temp2.ToString("K"));

Temperature temp3 = new Temperature(16m);


Console.WriteLine(temp3.ToString());
Console.WriteLine(temp3.ToString("G"));
Console.WriteLine(temp3.ToString("C"));
Console.WriteLine(temp3.ToString("F"));
Console.WriteLine(temp3.ToString("K"));

Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3));


}
}
// The example displays the following output:
// 0.00 °C
// 0.00 °C
// 0.00 °C
// 32.00 °F
// 273.15 K
// -40.00 °C
// -40.00 °C
// -40.00 °C
// -40.00 °F
// 233.15 K
// 16.00 °C
// 16.00 °C
// 16.00 °C
// 60.80 °F
// 289.15 K
// The temperature is now 16.00 °C.

Public Class Temperature


Private m_Temp As Decimal

Public Sub New(temperature As Decimal)


Me.m_Temp = temperature
End Sub

Public ReadOnly Property Celsius() As Decimal


Get
Return Me.m_Temp
End Get
End Property

Public ReadOnly Property Kelvin() As Decimal


Get
Return Me.m_Temp + 273.15d
End Get
End Property

Public ReadOnly Property Fahrenheit() As Decimal


Get
Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
End Get
End Property

Public Overrides Function ToString() As String


Return Me.ToString("C")
End Function

Public Overloads Function ToString(format As String) As String


' Handle null or empty string.
If String.IsNullOrEmpty(format) Then format = "C"
' Remove spaces and convert to uppercase.
format = format.Trim().ToUpperInvariant()

Select Case format


Case "F"
' Convert temperature to Fahrenheit and return string.
Return Me.Fahrenheit.ToString("N2") & " °F"
Case "K"
' Convert temperature to Kelvin and return string.
Return Me.Kelvin.ToString("N2") & " K"
Case "C", "G"
' Return temperature in Celsius.
Return Me.Celsius.ToString("N2") & " °C"
Case Else
Throw New FormatException(String.Format("The '{0}' format string is not supported.", format))
End Select
End Function
End Class

Public Module Example


Public Sub Main()
Dim temp1 As New Temperature(0d)
Console.WriteLine(temp1.ToString())
Console.WriteLine(temp1.ToString("G"))
Console.WriteLine(temp1.ToString("C"))
Console.WriteLine(temp1.ToString("F"))
Console.WriteLine(temp1.ToString("K"))
Dim temp2 As New Temperature(-40d)
Console.WriteLine(temp2.ToString())
Console.WriteLine(temp2.ToString("G"))
Console.WriteLine(temp2.ToString("C"))
Console.WriteLine(temp2.ToString("F"))
Console.WriteLine(temp2.ToString("K"))

Dim temp3 As New Temperature(16d)


Console.WriteLine(temp3.ToString())
Console.WriteLine(temp3.ToString("G"))
Console.WriteLine(temp3.ToString("C"))
Console.WriteLine(temp3.ToString("F"))
Console.WriteLine(temp3.ToString("K"))

Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3))


End Sub
End Module
' The example displays the following output:
' 0.00 °C
' 0.00 °C
' 0.00 °C
' 32.00 °F
' 273.15 K
' -40.00 °C
' -40.00 °C
' -40.00 °C
' -40.00 °F
' 233.15 K
' 16.00 °C
' 16.00 °C
' 16.00 °C
' 60.80 °F
' 289.15 K
' The temperature is now 16.00 °C.

Cadenas de formato personalizado


Además de las cadenas de formato estándar, .NET define cadenas de formato personalizado tanto para los
valores numéricos como para los valores de fecha y hora. Una cadena de formato personalizado se compone de
uno o varios especificadores de formato personalizado que definen la representación de cadena de un valor. Por
ejemplo, la cadena de formato personalizado de fecha y hora “yyyy/mm/dd hh:mm:ss.ffff t zzz” convierte una
fecha en su representación de cadena con el formato "2008/11/15 07:45:00.0000 P -08:00" para la referencia
cultural en-US. Del mismo modo, la cadena de formato personalizado “0000” convierte el valor entero 12 en
“0012”. Para una lista completa de las cadenas de formato personalizado, vea Custom Date and Time Format
Strings y Custom Numeric Format Strings.
Si una cadena de formato consta de un único especificador de formato personalizado, el especificador de
formato debe ir precedido del símbolo de porcentaje (%) para evitar la confusión con un especificador de
formato estándar. En el ejemplo siguiente, se usa el especificador de formato personalizado "M" para mostrar un
número de un dígito o de dos dígitos del mes de una fecha determinada.

DateTime date1 = new DateTime(2009, 9, 8);


Console.WriteLine(date1.ToString("%M")); // Displays 9

Dim date1 As Date = #09/08/2009#


Console.WriteLine(date1.ToString("%M")) ' Displays 9

Muchas cadenas de formato estándar para valores de fecha y hora son alias para cadenas de formato
personalizado definidas por propiedades del objeto DateTimeFormatInfo . Las cadenas de formato
personalizado también ofrecen una gran flexibilidad a la hora de proporcionar formatos definidos por la
aplicación para los valores numéricos o de fecha y hora. Puede definir sus propias cadenas de resultado
personalizadas para los valores numéricos y de fecha y hora si combina varios especificadores de formato
personalizados en una única cadena de formato personalizado. En el ejemplo siguiente se define una cadena de
formato personalizado que muestra el día de la semana entre paréntesis después del nombre de mes, el día y el
año.

string customFormat = "MMMM dd, yyyy (dddd)";


DateTime date1 = new DateTime(2009, 8, 28);
Console.WriteLine(date1.ToString(customFormat));
// The example displays the following output if run on a system
// whose language is English:
// August 28, 2009 (Friday)

Dim customFormat As String = "MMMM dd, yyyy (dddd)"


Dim date1 As Date = #8/28/2009#
Console.WriteLine(date1.ToString(customFormat))
' The example displays the following output if run on a system
' whose language is English:
' August 28, 2009 (Friday)

En el ejemplo siguiente se define una cadena de formato personalizado que muestra un valor de Int64 como un
número de teléfono de Estados Unidos estándar de siete dígitos con el código de área.

using System;

public class Example


{
public static void Main()
{
long number = 8009999999;
string fmt = "000-000-0000";
Console.WriteLine(number.ToString(fmt));
}
}
// The example displays the following output:
// 800-999-9999

Module Example
Public Sub Main()
Dim number As Long = 8009999999
Dim fmt As String = "000-000-0000"
Console.WriteLine(number.ToString(fmt))
End Sub
End Module
' The example displays the following output:

' The example displays the following output:


' 800-999-9999

Aunque las cadenas de formato estándar pueden satisfacer generalmente la mayoría de las necesidades de
formato para los tipos definidos por la aplicación, también puede definir especificadores de formato
personalizados para dar formato a sus tipos.
Cadenas de formato y tipos de .NET
Todos los tipos numéricos (es decir, los tipos Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16,
UInt32, UInt64 y BigInteger), así como DateTime, DateTimeOffset, TimeSpan, Guidy todos los tipos de
enumeración, son compatibles con el formato con cadenas de formato. Para obtener información sobre las
cadenas de formato específicas que admite cada tipo, consulte los temas siguientes:

TITLE DEFINICIÓN

Standard Numeric Format Strings Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de valores
numéricos.

Custom Numeric Format Strings Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para valores numéricos.

Standard Date and Time Format Strings Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de valores
DateTime y DateTimeOffset.

Custom Date and Time Format Strings Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para valores DateTime y
DateTimeOffset.

Cadenas de formato TimeSpan estándar Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de
intervalos de tiempo.

Cadenas de formato TimeSpan personalizado Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para intervalos de
tiempo.

Enumeration Format Strings Describe cadenas de formato estándar que se usan para
crear representaciones de cadena de valores de
enumeración.

Guid.ToString(String) Describe cadenas de formato estándar para los valores de


Guid .

Formato según la referencia cultural con proveedores de formato


Si bien los especificadores de formato permiten personalizar el formato de los objetos, la generación de una
representación de cadena significativa de los objetos requiere a menudo información de formato adicional. Por
ejemplo, cuando se da formato a un número como un valor de divisa mediante la cadena de formato estándar
"C" o la cadena de formato personalizado “$ #,#.00”, se necesita como mínimo información sobre el símbolo de
divisa, el separador de grupos y el separador decimal correctos para incluirla en la cadena con formato. En .NET,
esta información de formato adicional está disponible mediante la interfaz IFormatProvider, que se proporciona
como un parámetro a una o más sobrecargas del método ToString de los tipos numéricos y de fecha y hora.
Las implementaciones de IFormatProvider se usan en .NET para admitir el formato específico de una referencia
cultural. En el siguiente ejemplo se muestra cómo cambia la representación en forma de cadena de un objeto
cuando se le da formato con tres objetos IFormatProvider que representan referencias culturales diferentes.
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
decimal value = 1603.42m;
Console.WriteLine(value.ToString("C3", new CultureInfo("en-US")));
Console.WriteLine(value.ToString("C3", new CultureInfo("fr-FR")));
Console.WriteLine(value.ToString("C3", new CultureInfo("de-DE")));
}
}
// The example displays the following output:
// $1,603.420
// 1 603,420 €
// 1.603,420 €

Imports System.Globalization

Public Module Example


Public Sub Main()
Dim value As Decimal = 1603.42d
Console.WriteLine(value.ToString("C3", New CultureInfo("en-US")))
Console.WriteLine(value.ToString("C3", New CultureInfo("fr-FR")))
Console.WriteLine(value.ToString("C3", New CultureInfo("de-DE")))
End Sub
End Module
' The example displays the following output:
' $1,603.420
' 1 603,420 €
' 1.603,420 €

La interfaz IFormatProvider incluye un método, GetFormat(Type), que tiene un único parámetro que especifica
el tipo de objeto que proporciona información de formato. Si el método puede proporcionar un objeto de ese
tipo, lo devuelve. De lo contrario, devuelve una referencia nula ( Nothing en Visual Basic).
IFormatProvider.GetFormat es un método de devolución de llamada. Al llamar a una sobrecarga del método
ToString que incluye un parámetro de IFormatProvider , se llama al método GetFormat de ese objeto
IFormatProvider . El método GetFormat devuelve un objeto que proporciona al método formatType la
información de formato necesaria especificada por su parámetro ToString .
Varios métodos de formato o de conversión de cadenas incluyen un parámetro de tipo IFormatProviderpero, en
muchos casos, se omite el valor del parámetro cuando se llama al método. En la tabla siguiente se muestran
algunos métodos de formato que usan el parámetro y el tipo del objeto Type que pasan al método
IFormatProvider.GetFormat .

MÉTODO TIPO DE PARÁMETRO FORMATTYPE

Método ToString de tipos numéricos System.Globalization.NumberFormatInfo

Método ToString de tipos de fecha y hora System.Globalization.DateTimeFormatInfo

String.Format System.ICustomFormatter

StringBuilder.AppendFormat System.ICustomFormatter
NOTE
Los métodos ToString de los tipos numéricos y los tipos de fecha y hora se sobrecargan y solo algunas de las
sobrecargas incluyen un parámetro IFormatProvider . Si un método no tiene un parámetro de tipo IFormatProvider, se
pasa en su lugar el objeto devuelto por la propiedad CultureInfo.CurrentCulture . Por ejemplo, una llamada al método
Int32.ToString() predeterminado resultará finalmente en una llamada similar a esta:
Int32.ToString("G", System.Globalization.CultureInfo.CurrentCulture) .

.NET proporciona tres clases que implementan IFormatProvider:


DateTimeFormatInfo, una clase que proporciona información de formato para los valores de fecha y hora
para una referencia cultural concreta. Su implementación de IFormatProvider.GetFormat devuelve una
instancia de sí misma.
NumberFormatInfo, una clase que proporciona información de formato numérico para una referencia
cultural concreta. Su implementación de IFormatProvider.GetFormat devuelve una instancia de sí misma.
CultureInfo. Su implementación de IFormatProvider.GetFormat puede devolver un objeto
NumberFormatInfo para proporcionar información de formato numérico o un objeto
DateTimeFormatInfo para proporcionar información de formato para los valores de fecha y hora.
También se puede implementar un proveedor de formato propio para reemplazar cualquiera de estas clases. Sin
embargo, el método GetFormat de la implementación debe devolver un objeto del tipo mostrado en la tabla
anterior si debe proporcionar información de formato al método ToString .
Formato que tiene en cuenta las referencias culturales de valores numéricos
De forma predeterminada, el formato de los valores numéricos depende de la referencia cultural. Si no
especifica una referencia cultural cuando llama a un método de formato, se utilizan las convenciones de formato
de la referencia cultural del subproceso actual. Esto se muestra en el ejemplo siguiente, que cambia la referencia
cultural del subproceso actual cuatro veces y después llama al método Decimal.ToString(String) . En cada caso,
la cadena resultante refleja las convenciones de formato de la referencia cultural actual. Esto se debe a que los
métodos ToString y ToString(String) incluyen llamadas a cada tipo numérico del método
ToString(String, IFormatProvider) .
using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
string[] cultureNames = { "en-US", "fr-FR", "es-MX", "de-DE" };
Decimal value = 1043.17m;

foreach (var cultureName in cultureNames) {


// Change the current thread culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
Console.WriteLine("The current culture is {0}",
Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine(value.ToString("C2"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// The current culture is en-US
// $1,043.17
//
// The current culture is fr-FR
// 1 043,17 €
//
// The current culture is es-MX
// $1,043.17
//
// The current culture is de-DE
// 1.043,17 €

Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim cultureNames() As String = { "en-US", "fr-FR", "es-MX", "de-DE" }
Dim value As Decimal = 1043.17d

For Each cultureName In cultureNames


' Change the current thread culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
Console.WriteLine("The current culture is {0}",
Thread.CurrentThread.CurrentCulture.Name)
Console.WriteLine(value.ToString("C2"))
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' The current culture is en-US
' $1,043.17
'
' The current culture is fr-FR
' 1 043,17 €
'
' The current culture is es-MX
' $1,043.17
'
' The current culture is de-DE
' 1.043,17 €
También se puede dar formato a un valor numérico para una referencia cultural concreta llamando a una
sobrecarga de ToString que tenga un parámetro provider y pasándole uno de los elementos siguientes:
Un objeto CultureInfo que representa la referencia cultural cuyas convenciones de formato se van a usar.
El método CultureInfo.GetFormat devuelve el valor de la propiedad CultureInfo.NumberFormat , que es
el objeto NumberFormatInfo que proporciona información sobre el formato de la referencia cultural para
los valores numéricos.
Un objeto NumberFormatInfo que define las convenciones de formato de la referencia cultural que se
van a usar. Su método GetFormat devuelve una instancia de sí mismo.
En el siguiente ejemplo se utilizan objetos NumberFormatInfo que representan las referencias culturales de
inglés (Estados Unidos) e inglés (Reino Unido), y las referencias culturales neutras de francés y ruso para dar
formato a un número de punto flotante.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
Double value = 1043.62957;
string[] cultureNames = { "en-US", "en-GB", "ru", "fr" };

foreach (var name in cultureNames) {


NumberFormatInfo nfi = CultureInfo.CreateSpecificCulture(name).NumberFormat;
Console.WriteLine("{0,-6} {1}", name + ":", value.ToString("N3", nfi));
}
}
}
// The example displays the following output:
// en-US: 1,043.630
// en-GB: 1,043.630
// ru: 1 043,630
// fr: 1 043,630

Imports System.Globalization

Module Example
Public Sub Main()
Dim value As Double = 1043.62957
Dim cultureNames() As String = { "en-US", "en-GB", "ru", "fr" }

For Each name In cultureNames


Dim nfi As NumberFormatInfo = CultureInfo.CreateSpecificCulture(name).NumberFormat
Console.WriteLine("{0,-6} {1}", name + ":", value.ToString("N3", nfi))
Next
End Sub
End Module
' The example displays the following output:
' en-US: 1,043.630
' en-GB: 1,043.630
' ru: 1 043,630
' fr: 1 043,630

Formato que tiene en cuenta las referencias culturales de valores de fecha y hora
De forma predeterminada, el formato de los valores de fecha y hora tiene en cuenta las referencias culturales. Si
no especifica una referencia cultural cuando llama a un método de formato, se utilizan las convenciones de
formato de la referencia cultural del subproceso actual. Esto se muestra en el ejemplo siguiente, que cambia la
referencia cultural del subproceso actual cuatro veces y después llama al método DateTime.ToString(String) . En
cada caso, la cadena resultante refleja las convenciones de formato de la referencia cultural actual. Esto se debe
a que los métodos DateTime.ToString(), DateTime.ToString(String), DateTimeOffset.ToString()y
DateTimeOffset.ToString(String) encapsulan llamadas a los métodos DateTime.ToString(String,
IFormatProvider) y DateTimeOffset.ToString(String, IFormatProvider) .

using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
string[] cultureNames = { "en-US", "fr-FR", "es-MX", "de-DE" };
DateTime dateToFormat = new DateTime(2012, 5, 28, 11, 30, 0);

foreach (var cultureName in cultureNames) {


// Change the current thread culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
Console.WriteLine("The current culture is {0}",
Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine(dateToFormat.ToString("F"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// The current culture is en-US
// Monday, May 28, 2012 11:30:00 AM
//
// The current culture is fr-FR
// lundi 28 mai 2012 11:30:00
//
// The current culture is es-MX
// lunes, 28 de mayo de 2012 11:30:00 a.m.
//
// The current culture is de-DE
// Montag, 28. Mai 2012 11:30:00
Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim cultureNames() As String = { "en-US", "fr-FR", "es-MX", "de-DE" }
Dim dateToFormat As Date = #5/28/2012 11:30AM#

For Each cultureName In cultureNames


' Change the current thread culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
Console.WriteLine("The current culture is {0}",
Thread.CurrentThread.CurrentCulture.Name)
Console.WriteLine(dateToFormat.ToString("F"))
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' The current culture is en-US
' Monday, May 28, 2012 11:30:00 AM
'
' The current culture is fr-FR
' lundi 28 mai 2012 11:30:00
'
' The current culture is es-MX
' lunes, 28 de mayo de 2012 11:30:00 a.m.
'
' The current culture is de-DE
' Montag, 28. Mai 2012 11:30:00

También se puede dar formato a un valor de fecha y hora para una referencia cultural concreta llamando a una
sobrecarga de DateTime.ToString o DateTimeOffset.ToString que tenga un parámetro provider y pasándole
uno de los elementos siguientes:
Un objeto CultureInfo que representa la referencia cultural cuyas convenciones de formato se van a usar.
Su método CultureInfo.GetFormat devuelve el valor de la propiedad CultureInfo.DateTimeFormat , que
es el objeto DateTimeFormatInfo que proporciona información sobre el formato de una referencia
cultural específica para valores de fecha y hora.
Un objeto DateTimeFormatInfo que define las convenciones de formato de la referencia cultural que se
van a usar. Su método GetFormat devuelve una instancia de sí mismo.
En el siguiente ejemplo se utilizan objetos DateTimeFormatInfo que representan las referencias culturales de
inglés (Estados Unidos) e inglés (Reino Unido), y las referencias culturales neutras de francés y ruso para dar
formato a una fecha.
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
DateTime dat1 = new DateTime(2012, 5, 28, 11, 30, 0);
string[] cultureNames = { "en-US", "en-GB", "ru", "fr" };

foreach (var name in cultureNames) {


DateTimeFormatInfo dtfi = CultureInfo.CreateSpecificCulture(name).DateTimeFormat;
Console.WriteLine("{0}: {1}", name, dat1.ToString(dtfi));
}
}
}
// The example displays the following output:
// en-US: 5/28/2012 11:30:00 AM
// en-GB: 28/05/2012 11:30:00
// ru: 28.05.2012 11:30:00
// fr: 28/05/2012 11:30:00

Imports System.Globalization

Module Example
Public Sub Main()
Dim dat1 As Date = #5/28/2012 11:30AM#
Dim cultureNames() As String = { "en-US", "en-GB", "ru", "fr" }

For Each name In cultureNames


Dim dtfi As DateTimeFormatInfo = CultureInfo.CreateSpecificCulture(name).DateTimeFormat
Console.WriteLine("{0}: {1}", name, dat1.ToString(dtfi))
Next
End Sub
End Module
' The example displays the following output:
' en-US: 5/28/2012 11:30:00 AM
' en-GB: 28/05/2012 11:30:00
' ru: 28.05.2012 11:30:00
' fr: 28/05/2012 11:30:00

Interfaz IFormattable
Normalmente, los tipos que sobrecargan el método ToString con una cadena de formato y un parámetro
IFormatProvider también implementan la interfaz IFormattable . Esta interfaz tiene un solo miembro,
IFormattable.ToString(String, IFormatProvider), que incluye una cadena de formato y un proveedor de formato
como parámetros.
La implementación de la interfaz IFormattable para su clase definida por la aplicación ofrece dos ventajas:
Compatibilidad con la conversión de cadenas por la clase Convert . Las llamadas a los métodos
Convert.ToString(Object) y Convert.ToString(Object, IFormatProvider) llaman automáticamente a su
implementación de IFormattable .
Compatibilidad con formatos compuestos. Si se usa un elemento de formato que incluye una cadena de
formato para dar formato a su tipo personalizado, Common Language Runtime llama automáticamente
a su implementación de IFormattable y le pasa la cadena de formato. Para obtener más información
sobre los formatos compuestos con métodos como String.Format o Console.WriteLine, vea la sección
Formatos compuestos .
En el ejemplo siguiente se define una clase Temperature que implementa la interfaz IFormattable . Admite los
especificadores de formato "C" o "G" para mostrar la temperatura en grados centígrados, el especificador de
formato "F" para mostrar la temperatura en grados Fahrenheit y el especificador de formato "K" para mostrar la
temperatura en grados Kelvin.
using System;
using System.Globalization;

public class Temperature : IFormattable


{
private decimal m_Temp;

public Temperature(decimal temperature)


{
this.m_Temp = temperature;
}

public decimal Celsius


{
get { return this.m_Temp; }
}

public decimal Kelvin


{
get { return this.m_Temp + 273.15m; }
}

public decimal Fahrenheit


{
get { return Math.Round((decimal) this.m_Temp * 9 / 5 + 32, 2); }
}

public override string ToString()


{
return this.ToString("G", null);
}

public string ToString(string format)


{
return this.ToString(format, null);
}

public string ToString(string format, IFormatProvider provider)


{
// Handle null or empty arguments.
if (String.IsNullOrEmpty(format))
format = "G";
// Remove any white space and covert to uppercase.
format = format.Trim().ToUpperInvariant();

if (provider == null)
provider = NumberFormatInfo.CurrentInfo;

switch (format)
{
// Convert temperature to Fahrenheit and return string.
case "F":
return this.Fahrenheit.ToString("N2", provider) + "°F";
// Convert temperature to Kelvin and return string.
case "K":
return this.Kelvin.ToString("N2", provider) + "K";
// Return temperature in Celsius.
case "C":
case "G":
return this.Celsius.ToString("N2", provider) + "°C";
default:
throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
}
}
}
Imports System.Globalization

Public Class Temperature : Implements IFormattable


Private m_Temp As Decimal

Public Sub New(temperature As Decimal)


Me.m_Temp = temperature
End Sub

Public ReadOnly Property Celsius() As Decimal


Get
Return Me.m_Temp
End Get
End Property

Public ReadOnly Property Kelvin() As Decimal


Get
Return Me.m_Temp + 273.15d
End Get
End Property

Public ReadOnly Property Fahrenheit() As Decimal


Get
Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
End Get
End Property

Public Overrides Function ToString() As String


Return Me.ToString("G", Nothing)
End Function

Public Overloads Function ToString(format As String) As String


Return Me.ToString(format, Nothing)
End Function

Public Overloads Function ToString(format As String, provider As IFormatProvider) As String _


Implements IFormattable.ToString

' Handle null or empty arguments.


If String.IsNullOrEmpty(format) Then format = "G"
' Remove any white space and convert to uppercase.
format = format.Trim().ToUpperInvariant()

If provider Is Nothing Then provider = NumberFormatInfo.CurrentInfo

Select Case format


' Convert temperature to Fahrenheit and return string.
Case "F"
Return Me.Fahrenheit.ToString("N2", provider) & "°F"
' Convert temperature to Kelvin and return string.
Case "K"
Return Me.Kelvin.ToString("N2", provider) & "K"
' Return temperature in Celsius.
Case "C", "G"
Return Me.Celsius.ToString("N2", provider) & "°C"
Case Else
Throw New FormatException(String.Format("The '{0}' format string is not supported.", format))
End Select
End Function
End Class

En el ejemplo siguiente se crea una instancia de un objeto Temperature . A continuación, llama al método
ToString y usa varias cadenas de formato compuesto para obtener representaciones de cadena diferentes de un
objeto Temperature . Cada una de estas llamadas al método, a su vez, llama a la implementación de
IFormattable de la clase Temperature .
public class Example
{
public static void Main()
{
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
Temperature temp = new Temperature(22m);
Console.WriteLine(Convert.ToString(temp, new CultureInfo("ja-JP")));
Console.WriteLine("Temperature: {0:K}", temp);
Console.WriteLine("Temperature: {0:F}", temp);
Console.WriteLine(String.Format(new CultureInfo("fr-FR"), "Temperature: {0:F}", temp));
}
}
// The example displays the following output:
// 22.00°C
// Temperature: 295.15K
// Temperature: 71.60°F
// Temperature: 71,60°F

Public Module Example


Public Sub Main()
Dim temp As New Temperature(22d)
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US")
Console.WriteLine(Convert.ToString(temp1, New CultureInfo("ja-JP")))
Console.WriteLine("Temperature: {0:K}", temp)
Console.WriteLine("Temperature: {0:F}", temp)
Console.WriteLine(String.Format(New CultureInfo("fr-FR"), "Temperature: {0:F}", temp))
End Sub
End Module
' The example displays the following output:
' 22.00°C
' Temperature: 295.15K
' Temperature: 71.60°F
' Temperature: 71,60°F

Formatos compuestos
Algunos métodos, como String.Format y StringBuilder.AppendFormat, admiten formatos compuestos. Una
cadena de formato compuesto es un tipo de plantilla que devuelve una sola cadena que incorpora la
representación de cadena de cero, uno o más objetos. Cada objeto se representa en la cadena de formato
compuesto mediante un elemento de formato indizado. El índice del elemento de formato corresponde a la
posición del objeto que representa en la lista de parámetros del método. Los índices son de base cero. Por
ejemplo, en la siguiente llamada al método String.Format , el primer elemento de formato, {0:D} se reemplaza
con la representación de cadena de thatDate ; el segundo elemento de formato, {1} , se reemplaza con la
representación de cadena de item1 y el tercer elemento de formato, {2:C2} , se reemplaza con la
representación de cadena de item1.Value .

result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.",


thatDate, item1, item1.Value);
Console.WriteLine(result);
// The example displays output like the following if run on a system
// whose current culture is en-US:
// On 5/1/2009, the inventory of WidgetA was worth $107.44.
result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.", _
thatDate, item1, item1.Value)
Console.WriteLine(result)
' The example displays output like the following if run on a system
' whose current culture is en-US:
' On 5/1/2009, the inventory of WidgetA was worth $107.44.

Además de reemplazar un elemento de formato con la representación de cadena de su objeto correspondiente,


los elementos de formato también permiten controlar lo siguiente:
La forma específica en que un objeto se representa como una cadena, si el objeto implementa la interfaz
IFormattable y admite cadenas de formato. Para ello, siga el índice del elemento de formato con un signo
: (dos puntos) seguido de una cadena de formato válida. En el ejemplo anterior, esto se hacía dando
formato a un valor de fecha con la cadena de formato "d" (patrón de fecha corta) (por ejemplo, {0:d} ) y
dando formato a un valor numérico con la cadena de formato "C2" (por ejemplo, {2:C2} ) para
representar el número como un valor de moneda con dos decimales fraccionarios.
El ancho del campo que contiene la representación de cadena del objeto y la alineación de la
representación de cadena en ese campo. Para ello, escriba una coma ( , ) seguida del ancho del campo.
La cadena se alinea a la derecha en el campo si el ancho del campo es un valor positivo, y se alinea a la
izquierda si el ancho del campo es un valor negativo. En el ejemplo siguiente los valores de fecha se
alinean a la izquierda en un campo de 20 caracteres y los valores decimales con un dígito fraccionario se
alinean a la derecha en un campo de 11 caracteres.

DateTime startDate = new DateTime(2015, 8, 28, 6, 0, 0);


decimal[] temps = { 73.452m, 68.98m, 72.6m, 69.24563m,
74.1m, 72.156m, 72.228m };
Console.WriteLine("{0,-20} {1,11}\n", "Date", "Temperature");
for (int ctr = 0; ctr < temps.Length; ctr++)
Console.WriteLine("{0,-20:g} {1,11:N1}", startDate.AddDays(ctr), temps[ctr]);

// The example displays the following output:


// Date Temperature
//
// 8/28/2015 6:00 AM 73.5
// 8/29/2015 6:00 AM 69.0
// 8/30/2015 6:00 AM 72.6
// 8/31/2015 6:00 AM 69.2
// 9/1/2015 6:00 AM 74.1
// 9/2/2015 6:00 AM 72.2
// 9/3/2015 6:00 AM 72.2
Dim startDate As New Date(2015, 8, 28, 6, 0, 0)
Dim temps() As Decimal = { 73.452, 68.98, 72.6, 69.24563,
74.1, 72.156, 72.228 }
Console.WriteLine("{0,-20} {1,11}", "Date", "Temperature")
Console.WriteLine()
For ctr As Integer = 0 To temps.Length - 1
Console.WriteLine("{0,-20:g} {1,11:N1}", startDate.AddDays(ctr), temps(ctr))
Next
' The example displays the following output:
' Date Temperature
'
' 8/28/2015 6:00 AM 73.5
' 8/29/2015 6:00 AM 69.0
' 8/30/2015 6:00 AM 72.6
' 8/31/2015 6:00 AM 69.2
' 9/1/2015 6:00 AM 74.1
' 9/2/2015 6:00 AM 72.2
' 9/3/2015 6:00 AM 72.2

Tenga en cuenta que, si están presentes tanto el componente de cadena de alineación como el
componente de cadena de formato, el primero precede al último (por ejemplo, {0,-20:g} ).
Para más información sobre los formatos compuestos, vea Formatos compuestos.

Formato personalizado con ICustomFormatter


Dos métodos de formato compuesto, String.Format(IFormatProvider, String, Object[]) y
StringBuilder.AppendFormat(IFormatProvider, String, Object[]), incluyen un parámetro de proveedor de
formato que admite formatos personalizados. Cuando se llama a alguno de estos métodos de formato, se pasa
un objeto Type que representa una interfaz ICustomFormatter al método GetFormat del proveedor de formato.
A continuación, el método GetFormat devuelve la implementación de ICustomFormatter que proporciona el
formato personalizado.
La interfaz ICustomFormatter tiene un único método, Format(String, Object, IFormatProvider), al que un
método de formato compuesto llama automáticamente una vez para cada elemento de formato de una cadena
de formato compuesto. El método Format(String, Object, IFormatProvider) tiene tres parámetros: una cadena
de formato, que representa el argumento formatString de un elemento de formato, un objeto para dar formato
y un objeto IFormatProvider que proporciona servicios de formato. Normalmente, la clase que implementa
ICustomFormatter también implementa IFormatProvider, de modo que este último parámetro es una
referencia a la propia clase de formato personalizado. El método devuelve una representación de cadena con
formato personalizado del objeto al que se va a dar formato. Si el método no puede dar formato al objeto, debe
devolver una referencia nula ( Nothing en Visual Basic).
En el ejemplo siguiente se proporciona una implementación de ICustomFormatter denominada
ByteByByteFormatter que muestra los valores enteros como una secuencia de valores hexadecimales de dos
dígitos seguidos de un espacio.
public class ByteByByteFormatter : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}

public string Format(string format, object arg,


IFormatProvider formatProvider)
{
if (! formatProvider.Equals(this)) return null;

// Handle only hexadecimal format string.


if (! format.StartsWith("X")) return null;

byte[] bytes;
string output = null;

// Handle only integral types.


if (arg is Byte)
bytes = BitConverter.GetBytes((Byte) arg);
else if (arg is Int16)
bytes = BitConverter.GetBytes((Int16) arg);
else if (arg is Int32)
bytes = BitConverter.GetBytes((Int32) arg);
else if (arg is Int64)
bytes = BitConverter.GetBytes((Int64) arg);
else if (arg is SByte)
bytes = BitConverter.GetBytes((SByte) arg);
else if (arg is UInt16)
bytes = BitConverter.GetBytes((UInt16) arg);
else if (arg is UInt32)
bytes = BitConverter.GetBytes((UInt32) arg);
else if (arg is UInt64)
bytes = BitConverter.GetBytes((UInt64) arg);
else
return null;

for (int ctr = bytes.Length - 1; ctr >= 0; ctr--)


output += String.Format("{0:X2} ", bytes[ctr]);

return output.Trim();
}
}
Public Class ByteByByteFormatter : Implements IFormatProvider, ICustomFormatter
Public Function GetFormat(formatType As Type) As Object _
Implements IFormatProvider.GetFormat
If formatType Is GetType(ICustomFormatter) Then
Return Me
Else
Return Nothing
End If
End Function

Public Function Format(fmt As String, arg As Object,


formatProvider As IFormatProvider) As String _
Implements ICustomFormatter.Format

If Not formatProvider.Equals(Me) Then Return Nothing

' Handle only hexadecimal format string.


If Not fmt.StartsWith("X") Then
Return Nothing
End If

' Handle only integral types.


If Not typeof arg Is Byte AndAlso
Not typeof arg Is Int16 AndAlso
Not typeof arg Is Int32 AndAlso
Not typeof arg Is Int64 AndAlso
Not typeof arg Is SByte AndAlso
Not typeof arg Is UInt16 AndAlso
Not typeof arg Is UInt32 AndAlso
Not typeof arg Is UInt64 Then _
Return Nothing

Dim bytes() As Byte = BitConverter.GetBytes(arg)


Dim output As String = Nothing

For ctr As Integer = bytes.Length - 1 To 0 Step -1


output += String.Format("{0:X2} ", bytes(ctr))
Next

Return output.Trim()
End Function
End Class

En el ejemplo siguiente se usa la clase ByteByByteFormatter para dar formato a valores enteros. Observe que en
el ejemplo no se llama explícitamente al método ICustomFormatter.Format más de una vez en la segunda
llamada al método String.Format(IFormatProvider, String, Object[]) y que el proveedor NumberFormatInfo
predeterminado se usa en la tercera llamada al método porque el método ByteByByteFormatter.Format no
reconoce la cadena de formato "N0" y devuelve una referencia nula ( Nothing en Visual Basic).
public class Example
{
public static void Main()
{
long value = 3210662321;
byte value1 = 214;
byte value2 = 19;

Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X}", value));


Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})",
value1, value2, value1 & value2));
Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0,10:N0}", value));
}
}
// The example displays the following output:
// 00 00 00 00 BF 5E D1 B1
// 00 D6 And 00 13 = 00 12 (018)
// 3,210,662,321

Public Module Example


Public Sub Main()
Dim value As Long = 3210662321
Dim value1 As Byte = 214
Dim value2 As Byte = 19

Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X}", value)))


Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})",
value1, value2, value1 And value2)))
Console.WriteLine(String.Format(New ByteByByteFormatter(), "{0,10:N0}", value))
End Sub
End Module
' The example displays the following output:
' 00 00 00 00 BF 5E D1 B1
' 00 D6 And 00 13 = 00 12 (018)
' 3,210,662,321

Temas relacionados
TITLE DEFINICIÓN

Standard Numeric Format Strings Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de valores
numéricos.

Custom Numeric Format Strings Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para valores numéricos.

Standard Date and Time Format Strings Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de valores
DateTime .

Custom Date and Time Format Strings Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para valores DateTime .

Cadenas de formato TimeSpan estándar Describe cadenas de formato estándar que crean
representaciones de cadena usadas con frecuencia de
intervalos de tiempo.
TITLE DEFINICIÓN

Cadenas de formato TimeSpan personalizado Describe cadenas de formato personalizado que crean
formatos específicos de la aplicación para intervalos de
tiempo.

Enumeration Format Strings Describe cadenas de formato estándar que se usan para
crear representaciones de cadena de valores de
enumeración.

Formatos compuestos Describe cómo incrustar uno o más valores con formato en
una cadena. Posteriormente se puede mostrar la cadena en
la consola o escrita en una secuencia.

Efectuar operaciones de formato Muestra los temas en los que se proporcionan instrucciones
paso a paso para realizar operaciones de formato concretas.

Analizar cadenas en .NET Describe cómo inicializar objetos en los valores descritos por
representaciones de cadena de dichos objetos. El análisis es
la operación inversa de la aplicación de formato.

Referencia
System.IFormattable
System.IFormatProvider
System.ICustomFormatter
Cadenas con formato numérico estándar
13/01/2020 • 48 minutes to read • Edit Online

Las cadenas de formato numérico estándar se utilizan para dar formato a tipos numéricos comunes. La forma de
una cadena de formato numérico estándar es Axx , donde:
A es un carácter alfabético único denominado especificador de formato. Cualquier cadena de formato
numérico que contenga más de un carácter alfabético, incluido el espacio en blanco, se interpreta como
una cadena de formato numérico personalizado. Para obtener más información, consulte Cadenas con
formato numérico personalizado.
xx es un entero opcional denominado especificador de precisión. El especificador de precisión está
comprendido entre el 0 y el 99 y afecta al número de dígitos del resultado. Observe que el especificador
de precisión controla el número de dígitos en la representación de cadena de un número. No redondea el
número en sí. Para realizar una operación de redondeo, use el método Math.Ceiling, Math.Floor o
Math.Round.
Cuando el especificador de precisión controla el número de dígitos fraccionarios de la cadena de
resultado, esta refleja un número redondeado al resultado representable más cercano al resultado de
precisión infinita. En el caso de que haya dos resultados representables igualmente cercanos:
En .NET Framework y .NET Core (hasta la versión 2.0) , el runtime selecciona el resultado con el
dígito menos significativo más elevado (es decir, usando MidpointRounding.AwayFromZero).
En .NET Core 2.1 y versiones posteriores, el runtime selecciona el resultado con un dígito menos
significativo par (es decir, usando MidpointRounding.ToEven).

NOTE
El especificador de precisión determina el número de dígitos de la cadena de resultado. Para rellenar una cadena de
resultado con espacios iniciales o finales, use la característica formatos compuestos y defina un componente de
alineación en el elemento de formato.

Las cadenas con formato numérico estándar son compatibles con:


Algunas sobrecargas del método ToString de todos los tipos numéricos. Por ejemplo, se puede
proporcionar una cadena de formato numérico a los métodos Int32.ToString(String) y
Int32.ToString(String, IFormatProvider).
La característica de formato compuesto de .NET, que utilizan algunos métodos Write y WriteLine de las
clases Console y StreamWriter, el método String.Format y el método StringBuilder.AppendFormat. La
característica de formato compuesto permite incluir la representación de varios elementos de datos en
una sola cadena a fin de especificar el ancho de campo y alinear números en un campo. Para obtener más
información, consulte Formatos compuestos.
Cadenas interpoladas en C# y Visual Basic, que proporcionan una sintaxis simplificada cuando se
comparan con las cadenas de formato compuesto.
TIP
Puede descargar la Utilidad de formato, que es una aplicación de .NET Core Windows Forms que permite aplicar cadenas
de formato a valores numéricos o de fecha y hora, y que muestra la cadena de resultado. El código fuente está disponible
para C# y Visual Basic.

En la tabla siguiente se describen los especificadores de formato numérico estándar y se muestran los resultados
de ejemplo generados por cada especificador de formato. Consulte la sección Notas para obtener información
adicional sobre cómo usar las cadenas con formato numérico estándar y la sección Ejemplo para ver una
ilustración completa de su uso.

ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"C" o "c" Moneda Resultado: un valor de 123.456 ("C", en-US) ->


divisa. \$123.46

Compatible con: todos los 123.456 ("C", fr-FR) ->


tipos numéricos. 123,46 €

Especificador de precisión: 123.456 ("C", ja-JP) ->


número de dígitos ¥123
decimales.
-123.456 ("C3", en-US) ->
Especificador de precisión (\$123.456)
predeterminado: Definido
por -123.456 ("C3", fr-FR) -> -
NumberFormatInfo.Currenc 123,456 €
yDecimalDigits.
-123.456 ("C3", ja-JP) ->
Más información: -¥123.456
Especificador de formato de
divisa ("C").

"D" o "d" Decimal Resultado: dígitos enteros 1234 ("D") -> 1234
con signo negativo
opcional. -1234 ("D6") -> -001234

Compatible con: solo tipos


enteros.

Especificador de precisión:
número mínimo de dígitos.

Especificador de precisión
predeterminado: número
mínimo de dígitos
necesario.

Más información:
Especificador de formato
decimal ("D").
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"E" o "e" Exponencial (científico) Resultado: notación 1052.0329112756 ("E", en-


exponencial. US) -> 1.052033E+003

Compatible con: todos los 1052.0329112756 ("e", fr-


tipos numéricos. FR) -> 1,052033e+003

Especificador de precisión: -1052.0329112756 ("e2",


número de dígitos en-US) -> -1.05e+003
decimales.
-1052.0329112756 ("E2",
Especificador de precisión fr-FR) -> -1,05E+003
predeterminado: 6.

Más información:
Especificador de formato
exponencial ("E").

"F" o "f" Punto fijo Resultado: dígitos integrales 1234.567 ("F", en-US) ->
y decimales con signo 1234.57
negativo opcional.
1234.567 ("F", de-DE) ->
Compatible con: todos los 1234,57
tipos numéricos.
1234 ("F1", en-US) ->
Especificador de precisión: 1234.0
número de dígitos
decimales. 1234 ("F1", de-DE) ->
1234,0
Especificador de precisión
predeterminado: Definido -1234.56 ("F4", en-US) -> -
por 1234.5600
NumberFormatInfo.Number
DecimalDigits. -1234.56 ("F4", de-DE) -> -
1234,5600
Más información:
Especificador de formato de
punto fijo ("F").

"G" o "g" General Resultado: notación de -123.456 ("G", en-US) -> -


punto fijo o científica, la que 123.456
sea más compacta.
-123.456 ("G", sv-SE) -> -
Compatible con: todos los 123,456
tipos numéricos.
123.4546 ("G4", en-US) ->
Especificador de precisión: 123.5
número de dígitos
significativos. 123.4546 ("G4", sv-SE) ->
123,5
Especificador de precisión
predeterminado: depende -1.234567890e-25 ("G",
del tipo numérico. en-US) -> -1.23456789E-
25
Más información:
Especificador de formato -1.234567890e-25 ("G", sv-
general ("G"). SE) -> -1,23456789E-25
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"N" o "n" número Resultado: dígitos integrales 1234.567 ("N", en-US) ->
y decimales, separadores de 1,234.57
grupos y un separador
decimal con signo negativo 1234.567 ("N", ru-RU) -> 1
opcional. 234,57

Compatible con: todos los 1234 ("N1", en-US) ->


tipos numéricos. 1,234.0

Especificador de precisión: 1234 ("N1", ru-RU) -> 1


número deseado de 234,0
decimales.
-1234.56 ("N3", en-US) -> -
Especificador de precisión 1,234.560
predeterminado: Definido
por -1234.56 ("N3", ru-RU) -> -
NumberFormatInfo.Number 1 234,560
DecimalDigits.

Más información:
Especificador de formato
numérico ("N").

"P" o "p" Porcentaje Resultado: número 1 ("P", en-US) -> 100.00 %


multiplicado por 100 y
mostrado con un símbolo 1 ("P", fr-FR) -> 100,00 %
de porcentaje.
-0.39678 ("P1", en-US) -> -
Compatible con: todos los 39.7 %
tipos numéricos.
-0.39678 ("P1", fr-FR) -> -
Especificador de precisión: 39,7 %
número deseado de
decimales.

Especificador de precisión
predeterminado: Definido
por
NumberFormatInfo.Percent
DecimalDigits.

Más información:
Especificador de formato de
porcentaje ("P").
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"R" o "r" Acción de ida y vuelta Resultado: cadena que 123456789.12345678 ("R")
puede aplicar acciones de -> 123456789.12345678
ida y vuelta (round-trip) a
un número idéntico. -1234567890.12345678
("R") -> -
Compatible con: Single, 1234567890.1234567
Double y BigInteger.

Nota: Se recomienda solo


para el tipo BigInteger. Para
los tipos Double, use "G17";
para los tipos Single, use
"G9".
Especificador de precisión:
ignorado.

Más información:
Especificador de formato de
operación de ida y vuelta
("R").

"X" o "x" Hexadecimal Resultado: cadena 255 ("X") -> FF


hexadecimal.
-1 ("x") -> ff
Compatible con: solo tipos
enteros. 255 ("x4") -> 00ff

Especificador de precisión: -1 ("X4") -> 00FF


número de dígitos en la
cadena de resultado.

Más información:
Especificador de formato
hexadecimal ("X").

Cualquier otro carácter Especificador desconocido Resultado: produce


único FormatException en tiempo
de ejecución.

Usar cadenas de formato numérico estándar


NOTE
Los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET. Haga clic en
el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código, puede modificar
y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la ventana interactiva
o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes de error del
compilador de C#.

Una cadena de formato numérico estándar se puede usar para definir el formato de un valor numérico de una
de dos maneras:
Se puede pasar a una sobrecarga del método ToString que tiene un parámetro format . En el ejemplo
siguiente se da formato a un valor numérico como una cadena de divisa en la referencia cultural actual
(en este caso, en-US ).
Decimal value = static_cast<Decimal>(123.456);
Console::WriteLine(value.ToString("C2"));
// Displays $123.46

decimal value = 123.456m;


Console.WriteLine(value.ToString("C2"));
// Displays $123.46

Dim value As Decimal = 123.456d


Console.WriteLine(value.ToString("C2"))
' Displays $123.46

Se puede proporcionar como el argumento formatString de un elemento de formato usado con


métodos como String.Format, Console.WriteLine y StringBuilder.AppendFormat. Para obtener más
información, consulte Formatos compuestos. En el ejemplo siguiente se usa un elemento de formato para
insertar un valor de divisa en una cadena.

Decimal value = static_cast<Decimal>(123.456);


Console::WriteLine("Your account balance is {0:C2}.", value);
// Displays "Your account balance is $123.46."

decimal value = 123.456m;


Console.WriteLine("Your account balance is {0:C2}.", value);
// Displays "Your account balance is $123.46."

Dim value As Decimal = 123.456d


Console.WriteLine("Your account balance is {0:C2}.", value)
' Displays "Your account balance is $123.46."

Opcionalmente, puede facilitar un argumento alignment para especificar el ancho del campo numérico y
si su valor está alineado a izquierda o derecha. En el ejemplo siguiente se alinea a la izquierda un valor de
moneda en un campo de 28 caracteres y se alinea a la derecha un valor de moneda en un campo de 14
caracteres.

array<Decimal>^ amounts = { static_cast<Decimal>(16305.32),


static_cast<Decimal>(18794.16) };
Console::WriteLine(" Beginning Balance Ending Balance");
Console::WriteLine(" {0,-28:C2}{1,14:C2}", amounts[0], amounts[1]);
// Displays:
// Beginning Balance Ending Balance
// $16,305.32 $18,794.16

decimal[] amounts = { 16305.32m, 18794.16m };


Console.WriteLine(" Beginning Balance Ending Balance");
Console.WriteLine(" {0,-28:C2}{1,14:C2}", amounts[0], amounts[1]);
// Displays:
// Beginning Balance Ending Balance
// $16,305.32 $18,794.16
Dim amounts() As Decimal = { 16305.32d, 18794.16d }
Console.WriteLine(" Beginning Balance Ending Balance")
Console.WriteLine(" {0,-28:C2}{1,14:C2}", amounts(0), amounts(1))
' Displays:
' Beginning Balance Ending Balance
' $16,305.32 $18,794.16

Se puede proporcionar como el argumento formatString en un elemento de la expresión interpolada de


una cadena interpolada. Para más información, vea el tema $ (Referencia de C#) en la referencia de C# o
el tema Interpolated Strings (Visual Basic Reference) [Cadenas interpoladas (Referencia de Visual Basic)]
en la referencia de Visual Basic.
En las secciones siguientes se proporciona información detallada sobre cada una de las cadenas de formato
numérico estándar.

Especificador de formato de divisa ("C")


El especificador de formato "C" (divisa) convierte un número en una cadena que representa una cantidad de
divisa. El especificador de precisión indica el número deseado de posiciones decimales en la cadena de resultado.
Si se omite el especificador de precisión, la precisión predeterminada está definida por la propiedad
NumberFormatInfo.CurrencyDecimalDigits.
Si el valor al que se va a dar formato tiene más posiciones decimales que el número especificado o
predeterminado, el valor fraccionario se redondea en la cadena de resultado. Si el valor situado a la derecha del
número de posiciones decimales especificadas es 5 o superior, el último dígito de la cadena de resultado se
redondea desde cero.
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. En la tabla
siguiente se enumeran las propiedades de NumberFormatInfo que controlan el formato de la cadena devuelta.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

CurrencyPositivePattern Define la posición del símbolo de divisa para los valores


positivos.

CurrencyNegativePattern Define la posición del símbolo de divisa para los valores


negativos y especifica si el signo negativo está representado
por paréntesis o por la propiedad NegativeSign.

NegativeSign Define el signo negativo usado si CurrencyNegativePattern


indica que no se emplean paréntesis.

CurrencySymbol Define el símbolo de divisa.

CurrencyDecimalDigits Define el número predeterminado de dígitos decimales en un


valor de divisa. Este valor puede reemplazarse por el uso del
especificador de precisión.

CurrencyDecimalSeparator Define la cadena que separa los dígitos integrales y


decimales.

CurrencyGroupSeparator Define la cadena que separa los grupos de números


integrales.
PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

CurrencyGroupSizes Define el número de dígitos enteros que aparecen en un


grupo.

En el ejemplo siguiente se da formato a un valor Double con el especificador de formato de divisa:

double value = 12345.6789;


Console::WriteLine(value.ToString("C", CultureInfo::CurrentCulture));

Console::WriteLine(value.ToString("C3", CultureInfo::CurrentCulture));

Console::WriteLine(value.ToString("C3",
CultureInfo::CreateSpecificCulture("da-DK")));
// The example displays the following output on a system whose
// current culture is English (United States):
// $12,345.68
// $12,345.679
// kr 12.345,679

double value = 12345.6789;


Console.WriteLine(value.ToString("C", CultureInfo.CurrentCulture));

Console.WriteLine(value.ToString("C3", CultureInfo.CurrentCulture));

Console.WriteLine(value.ToString("C3",
CultureInfo.CreateSpecificCulture("da-DK")));
// The example displays the following output on a system whose
// current culture is English (United States):
// $12,345.68
// $12,345.679
// 12.345,679 kr

Dim value As Double = 12345.6789


Console.WriteLine(value.ToString("C", CultureInfo.CurrentCulture))

Console.WriteLine(value.ToString("C3", CultureInfo.CurrentCulture))

Console.WriteLine(value.ToString("C3", _
CultureInfo.CreateSpecificCulture("da-DK")))
' The example displays the following output on a system whose
' current culture is English (United States):
' $12,345.68
' $12,345.679
' kr 12.345,679

Volver a la tabla

Especificador de formato decimal ("D")


El especificador de formato "D" (o decimal) convierte un número en una cadena de dígitos decimales (0-9),
precedida por un signo menos si el número es negativo. Este formato sólo es compatible con los tipos enteros.
El especificador de precisión indica el número mínimo de dígitos deseado en la cadena resultante. Si es preciso,
el número se rellena con ceros a la izquierda para generar el número de dígitos que aporta el especificador de
precisión. Si no se indica ningún especificador de precisión, el valor predeterminado es el valor mínimo
necesario para representar el entero sin ceros iniciales.
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. Como se
muestra en la tabla siguiente, una única propiedad afecta al formato de la cadena de resultado.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo.

En el ejemplo siguiente se da formato a un valor Int32 con el especificador de formato decimal.

int value;

value = 12345;
Console::WriteLine(value.ToString("D"));
// Displays 12345
Console::WriteLine(value.ToString("D8"));
// Displays 00012345

value = -12345;
Console::WriteLine(value.ToString("D"));
// Displays -12345
Console::WriteLine(value.ToString("D8"));
// Displays -00012345

int value;

value = 12345;
Console.WriteLine(value.ToString("D"));
// Displays 12345
Console.WriteLine(value.ToString("D8"));
// Displays 00012345

value = -12345;
Console.WriteLine(value.ToString("D"));
// Displays -12345
Console.WriteLine(value.ToString("D8"));
// Displays -00012345

Dim value As Integer

value = 12345
Console.WriteLine(value.ToString("D"))
' Displays 12345
Console.WriteLine(value.ToString("D8"))
' Displays 00012345

value = -12345
Console.WriteLine(value.ToString("D"))
' Displays -12345
Console.WriteLine(value.ToString("D8"))
' Displays -00012345

Volver a la tabla

Especificador de formato exponencial ("E")


El especificador de formato exponencial ("E") convierte un número en una cadena con el formato "-d.ddd…
E+ddd" o "-d.ddd…e+ddd", donde cada "d" indica un dígito (0-9). La cadena comienza con un signo menos si el
número es negativo. El separador decimal siempre va precedido por exactamente un dígito.
El especificador de precisión indica el número deseado de dígitos después del separador decimal. Si se omite el
especificador de precisión, se emplea uno predeterminado que tiene seis dígitos después del separador decimal.
El modelo de mayúsculas o minúsculas del especificador de formato indica si se debe prefijar el exponente con
una "E" o con una "e". El exponente siempre consta de un signo más o menos y de un mínimo de tres dígitos. El
exponente se rellena con ceros para adaptarlo a este mínimo, si es necesario.
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. En la tabla
siguiente se enumeran las propiedades de NumberFormatInfo que controlan el formato de la cadena devuelta.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo


tanto para el coeficiente como para el exponente.

NumberDecimalSeparator Define la cadena que separa el dígito integral de los dígitos


decimales en el coeficiente.

PositiveSign Define la cadena que indica que un exponente es positivo.

En el ejemplo siguiente se da formato a un valor Double con el especificador de formato exponencial:

double value = 12345.6789;


Console::WriteLine(value.ToString("E", CultureInfo::InvariantCulture));
// Displays 1.234568E+004

Console::WriteLine(value.ToString("E10", CultureInfo::InvariantCulture));
// Displays 1.2345678900E+004

Console::WriteLine(value.ToString("e4", CultureInfo::InvariantCulture));
// Displays 1.2346e+004

Console::WriteLine(value.ToString("E",
CultureInfo::CreateSpecificCulture("fr-FR")));
// Displays 1,234568E+004

double value = 12345.6789;


Console.WriteLine(value.ToString("E", CultureInfo.InvariantCulture));
// Displays 1.234568E+004

Console.WriteLine(value.ToString("E10", CultureInfo.InvariantCulture));
// Displays 1.2345678900E+004

Console.WriteLine(value.ToString("e4", CultureInfo.InvariantCulture));
// Displays 1.2346e+004

Console.WriteLine(value.ToString("E",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 1,234568E+004
Dim value As Double = 12345.6789
Console.WriteLine(value.ToString("E", CultureInfo.InvariantCulture))
' Displays 1.234568E+004

Console.WriteLine(value.ToString("E10", CultureInfo.InvariantCulture))
' Displays 1.2345678900E+004

Console.WriteLine(value.ToString("e4", CultureInfo.InvariantCulture))
' Displays 1.2346e+004

Console.WriteLine(value.ToString("E", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 1,234568E+004

Volver a la tabla

Especificador de formato de punto fijo ("F")


El especificador de formato de punto fijo ("F") convierte un número en una cadena con el formato "-ddd.ddd…",
donde cada "d" indica un dígito (0-9). La cadena comienza con un signo menos si el número es negativo.
El especificador de precisión indica el número deseado de cifras decimales. Si se omite el especificador de
precisión, la propiedad NumberFormatInfo.NumberDecimalDigits actual proporciona la precisión numérica.
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. En la tabla
siguiente se enumeran las propiedades del objeto NumberFormatInfo que controlan el formato de la cadena de
resultado.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo.

NumberDecimalSeparator Define la cadena que separa los dígitos integrales de los


decimales.

NumberDecimalDigits Define el número predeterminado de dígitos decimales. Este


valor puede reemplazarse por el uso del especificador de
precisión.

En el ejemplo siguiente se da formato a un valor Double e Int32 con el especificador de formato de punto fijo:
int integerNumber;
integerNumber = 17843;
Console::WriteLine(integerNumber.ToString("F",
CultureInfo::InvariantCulture));
// Displays 17843.00

integerNumber = -29541;
Console::WriteLine(integerNumber.ToString("F3",
CultureInfo::InvariantCulture));
// Displays -29541.000

double doubleNumber;
doubleNumber = 18934.1879;
Console::WriteLine(doubleNumber.ToString("F", CultureInfo::InvariantCulture));
// Displays 18934.19

Console::WriteLine(doubleNumber.ToString("F0", CultureInfo::InvariantCulture));
// Displays 18934

doubleNumber = -1898300.1987;
Console::WriteLine(doubleNumber.ToString("F1", CultureInfo::InvariantCulture));
// Displays -1898300.2

Console::WriteLine(doubleNumber.ToString("F3",
CultureInfo::CreateSpecificCulture("es-ES")));
// Displays -1898300,199

int integerNumber;
integerNumber = 17843;
Console.WriteLine(integerNumber.ToString("F",
CultureInfo.InvariantCulture));
// Displays 17843.00

integerNumber = -29541;
Console.WriteLine(integerNumber.ToString("F3",
CultureInfo.InvariantCulture));
// Displays -29541.000

double doubleNumber;
doubleNumber = 18934.1879;
Console.WriteLine(doubleNumber.ToString("F", CultureInfo.InvariantCulture));
// Displays 18934.19

Console.WriteLine(doubleNumber.ToString("F0", CultureInfo.InvariantCulture));
// Displays 18934

doubleNumber = -1898300.1987;
Console.WriteLine(doubleNumber.ToString("F1", CultureInfo.InvariantCulture));
// Displays -1898300.2

Console.WriteLine(doubleNumber.ToString("F3",
CultureInfo.CreateSpecificCulture("es-ES")));
// Displays -1898300,199
Dim integerNumber As Integer
integerNumber = 17843
Console.WriteLine(integerNumber.ToString("F", CultureInfo.InvariantCulture))
' Displays 17843.00

integerNumber = -29541
Console.WriteLine(integerNumber.ToString("F3", CultureInfo.InvariantCulture))
' Displays -29541.000

Dim doubleNumber As Double


doubleNumber = 18934.1879
Console.WriteLine(doubleNumber.ToString("F", CultureInfo.InvariantCulture))
' Displays 18934.19

Console.WriteLine(doubleNumber.ToString("F0", CultureInfo.InvariantCulture))
' Displays 18934

doubleNumber = -1898300.1987
Console.WriteLine(doubleNumber.ToString("F1", CultureInfo.InvariantCulture))
' Displays -1898300.2

Console.WriteLine(doubleNumber.ToString("F3", _
CultureInfo.CreateSpecificCulture("es-ES")))
' Displays -1898300,199

Volver a la tabla

Especificador de formato general ("G")


El especificador de formato general ("G") convierte un número a la notación de punto fijo o científica más
compacta, dependiendo del tipo del número y de si hay un especificador de precisión o no. El especificador de
precisión define el número máximo de dígitos significativos que pueden aparecer en la cadena de resultado. Si el
especificador de precisión se omite o es cero, el tipo del número determina la precisión predeterminada, como
se indica en la tabla siguiente.

TIPO NUMÉRICO PRECISIÓN PREDETERMINADA

Byte o SByte 3 dígitos

Int16 o UInt16 5 dígitos

Int32 o UInt32 10 dígitos

Int64 19 dígitos

UInt64 20 dígitos

BigInteger Sin límite (igual que "R")

Single 7 dígitos

Double 15 dígitos

Decimal 29 dígitos

La notación de punto fijo se utiliza si el exponente que resultaría de la expresión del número en notación
científica es mayor que -5 y menor que el especificador de precisión, de lo contrario se utiliza la notación
científica. El resultado contiene un separador decimal si es necesario y se omiten los ceros finales después de ese
separador. Si el especificador de precisión está presente y el número de dígitos significativos del resultado
supera la precisión especificada, los dígitos finales sobrantes se quitan mediante redondeo.
Sin embargo, si el número es Decimal y se omite el especificador de precisión, siempre se usa la notación de
punto fijo y se conservan los ceros finales.
Si se usa la notación científica, el exponente del resultado lleva el prefijo "E" si el especificador de formato es "G",
o "e" si el especificador de formato es "g". El exponente contiene un mínimo de dos dígitos. Esto difiere del
formato para la notación científica que genera el especificador de formato exponencial, que incluye un mínimo
de tres dígitos en el exponente.
Tenga en cuenta que, cuando se usa con un valor Double, el especificador de formato "G17" garantiza que el
valor Double original realice un recorrido de ida y vuelta correctamente. Esto se debe a que Double es un
número de punto flotante de doble precisión compatible con IEEE 754-2008 ( binary64 ) que ofrece un máximo
de 17 dígitos de precisión significativos. Se recomienda su uso en lugar del especificador de formato "R", ya que,
en algunos casos, "R" no logra realizar un recorrido de ida y vuelta correcto por los valores de números de punto
flotante de doble precisión. Esto se ilustra en el siguiente ejemplo.

double original = 0.84551240822557006;


var rSpecifier = original.ToString("R");
var g17Specifier = original.ToString("G17");

var rValue = Double.Parse(rSpecifier);


var g17Value = Double.Parse(g17Specifier);

Console.WriteLine($"{original:G17} = {rSpecifier} (R): {original.Equals(rValue)}");


Console.WriteLine($"{original:G17} = {g17Specifier} (G17): {original.Equals(g17Value)}");
// The example displays the following output:
// 0.84551240822557006 = 0.84551240822557: False
// 0.84551240822557006 = 0.84551240822557006: True

Module Example
Public Sub Main()
Dim original As Double = 0.84551240822557006
Dim rSpecifier = original.ToString("R")
Dim g17Specifier = original.ToString("G17")

Dim rValue = Double.Parse(rSpecifier)


Dim g17Value = Double.Parse(g17Specifier)

Console.WriteLine($"{original:G17} = {rSpecifier} (R): {original.Equals(rValue)}")


Console.WriteLine($"{original:G17} = {g17Specifier} (G17): {original.Equals(g17Value)}")
End Sub
End Module
' The example displays the following output:
' 0.84551240822557006 = 0.84551240822557 (R): False
' 0.84551240822557006 = 0.84551240822557006 (G17): True

Cuando se usa con un valor Single, el especificador de formato "G9" garantiza que el valor Single original realice
un recorrido de ida y vuelta correctamente. Esto se debe a que Single es un número de punto flotante de
precisión sencilla compatible con IEEE 754-2008 ( binary32 ) que ofrece hasta nueve dígitos de precisión
significativos. Por motivos de rendimiento, se recomienda su uso en lugar del especificador de formato "R".
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. En la tabla
siguiente se enumeran las propiedades de NumberFormatInfo que controlan el formato de la cadena de
resultado.
PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo.

NumberDecimalSeparator Define la cadena que separa los dígitos integrales de los


decimales.

PositiveSign Define la cadena que indica que un exponente es positivo.

En el ejemplo siguiente se da formato a valores de punto flotante ordenados con el especificador de formato
general:

double number;

number = 12345.6789;
Console::WriteLine(number.ToString("G", CultureInfo::InvariantCulture));
// Displays 12345.6789
Console::WriteLine(number.ToString("G",
CultureInfo::CreateSpecificCulture("fr-FR")));
// Displays 12345,6789

Console::WriteLine(number.ToString("G7", CultureInfo::InvariantCulture));
// Displays 12345.68

number = .0000023;
Console::WriteLine(number.ToString("G", CultureInfo::InvariantCulture));
// Displays 2.3E-06
Console::WriteLine(number.ToString("G",
CultureInfo::CreateSpecificCulture("fr-FR")));
// Displays 2,3E-06

number = .0023;
Console::WriteLine(number.ToString("G", CultureInfo::InvariantCulture));
// Displays 0.0023

number = 1234;
Console::WriteLine(number.ToString("G2", CultureInfo::InvariantCulture));
// Displays 1.2E+03

number = Math::PI;
Console::WriteLine(number.ToString("G5", CultureInfo::InvariantCulture));
// Displays 3.1416
double number;

number = 12345.6789;
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture));
// Displays 12345.6789
Console.WriteLine(number.ToString("G",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 12345,6789

Console.WriteLine(number.ToString("G7", CultureInfo.InvariantCulture));
// Displays 12345.68

number = .0000023;
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture));
// Displays 2.3E-06
Console.WriteLine(number.ToString("G",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 2,3E-06

number = .0023;
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture));
// Displays 0.0023

number = 1234;
Console.WriteLine(number.ToString("G2", CultureInfo.InvariantCulture));
// Displays 1.2E+03

number = Math.PI;
Console.WriteLine(number.ToString("G5", CultureInfo.InvariantCulture));
// Displays 3.1416

Dim number As Double

number = 12345.6789
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture))
' Displays 12345.6789
Console.WriteLine(number.ToString("G", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 12345,6789

Console.WriteLine(number.ToString("G7", CultureInfo.InvariantCulture))
' Displays 12345.68

number = .0000023
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture))
' Displays 2.3E-06
Console.WriteLine(number.ToString("G", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 2,3E-06

number = .0023
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture))
' Displays 0.0023

number = 1234
Console.WriteLine(number.ToString("G2", CultureInfo.InvariantCulture))
' Displays 1.2E+03

number = Math.Pi
Console.WriteLine(number.ToString("G5", CultureInfo.InvariantCulture))
' Displays 3.1416

Volver a la tabla
Especificador de formato numérico ("N")
El especificador de formato numérico ("N") convierte un número en una cadena con el formato "-
d,ddd,ddd.ddd…", donde "-" indica el símbolo de número negativo, si es necesario; "d", representa cada dígito (0-
9); "," es el separador de grupo; y "." es el símbolo de punto decimal. El especificador de precisión indica el
número deseado de dígitos después del separador decimal. Si se omite el especificador de precisión, el número
de posiciones decimales está definido por la propiedad NumberFormatInfo.NumberDecimalDigits actual.
La información de formato del objeto NumberFormatInfo actual afecta a la cadena de resultado. En la tabla
siguiente se enumeran las propiedades de NumberFormatInfo que controlan el formato de la cadena de
resultado.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo.

NumberNegativePattern Define el formato de los valores negativos y especifica si el


signo negativo se representa mediante paréntesis o por la
propiedad NegativeSign.

NumberGroupSizes Define el número de dígitos enteros que aparecen entre los


separadores de grupos.

NumberGroupSeparator Define la cadena que separa los grupos de números


integrales.

NumberDecimalSeparator Define la cadena que separa los dígitos integrales y


decimales.

NumberDecimalDigits Define el número predeterminado de dígitos decimales. Este


valor puede reemplazarse por el uso de un especificador de
precisión.

En el ejemplo siguiente se da formato a valores de punto flotante ordenados con el especificador de formato
numérico:

double dblValue = -12445.6789;


Console::WriteLine(dblValue.ToString("N", CultureInfo::InvariantCulture));
// Displays -12,445.68
Console::WriteLine(dblValue.ToString("N1",
CultureInfo::CreateSpecificCulture("sv-SE")));
// Displays -12 445,7

int intValue = 123456789;


Console::WriteLine(intValue.ToString("N1", CultureInfo::InvariantCulture));
// Displays 123,456,789.0

double dblValue = -12445.6789;


Console.WriteLine(dblValue.ToString("N", CultureInfo.InvariantCulture));
// Displays -12,445.68
Console.WriteLine(dblValue.ToString("N1",
CultureInfo.CreateSpecificCulture("sv-SE")));
// Displays -12 445,7

int intValue = 123456789;


Console.WriteLine(intValue.ToString("N1", CultureInfo.InvariantCulture));
// Displays 123,456,789.0
Dim dblValue As Double = -12445.6789
Console.WriteLine(dblValue.ToString("N", CultureInfo.InvariantCulture))
' Displays -12,445.68
Console.WriteLine(dblValue.ToString("N1", _
CultureInfo.CreateSpecificCulture("sv-SE")))
' Displays -12 445,7

Dim intValue As Integer = 123456789


Console.WriteLine(intValue.ToString("N1", CultureInfo.InvariantCulture))
' Displays 123,456,789.0

Volver a la tabla

Especificador de formato de porcentaje ("P")


El especificador de formato de porcentaje ("P") multiplica un número por 100 y lo convierte en una cadena que
representa un porcentaje. El especificador de precisión indica el número deseado de cifras decimales. Si se omite
el especificador de precisión, se usará la precisión numérica predeterminada proporcionada por la propiedad
PercentDecimalDigits actual.
En la tabla siguiente se enumeran las propiedades de NumberFormatInfo que controlan el formato de la cadena
devuelta.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

PercentPositivePattern Define la posición del símbolo de porcentaje para los valores


positivos.

PercentNegativePattern Define la posición del símbolo de porcentaje y del símbolo


negativo para los valores negativos.

NegativeSign Define la cadena que indica que un número es negativo.

PercentSymbol Define el símbolo de porcentaje.

PercentDecimalDigits Define el número predeterminado de dígitos decimales en un


valor de porcentaje. Este valor puede reemplazarse por el uso
del especificador de precisión.

PercentDecimalSeparator Define la cadena que separa los dígitos integrales y


decimales.

PercentGroupSeparator Define la cadena que separa los grupos de números


integrales.

PercentGroupSizes Define el número de dígitos enteros que aparecen en un


grupo.

En el ejemplo siguiente se da formato a valores de punto flotante con el especificador de formato de porcentaje:
double number = .2468013;
Console::WriteLine(number.ToString("P", CultureInfo::InvariantCulture));
// Displays 24.68 %
Console::WriteLine(number.ToString("P",
CultureInfo::CreateSpecificCulture("hr-HR")));
// Displays 24,68%
Console::WriteLine(number.ToString("P1", CultureInfo::InvariantCulture));
// Displays 24.7 %

double number = .2468013;


Console.WriteLine(number.ToString("P", CultureInfo.InvariantCulture));
// Displays 24.68 %
Console.WriteLine(number.ToString("P",
CultureInfo.CreateSpecificCulture("hr-HR")));
// Displays 24,68%
Console.WriteLine(number.ToString("P1", CultureInfo.InvariantCulture));
// Displays 24.7 %

Dim number As Double = .2468013


Console.WriteLine(number.ToString("P", CultureInfo.InvariantCulture))
' Displays 24.68 %
Console.WriteLine(number.ToString("P", _
CultureInfo.CreateSpecificCulture("hr-HR")))
' Displays 24,68%
Console.WriteLine(number.ToString("P1", CultureInfo.InvariantCulture))
' Displays 24.7 %

Volver a la tabla

Especificador de formato de operación de ida y vuelta ("R")


El especificador de formato de operación de ida y vuelta ("R") intenta garantizar que un valor numérico que se
convierte en una cadena vuelva a tomar el mismo valor numérico. Este formato solo es compatible para los tipos
Single, Double y BigInteger.
Para los valores Double, el especificador de formato "R", en algunos casos, no logra realizar un recorrido de ida y
vuelta correcto por el valor original. Para los dos valores Double y Single, también ofrece un rendimiento
relativamente bajo. En su lugar, se recomienda usar el especificador de formato "G17" para los valores Double y
el especificador de formato "G9" para realizar un recorrido de ida y vuelta correcto por los valores Single.
Cuando se da formato a un valor BigInteger mediante este especificador, su representación de cadena contiene
todos los dígitos significativos del valor BigInteger.
Aunque puede incluir un especificador de precisión, se omite. Los especificadores de ida y vuelta tienen
prioridad sobre la precisión al utilizar este especificador. La información de formato del objeto
NumberFormatInfo actual afecta a la cadena de resultado. En la tabla siguiente se enumeran las propiedades de
NumberFormatInfo que controlan el formato de la cadena de resultado.

PROPIEDAD DE NUMBERFORMATINFO DESCRIPCIÓN

NegativeSign Define la cadena que indica que un número es negativo.

NumberDecimalSeparator Define la cadena que separa los dígitos integrales de los


decimales.

PositiveSign Define la cadena que indica que un exponente es positivo.


En el ejemplo siguiente se da formato a un valor BigInteger con el especificador de formato de ida y vuelta.

#using <System.Numerics.dll>

using namespace System;


using namespace System::Numerics;

void main()
{
BigInteger value = BigInteger::Pow(Int64::MaxValue, 2);
Console::WriteLine(value.ToString("R"));
}
// The example displays the following output:
// 85070591730234615847396907784232501249

using System;
using System.Numerics;

public class Example


{
public static void Main()
{
var value = BigInteger.Pow(Int64.MaxValue, 2);
Console.WriteLine(value.ToString("R"));
}
}
// The example displays the following output:
// 85070591730234615847396907784232501249

Imports System.Numerics

Module Example
Public Sub Main()
Dim value = BigInteger.Pow(Int64.MaxValue, 2)
Console.WriteLine(value.ToString("R"))
End Sub
End Module
' The example displays the following output:
' 85070591730234615847396907784232501249

IMPORTANT
En algunos casos, los valores Double con el formato de cadena numérica estándar "R" no realizan correctamente la
operación de ida y vuelta si se compilan usando los modificadores /platform:x64 o /platform:anycpu y se ejecutan
en sistemas de 64 bits. Para más información, consulte el siguiente párrafo.

Para solucionar el problema de los valores Double con formato de cadena numérico estándar “R” que no hacen
correctamente el viaje de ida y vuelta si se compilan con conmutadores /platform:x64 o /platform:anycpu y se
ejecutan en sistemas de 64 bits, puede dar formato a los valores Double usando la cadena de formato numérico
estándar “G17”. En el ejemplo siguiente se usa la cadena de formato "R" con un valor Double que no realiza
correctamente la operación de ida y vuelta, y usa también la cadena de formato "G17" para realizar
correctamente la operación de ida y vuelta del valor original:
Console.WriteLine("Attempting to round-trip a Double with 'R':");
double initialValue = 0.6822871999174;
string valueString = initialValue.ToString("R",
CultureInfo.InvariantCulture);
double roundTripped = double.Parse(valueString,
CultureInfo.InvariantCulture);
Console.WriteLine("{0:R} = {1:R}: {2}\n",
initialValue, roundTripped, initialValue.Equals(roundTripped));

Console.WriteLine("Attempting to round-trip a Double with 'G17':");


string valueString17 = initialValue.ToString("G17",
CultureInfo.InvariantCulture);
double roundTripped17 = double.Parse(valueString17,
CultureInfo.InvariantCulture);
Console.WriteLine("{0:R} = {1:R}: {2}\n",
initialValue, roundTripped17, initialValue.Equals(roundTripped17));
// If compiled to an application that targets anycpu or x64 and run on an x64 system,
// the example displays the following output:
// Attempting to round-trip a Double with 'R':
// 0.6822871999174 = 0.68228719991740006: False
//
// Attempting to round-trip a Double with 'G17':
// 0.6822871999174 = 0.6822871999174: True

Imports System.Globalization

Module Example
Public Sub Main()
Console.WriteLine("Attempting to round-trip a Double with 'R':")
Dim initialValue As Double = 0.6822871999174
Dim valueString As String = initialValue.ToString("R",
CultureInfo.InvariantCulture)
Dim roundTripped As Double = Double.Parse(valueString,
CultureInfo.InvariantCulture)
Console.WriteLine("{0:R} = {1:R}: {2}",
initialValue, roundTripped, initialValue.Equals(roundTripped))
Console.WriteLine()

Console.WriteLine("Attempting to round-trip a Double with 'G17':")


Dim valueString17 As String = initialValue.ToString("G17",
CultureInfo.InvariantCulture)
Dim roundTripped17 As Double = double.Parse(valueString17,
CultureInfo.InvariantCulture)
Console.WriteLine("{0:R} = {1:R}: {2}",
initialValue, roundTripped17, initialValue.Equals(roundTripped17))
End Sub
End Module
' If compiled to an application that targets anycpu or x64 and run on an x64 system,
' the example displays the following output:
' Attempting to round-trip a Double with 'R':
' 0.6822871999174 = 0.68228719991740006: False
'
' Attempting to round-trip a Double with 'G17':
' 0.6822871999174 = 0.6822871999174: True

Volver a la tabla

Especificador de formato hexadecimal ("X")


El especificador de formato hexadecimal ("X") convierte un número en una cadena de dígitos hexadecimales. El
modelo de mayúsculas y minúsculas del especificador de formato indica si se van a usar caracteres en
mayúsculas o en minúsculas para los dígitos hexadecimales mayores de 9. Por ejemplo, use "X" para generar
"ABCDEF" y "x" para generar "abcdef". Este formato sólo es compatible con los tipos enteros.
El especificador de precisión indica el número mínimo de dígitos deseado en la cadena resultante. Si es preciso,
el número se rellena con ceros a la izquierda para generar el número de dígitos que aporta el especificador de
precisión.
La información de formato del objeto NumberFormatInfo actual no afecta a la cadena de resultado.
En el ejemplo siguiente se da formato a valores Int32 con el especificador de formato hexadecimal.

int value;

value = 0x2045e;
Console::WriteLine(value.ToString("x"));
// Displays 2045e
Console::WriteLine(value.ToString("X"));
// Displays 2045E
Console::WriteLine(value.ToString("X8"));
// Displays 0002045E

value = 123456789;
Console::WriteLine(value.ToString("X"));
// Displays 75BCD15
Console::WriteLine(value.ToString("X2"));
// Displays 75BCD15

int value;

value = 0x2045e;
Console.WriteLine(value.ToString("x"));
// Displays 2045e
Console.WriteLine(value.ToString("X"));
// Displays 2045E
Console.WriteLine(value.ToString("X8"));
// Displays 0002045E

value = 123456789;
Console.WriteLine(value.ToString("X"));
// Displays 75BCD15
Console.WriteLine(value.ToString("X2"));
// Displays 75BCD15

Dim value As Integer

value = &h2045e
Console.WriteLine(value.ToString("x"))
' Displays 2045e
Console.WriteLine(value.ToString("X"))
' Displays 2045E
Console.WriteLine(value.ToString("X8"))
' Displays 0002045E

value = 123456789
Console.WriteLine(value.ToString("X"))
' Displays 75BCD15
Console.WriteLine(value.ToString("X2"))
' Displays 75BCD15

Volver a la tabla

Notas
Configuración del Panel de control
Los valores de configuración del elemento Configuración regional y de idioma del Panel de control influyen
en la cadena de resultado generada por una operación de formato. Esas configuraciones se usan para inicializar
el objeto NumberFormatInfo asociado a la referencia cultural del subproceso actual, que proporciona valores
que se usan para controlar el formato. Los equipos que usan configuraciones diferentes generarán cadenas de
resultado distintas.
Asimismo, si se utiliza el constructor CultureInfo.CultureInfo(String) para crear instancias de un nuevo objeto
CultureInfo que representa la misma referencia cultural que la referencia cultural del sistema actual, cualquier
personalización establecida por el elemento Configuración regional y de idioma del Panel de control se
aplicará al nuevo objeto CultureInfo. Puede usar el constructor CultureInfo.CultureInfo(String, Boolean) para
crear un objeto CultureInfo que no refleje las personalizaciones de un sistema.
Propiedades NumberFormatInfo
El formato se ve influenciado por las propiedades del objeto NumberFormatInfo actual, proporcionado
implícitamente por la referencia cultural del subproceso actual o explícitamente por el parámetro
IFormatProvider del método que invoca el formato. Especifique un objeto NumberFormatInfo o CultureInfo
para dicho parámetro.

NOTE
Para obtener información sobre la personalización de patrones o cadenas que se usan para dar formato a valores
numéricos, vea el tema de la clase NumberFormatInfo.

Tipos numéricos enteros y de punto flotante


Algunas descripciones de especificadores de formato numérico estándar hacen referencia a tipos numéricos
enteros o de punto flotante. Los tipos numéricos integrales son Byte, SByte, Int16, Int32, Int64, UInt16, UInt32,
UInt64 y BigInteger. Los tipos numéricos de punto flotante son Decimal, Single y Double.
Infinitos de punto flotante y NaN
Independientemente de la cadena de formato, si el valor de un tipo de punto flotante Single o Double es infinito
positivo, infinito negativo o NaN (Not a Number, no es un número), la cadena con formato será el valor de la
propiedad PositiveInfinitySymbol, NegativeInfinitySymbol o NaNSymbol respectiva especificada por el objeto
NumberFormatInfo aplicable actualmente.

Ejemplo
NOTE
Algunos de los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET.
Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código,
puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la
ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes
de error del compilador de C#.

En el ejemplo siguiente se da formato a un valor numérico integral y de punto flotante mediante la referencia
cultural en-US y todos los especificadores de formato numérico estándar. En este ejemplo se usan dos tipos
numéricos concretos (Double y Int32), pero se obtendrían resultados similares con cualquiera de los demás
tipos base numéricos (Byte, SByte, Int16, Int32, Int64, UInt16, UInt32, UInt64, BigInteger, Decimal y Single).
// Display string representations of numbers for en-us culture
CultureInfo ci = new CultureInfo("en-us");

// Output floating point values


double floating = 10761.937554;
Console.WriteLine("C: {0}",
floating.ToString("C", ci)); // Displays "C: $10,761.94"
Console.WriteLine("E: {0}",
floating.ToString("E03", ci)); // Displays "E: 1.076E+004"
Console.WriteLine("F: {0}",
floating.ToString("F04", ci)); // Displays "F: 10761.9376"
Console.WriteLine("G: {0}",
floating.ToString("G", ci)); // Displays "G: 10761.937554"
Console.WriteLine("N: {0}",
floating.ToString("N03", ci)); // Displays "N: 10,761.938"
Console.WriteLine("P: {0}",
(floating/10000).ToString("P02", ci)); // Displays "P: 107.62 %"
Console.WriteLine("R: {0}",
floating.ToString("R", ci)); // Displays "R: 10761.937554"
Console.WriteLine();

// Output integral values


int integral = 8395;
Console.WriteLine("C: {0}",
integral.ToString("C", ci)); // Displays "C: $8,395.00"
Console.WriteLine("D: {0}",
integral.ToString("D6", ci)); // Displays "D: 008395"
Console.WriteLine("E: {0}",
integral.ToString("E03", ci)); // Displays "E: 8.395E+003"
Console.WriteLine("F: {0}",
integral.ToString("F01", ci)); // Displays "F: 8395.0"
Console.WriteLine("G: {0}",
integral.ToString("G", ci)); // Displays "G: 8395"
Console.WriteLine("N: {0}",
integral.ToString("N01", ci)); // Displays "N: 8,395.0"
Console.WriteLine("P: {0}",
(integral/10000.0).ToString("P02", ci)); // Displays "P: 83.95 %"
Console.WriteLine("X: 0x{0}",
integral.ToString("X", ci)); // Displays "X: 0x20CB"
Console.WriteLine();
Option Strict On

Imports System.Globalization
Imports System.Threading

Module NumericFormats
Public Sub Main()
' Display string representations of numbers for en-us culture
Dim ci As New CultureInfo("en-us")

' Output floating point values


Dim floating As Double = 10761.937554
Console.WriteLine("C: {0}", _
floating.ToString("C", ci)) ' Displays "C: $10,761.94"
Console.WriteLine("E: {0}", _
floating.ToString("E03", ci)) ' Displays "E: 1.076E+004"
Console.WriteLine("F: {0}", _
floating.ToString("F04", ci)) ' Displays "F: 10761.9376"
Console.WriteLine("G: {0}", _
floating.ToString("G", ci)) ' Displays "G: 10761.937554"
Console.WriteLine("N: {0}", _
floating.ToString("N03", ci)) ' Displays "N: 10,761.938"
Console.WriteLine("P: {0}", _
(floating/10000).ToString("P02", ci)) ' Displays "P: 107.62 %"
Console.WriteLine("R: {0}", _
floating.ToString("R", ci)) ' Displays "R: 10761.937554"
Console.WriteLine()

' Output integral values


Dim integral As Integer = 8395
Console.WriteLine("C: {0}", _
integral.ToString("C", ci)) ' Displays "C: $8,395.00"
Console.WriteLine("D: {0}", _
integral.ToString("D6")) ' Displays "D: 008395"
Console.WriteLine("E: {0}", _
integral.ToString("E03", ci)) ' Displays "E: 8.395E+003"
Console.WriteLine("F: {0}", _
integral.ToString("F01", ci)) ' Displays "F: 8395.0"
Console.WriteLine("G: {0}", _
integral.ToString("G", ci)) ' Displays "G: 8395"
Console.WriteLine("N: {0}", _
integral.ToString("N01", ci)) ' Displays "N: 8,395.0"
Console.WriteLine("P: {0}", _
(integral/10000).ToString("P02", ci)) ' Displays "P: 83.95 %"
Console.WriteLine("X: 0x{0}", _
integral.ToString("X", ci)) ' Displays "X: 0x20CB"
Console.WriteLine()
End Sub
End Module

Vea también
NumberFormatInfo
Custom Numeric Format Strings
Aplicación de formato a tipos
Cómo: Rellenar un número con ceros a la izquierda
Formatos compuestos
Ejemplo: Utilidad de formato WinForms de .NET Core (C#)
Ejemplo: Utilidad de formato WinForms de .NET Core (Visual Basic)
Cadenas con formato numérico personalizado
13/01/2020 • 38 minutes to read • Edit Online

Puede crear una cadena de formato numérico personalizado, formada por uno o varios especificadores
numéricos personalizados, para definir cómo debe darse formato a los datos numéricos. Una cadena de formato
numérico personalizado es cualquier cadena que no sea una cadena de formato numérico estándar.
Algunas sobrecargas del método ToString de todos los tipos numéricos admiten las cadenas de formato
numérico personalizado. Por ejemplo, se puede proporcionar una cadena de formato numérico a los métodos
ToString(String) y ToString(String, IFormatProvider) del tipo Int32 . La característica de formato compuesto de
.NET, que utilizan algunos métodos Write y WriteLine de las clases Console y StreamWriter, el método
String.Format y el método StringBuilder.AppendFormat, admite también cadenas de formato numérico
personalizado. La característica interpolación de cadenas admite también cadenas de formato numérico
personalizado.

TIP
Puede descargar la Utilidad de formato, que es una aplicación de .NET Core Windows Forms que permite aplicar
cadenas de formato a valores numéricos o de fecha y hora, y que muestra la cadena de resultado. El código fuente está
disponible para C# y Visual Basic.

En la tabla siguiente se describen los especificadores de formato numérico personalizado y se muestran las
salidas de ejemplo generadas por cada especificador de formato. Vea la sección Notas para obtener información
adicional sobre cómo usar las cadenas de formato numérico personalizado y la sección Ejemplo para ver una
ilustración completa de su uso.

ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"0" Marcador de posición cero Reemplaza el cero con el 1234.5678 ("00000") ->
dígito correspondiente si 01235
hay alguno presente; de lo
contrario, el cero aparece en 0.45678 ("0.00", en-US) ->
la cadena de resultado. 0.46

Más información: 0.45678 ("0.00", fr-FR) ->


Especificador personalizado 0,46
"0".
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"#" Marcador de posición de Reemplaza el símbolo "#" 1234.5678 ("#####") ->


dígito. por el dígito 1235
correspondiente si hay
alguno presente; de lo 0.45678 ("#.##", en-US) ->
contrario, no aparece .46
ningún dígito en la cadena
de resultado. 0.45678 ("#.##", fr-FR) ->
,46
Tenga en cuenta que no se
mostrará ningún dígito en
la cadena de resultado si el
dígito que se encuentra en
la cadena de entrada es un
0 no significativo. Por
ejemplo, 0003 ("####") ->
3.

Más información:
Especificador personalizado
"#".

"." Separador decimal Determina la ubicación del 0.45678 ("0.00", en-US) ->
separador decimal en la 0.46
cadena de resultado.
0.45678 ("0.00", fr-FR) ->
Más información: El 0,46
especificador personalizado
".".

"," Separador de grupos y Actúa como separador de Especificador de separador


escala numérica grupos y como de grupos:
especificador de escala
numérica. Como separador 2147483647 ("##,#", en-
de grupos, inserta un US) -> 2,147,483,647
carácter separador de
grupos adaptado entre 2147483647 ("##,#", es-ES)
cada grupo. Como -> 2.147.483.647
especificador de escala
numérica, divide un número Especificador de escala:
por 1000 por cada coma
especificada. 2147483647 ("#,#,,", en-US)
-> 2,147
Más información:
Especificador personalizado 2147483647 ("#,#,,", es-ES)
",". -> 2.147

"%" Marcador de posición de Multiplica un número por 0.3697 ("%#0.00", en-US) -


porcentaje. 100 e inserta un símbolo de > %36.97
porcentaje adaptado en la
cadena de resultado. 0.3697 ("%#0.00", el-GR) ->
%36,97
Más información:
Especificador personalizado 0.3697 ("##.0 %", en-US) ->
"%". 37.0 %

0.3697 ("##.0 %", el-GR) ->


37,0 %
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"‰" Marcador de posición de Multiplica un número por 0.03697 ("#0.00‰", en-US)


"por mil" 1000 e inserta un símbolo -> 36.97‰
de "por mil" adaptado en la
cadena de resultado. 0.03697 ("#0.00‰", ru-RU)
-> 36,97‰
Más información:
Especificador personalizado
"‰".

"E0" Notación exponencial Si va seguido al menos de 987654 ("#0.0e0") ->


un 0 (cero), da formato al 98.8e4
"E+0" resultado usando notación
exponencial. El modelo de 1503.92311 ("0.0##e+00")
"E-0" mayúsculas de "E" o "e" -> 1.504e+03
indica el modelo de
"E0" mayúsculas del símbolo de 1.8901385E-16 ("0.0e+00")
exponente en la cadena de -> 1.9e-16
"E+0" resultado. El número de
ceros que siguen al carácter
"E-0" "E" o "e" determina el
número mínimo de dígitos
en el exponente. Un signo
más (+) indica que un
carácter de signo precede
siempre al exponente. Un
signo menos (-) indica que
un carácter de signo solo
precede a los exponentes
negativos.

Más información:
Especificadores
personalizados "E" y "e".

"\" Carácter de escape Hace que el carácter 987654 ("\###00\#") ->


siguiente se interprete #987654#
como un literal en lugar de
como un especificador de
formato personalizado.

Más información: Carácter


de escape "\".

'cadena' Delimitador de cadena Indica que los caracteres 68 ("# ' grados'") -> 68
literal que encierra se deben grados
"string" copiar en la cadena de
resultado sin modificar. 68 ("# ' grados'") -> 68
grados
Más información: Literales
de carácter.
ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

; Separador de secciones Define secciones con 12.345 ("#0.0#;(#0.0#);-\0-


cadenas de formato ") -> 12.35
diferentes para los números
positivos, negativos y cero. 0 ("#0.0#;(#0.0#);-\0-") -> -
0-
Más información: Separador
de sección ";". -12.345 ("#0.0#;(#0.0#);-\0-
") -> (12.35)

12.345 ("#0.0#;(#0.0#)") ->


12.35

0 ("#0.0#;(#0.0#)") -> 0.0

-12.345 ("#0.0#;(#0.0#)") ->


(12.35)

Otros Todos los demás caracteres El carácter se copia en la 68 ("# °") -> 68 °
cadena de resultado sin
modificar.

Más información: Literales


de carácter.

En las secciones siguientes se proporciona información detallada sobre cada uno de los especificadores de
formato numérico personalizado.

NOTE
Algunos de los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET.
Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código,
puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la
ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes
de error del compilador de C#.

Especificador personalizado "0"


El especificador de formato personalizado "0" actúa como un símbolo de marcador de posición cero. Si el valor
al que se está dando formato tiene un dígito en la posición donde aparece el cero en la cadena de formato, se
copia ese dígito a la cadena de resultado; de lo contrario, aparecerá un cero en la cadena de resultado. La
posición del cero que aparece más a la izquierda antes del separador decimal y la del cero que está más a la
derecha después del separador decimal determinan el intervalo de dígitos que están siempre presentes en la
cadena de resultado.
El especificador "00" hace que el valor se redondee al dígito más próximo que precede al decimal, donde
siempre se utiliza el redondeo para evitar el cero. Por ejemplo, al aplicar el formato a 34.5 con "00" el resultado
del valor es 35.
En el ejemplo siguiente se muestran varios valores a los que se les ha aplicado cadenas de formato
personalizado que incluyen marcadores de posición cero.
double value;

value = 123;
Console::WriteLine(value.ToString("00000"));
Console::WriteLine(String::Format("{0:00000}", value));
// Displays 00123

value = 1.2;
Console::WriteLine(value.ToString("0.00", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.00}", value));
// Displays 1.20

Console::WriteLine(value.ToString("00.00", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:00.00}", value));
// Displays 01.20

CultureInfo^ daDK = CultureInfo::CreateSpecificCulture("da-DK");


Console::WriteLine(value.ToString("00.00", daDK));
Console::WriteLine(String::Format(daDK, "{0:00.00}", value));
// Displays 01,20

value = .56;
Console::WriteLine(value.ToString("0.0", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.0}", value));
// Displays 0.6

value = 1234567890;
Console::WriteLine(value.ToString("0,0", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0,0}", value));
// Displays 1,234,567,890

CultureInfo^ elGR = CultureInfo::CreateSpecificCulture("el-GR");


Console::WriteLine(value.ToString("0,0", elGR));
Console::WriteLine(String::Format(elGR, "{0:0,0}", value));
// Displays 1.234.567.890

value = 1234567890.123456;
Console::WriteLine(value.ToString("0,0.0", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0,0.0}", value));
// Displays 1,234,567,890.1

value = 1234.567890;
Console::WriteLine(value.ToString("0,0.00", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0,0.00}", value));
// Displays 1,234.57
double value;

value = 123;
Console.WriteLine(value.ToString("00000"));
Console.WriteLine(String.Format("{0:00000}", value));
// Displays 00123

value = 1.2;
Console.WriteLine(value.ToString("0.00", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.00}", value));
// Displays 1.20

Console.WriteLine(value.ToString("00.00", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:00.00}", value));
// Displays 01.20

CultureInfo daDK = CultureInfo.CreateSpecificCulture("da-DK");


Console.WriteLine(value.ToString("00.00", daDK));
Console.WriteLine(String.Format(daDK, "{0:00.00}", value));
// Displays 01,20

value = .56;
Console.WriteLine(value.ToString("0.0", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.0}", value));
// Displays 0.6

value = 1234567890;
Console.WriteLine(value.ToString("0,0", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0}", value));
// Displays 1,234,567,890

CultureInfo elGR = CultureInfo.CreateSpecificCulture("el-GR");


Console.WriteLine(value.ToString("0,0", elGR));
Console.WriteLine(String.Format(elGR, "{0:0,0}", value));
// Displays 1.234.567.890

value = 1234567890.123456;
Console.WriteLine(value.ToString("0,0.0", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0.0}", value));
// Displays 1,234,567,890.1

value = 1234.567890;
Console.WriteLine(value.ToString("0,0.00", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0.00}", value));
// Displays 1,234.57
Dim value As Double

value = 123
Console.WriteLine(value.ToString("00000"))
Console.WriteLine(String.Format("{0:00000}", value))
' Displays 00123

value = 1.2
Console.Writeline(value.ToString("0.00", CultureInfo.InvariantCulture))
Console.Writeline(String.Format(CultureInfo.InvariantCulture,
"{0:0.00}", value))
' Displays 1.20
Console.WriteLine(value.ToString("00.00", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:00.00}", value))
' Displays 01.20
Dim daDK As CultureInfo = CultureInfo.CreateSpecificCulture("da-DK")
Console.WriteLine(value.ToString("00.00", daDK))
Console.WriteLine(String.Format(daDK, "{0:00.00}", value))
' Displays 01,20

value = .56
Console.WriteLine(value.ToString("0.0", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.0}", value))
' Displays 0.6

value = 1234567890
Console.WriteLine(value.ToString("0,0", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0}", value))
' Displays 1,234,567,890
Dim elGR As CultureInfo = CultureInfo.CreateSpecificCulture("el-GR")
Console.WriteLine(value.ToString("0,0", elGR))
Console.WriteLine(String.Format(elGR, "{0:0,0}", value))
' Displays 1.234.567.890

value = 1234567890.123456
Console.WriteLine(value.ToString("0,0.0", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0.0}", value))
' Displays 1,234,567,890.1

value = 1234.567890
Console.WriteLine(value.ToString("0,0.00", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0,0.00}", value))
' Displays 1,234.57

Volver a la tabla

Especificador personalizado "#"


El especificador de formato personalizado "#" actúa como un símbolo de marcador de posición de dígitos. Si el
valor al que se está dando formato tiene un dígito en la posición donde aparece el símbolo "#" en la cadena de
formato, ese dígito se copia a la cadena de resultado. En caso contrario, no se almacena nada en esa posición de
la cadena de resultado.
Tenga en cuenta que este especificador nunca muestra un cero que no sea un dígito significativo, incluso aunque
el cero sea el único dígito de la cadena. Solo mostrará cero si es un dígito significativo del número que se está
mostrando.
La cadena de formato "##" hace que el valor se redondee al dígito más próximo que precede al decimal, donde
siempre se utiliza el redondeo para evitar el cero. Por ejemplo, al aplicar el formato a 34.5 con "##" el resultado
del valor es 35.
En el ejemplo siguiente se muestran varios valores a los que se les ha aplicado cadenas de formato
personalizado que incluyen marcadores de posición de dígitos.

double value;

value = 1.2;
Console::WriteLine(value.ToString("#.##", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#.##}", value));
// Displays 1.2

value = 123;
Console::WriteLine(value.ToString("#####"));
Console::WriteLine(String::Format("{0:#####}", value));
// Displays 123

value = 123456;
Console::WriteLine(value.ToString("[##-##-##]"));
Console::WriteLine(String::Format("{0:[##-##-##]}", value));
// Displays [12-34-56]

value = 1234567890;
Console::WriteLine(value.ToString("#"));
Console::WriteLine(String::Format("{0:#}", value));
// Displays 1234567890

Console::WriteLine(value.ToString("(###) ###-####"));
Console::WriteLine(String::Format("{0:(###) ###-####}", value));
// Displays (123) 456-7890

double value;

value = 1.2;
Console.WriteLine(value.ToString("#.##", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#.##}", value));
// Displays 1.2

value = 123;
Console.WriteLine(value.ToString("#####"));
Console.WriteLine(String.Format("{0:#####}", value));
// Displays 123

value = 123456;
Console.WriteLine(value.ToString("[##-##-##]"));
Console.WriteLine(String.Format("{0:[##-##-##]}", value));
// Displays [12-34-56]

value = 1234567890;
Console.WriteLine(value.ToString("#"));
Console.WriteLine(String.Format("{0:#}", value));
// Displays 1234567890

Console.WriteLine(value.ToString("(###) ###-####"));
Console.WriteLine(String.Format("{0:(###) ###-####}", value));
// Displays (123) 456-7890
Dim value As Double

value = 1.2
Console.WriteLine(value.ToString("#.##", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#.##}", value))
' Displays 1.2

value = 123
Console.WriteLine(value.ToString("#####"))
Console.WriteLine(String.Format("{0:#####}", value))
' Displays 123

value = 123456
Console.WriteLine(value.ToString("[##-##-##]"))
Console.WriteLine(String.Format("{0:[##-##-##]}", value))
' Displays [12-34-56]

value = 1234567890
Console.WriteLine(value.ToString("#"))
Console.WriteLine(String.Format("{0:#}", value))
' Displays 1234567890

Console.WriteLine(value.ToString("(###) ###-####"))
Console.WriteLine(String.Format("{0:(###) ###-####}", value))
' Displays (123) 456-7890

Para devolver una cadena de resultado en la que los dígitos que faltan o los ceros iniciales se reemplazan por
espacios, use la característica de formato compuesto y especifique un ancho de campo, como se muestra en el
ejemplo siguiente.

using namespace System;

void main()
{
Double value = .324;
Console::WriteLine("The value is: '{0,5:#.###}'", value);
}
// The example displays the following output if the current culture
// is en-US:
// The value is: ' .324'

using System;

public class Example


{
public static void Main()
{
Double value = .324;
Console.WriteLine("The value is: '{0,5:#.###}'", value);
}
}
// The example displays the following output if the current culture
// is en-US:
// The value is: ' .324'
Module Example
Public Sub Main()
Dim value As Double = .324
Console.WriteLine("The value is: '{0,5:#.###}'", value)
End Sub
End Module
' The example displays the following output if the current culture
' is en-US:
' The value is: ' .324'

Volver a la tabla

Especificador personalizado "."


El especificador de formato personalizado "." inserta un separador decimal localizado en la cadena del resultado.
El primer punto de la cadena de formato determina la ubicación del separador decimal en el valor con formato y
se omite cualquier punto adicional.
El carácter que se usa como separador decimal en la cadena de resultado no es siempre un punto; viene
determinado por la propiedad NumberDecimalSeparator del objeto NumberFormatInfo que controla la
aplicación de formato.
En el ejemplo siguiente se utiliza el especificador de formato "." para definir la ubicación del separador decimal
en varias cadenas de resultado.

double value;

value = 1.2;
Console::WriteLine(value.ToString("0.00", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.00}", value));
// Displays 1.20

Console::WriteLine(value.ToString("00.00", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:00.00}", value));
// Displays 01.20

Console::WriteLine(value.ToString("00.00",
CultureInfo::CreateSpecificCulture("da-DK")));
Console::WriteLine(String::Format(CultureInfo::CreateSpecificCulture("da-DK"),
"{0:00.00}", value));
// Displays 01,20

value = .086;
Console::WriteLine(value.ToString("#0.##%", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#0.##%}", value));
// Displays 8.6%

value = 86000;
Console::WriteLine(value.ToString("0.###E+0", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.###E+0}", value));
// Displays 8.6E+4
double value;

value = 1.2;
Console.WriteLine(value.ToString("0.00", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.00}", value));
// Displays 1.20

Console.WriteLine(value.ToString("00.00", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:00.00}", value));
// Displays 01.20

Console.WriteLine(value.ToString("00.00",
CultureInfo.CreateSpecificCulture("da-DK")));
Console.WriteLine(String.Format(CultureInfo.CreateSpecificCulture("da-DK"),
"{0:00.00}", value));
// Displays 01,20

value = .086;
Console.WriteLine(value.ToString("#0.##%", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#0.##%}", value));
// Displays 8.6%

value = 86000;
Console.WriteLine(value.ToString("0.###E+0", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+0}", value));
// Displays 8.6E+4

Dim value As Double

value = 1.2
Console.Writeline(value.ToString("0.00", CultureInfo.InvariantCulture))
Console.Writeline(String.Format(CultureInfo.InvariantCulture,
"{0:0.00}", value))
' Displays 1.20

Console.WriteLine(value.ToString("00.00", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:00.00}", value))
' Displays 01.20

Console.WriteLine(value.ToString("00.00", _
CultureInfo.CreateSpecificCulture("da-DK")))
Console.WriteLine(String.Format(CultureInfo.CreateSpecificCulture("da-DK"),
"{0:00.00}", value))
' Displays 01,20

value = .086
Console.WriteLine(value.ToString("#0.##%", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#0.##%}", value))
' Displays 8.6%

value = 86000
Console.WriteLine(value.ToString("0.###E+0", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+0}", value))
' Displays 8.6E+4

Volver a la tabla
Especificador personalizado ","
El carácter "," actúa como separador de grupos y como especificador de escala numérica.
Separador de grupos: si se especifican una o varias comas dos marcadores de posición de dígitos (0 o #)
que dan formato a los dígitos enteros de un número, se insertará un carácter separador de grupos entre
cada grupo de números en la parte entera de la salida.
Las propiedades NumberGroupSeparator y NumberGroupSizes del objeto NumberFormatInfo actual
determinan el carácter utilizado como separador de grupos de números y el tamaño de cada grupo de
números. Por ejemplo, si se utiliza la cadena "#,#" y la referencia cultural de todos los idiomas para dar
formato al número 1000, el resultado será "1,000".
Especificador de escala numérica: si se especifican una o varias comas inmediatamente a la izquierda del
signo decimal explícito o implícito, el número al que se va a dar formato se divide por 1000 por cada
coma. Por ejemplo, si se utiliza la cadena "0,," para dar formato al número 100 millones, el resultado será
"100".
Puede usar especificadores de separador de grupos y de escala numérica en la misma cadena de formato. Por
ejemplo, si se utiliza la cadena "#,0,," y la referencia cultural de todos los idiomas para dar formato al número
mil millones, el resultado será "1,000".
En el ejemplo siguiente se muestra el uso de la coma como separador de grupos.

double value = 1234567890;


Console::WriteLine(value.ToString("#,#", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#,#}", value));
// Displays 1,234,567,890

Console::WriteLine(value.ToString("#,##0,,", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#,##0,,}", value));
// Displays 1,235

double value = 1234567890;


Console.WriteLine(value.ToString("#,#", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,#}", value));
// Displays 1,234,567,890

Console.WriteLine(value.ToString("#,##0,,", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,##0,,}", value));
// Displays 1,235

Dim value As Double = 1234567890


Console.WriteLine(value.ToString("#,#", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,#}", value))
' Displays 1,234,567,890

Console.WriteLine(value.ToString("#,##0,,", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,##0,,}", value))
' Displays 1,235

En el ejemplo siguiente se muestra el uso de la coma como especificador de escala numérica.


double value = 1234567890;
Console::WriteLine(value.ToString("#,,", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#,,}", value));
// Displays 1235

Console::WriteLine(value.ToString("#,,,", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#,,,}", value));
// Displays 1

Console::WriteLine(value.ToString("#,##0,,", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#,##0,,}", value));
// Displays 1,235

double value = 1234567890;


Console.WriteLine(value.ToString("#,,", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,,}", value));
// Displays 1235

Console.WriteLine(value.ToString("#,,,", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,,,}", value));
// Displays 1

Console.WriteLine(value.ToString("#,##0,,", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,##0,,}", value));
// Displays 1,235

Dim value As Double = 1234567890


Console.WriteLine(value.ToString("#,,", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0:#,,}", value))
' Displays 1235

Console.WriteLine(value.ToString("#,,,", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,,,}", value))
' Displays 1

Console.WriteLine(value.ToString("#,##0,,", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#,##0,,}", value))
' Displays 1,235

Volver a la tabla

Especificador personalizado "%"


Un signo de porcentaje (%) en una cadena de formato hace que se multiplique un número por 100 antes de
darle formato. El símbolo de porcentaje adaptado se inserta en el número en la ubicación donde aparece % en la
cadena de formato. La propiedad PercentSymbol del objeto NumberFormatInfo actual define el carácter de
porcentaje empleado.
En el ejemplo siguiente se definen varias cadenas de formato personalizado que incluyen el especificador
personalizado "%".
double value = .086;
Console::WriteLine(value.ToString("#0.##%", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:#0.##%}", value));
// Displays 8.6%

double value = .086;


Console.WriteLine(value.ToString("#0.##%", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#0.##%}", value));
// Displays 8.6%

Dim value As Double = .086


Console.WriteLine(value.ToString("#0.##%", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:#0.##%}", value))
' Displays 8.6%

Volver a la tabla

Especificador personalizado "‰"


Un carácter de "por mil" (‰ o \u2030) en una cadena de formato hace que un número se multiplique por 1000
antes de darle formato. El símbolo de "por mil" adecuado se inserta en la cadena devuelta, en la ubicación de la
cadena de formato en la que aparece el símbolo ‰. La propiedad NumberFormatInfo.PerMilleSymbol del
objeto que proporciona la información de formato específica de la referencia cultural es la que determina el
carácter de "por mil" que se utiliza.
En el ejemplo siguiente se define una cadena de formato personalizado que incluye el especificador
personalizado "‰".

double value = .00354;


String^ perMilleFmt = "#0.## " + '\u2030';
Console::WriteLine(value.ToString(perMilleFmt, CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:" + perMilleFmt + "}", value));
// Displays 3.54‰

double value = .00354;


string perMilleFmt = "#0.## " + '\u2030';
Console.WriteLine(value.ToString(perMilleFmt, CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:" + perMilleFmt + "}", value));
// Displays 3.54‰

Dim value As Double = .00354


Dim perMilleFmt As String = "#0.## " & ChrW(&h2030)
Console.WriteLine(value.ToString(perMilleFmt, CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:" + perMilleFmt + "}", value))
' Displays 3.54 ‰

Volver a la tabla
Especificadores personalizados "E" y "e"
Si alguna de las cadenas "E", "E+", "E -", "e", "e+", o "e-" está presente en la cadena de formato y va seguida
inmediatamente de al menos un cero, se da formato al número mediante notación científica con una 'E' o una 'e'
insertadas entre el número y el exponente. El número de ceros que hay a continuación del indicador de notación
científica determina el número mínimo de dígitos para el exponente. Los formatos 'E+' y 'e+' indican que un
signo más o un signo menos debe preceder siempre al exponente. Los formatos 'E', 'E -', 'e' o 'e-' indican que un
carácter de signo debe preceder solo a exponentes negativos.
En el ejemplo siguiente se da formato a varios valores numéricos utilizando los especificadores de notación
científica.

double value = 86000;


Console::WriteLine(value.ToString("0.###E+0", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.###E+0}", value));
// Displays 8.6E+4

Console::WriteLine(value.ToString("0.###E+000", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.###E+000}", value));
// Displays 8.6E+004

Console::WriteLine(value.ToString("0.###E-000", CultureInfo::InvariantCulture));
Console::WriteLine(String::Format(CultureInfo::InvariantCulture,
"{0:0.###E-000}", value));
// Displays 8.6E004

double value = 86000;


Console.WriteLine(value.ToString("0.###E+0", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+0}", value));
// Displays 8.6E+4

Console.WriteLine(value.ToString("0.###E+000", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+000}", value));
// Displays 8.6E+004

Console.WriteLine(value.ToString("0.###E-000", CultureInfo.InvariantCulture));
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E-000}", value));
// Displays 8.6E004

Dim value As Double = 86000


Console.WriteLine(value.ToString("0.###E+0", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+0}", value))
' Displays 8.6E+4

Console.WriteLine(value.ToString("0.###E+000", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E+000}", value))
' Displays 8.6E+004

Console.WriteLine(value.ToString("0.###E-000", CultureInfo.InvariantCulture))
Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
"{0:0.###E-000}", value))
' Displays 8.6E004
Volver a la tabla

Carácter de escape "\"


Los símbolos "#", "0", ".", ",", "%" y "‰" en una cadena de formato se interpretan como especificadores de
formato en lugar de como caracteres literales. Dependiendo de su posición en una cadena de formato
personalizado, la "E" en mayúsculas y minúsculas así como los símbolos + y - también se pueden interpretar
como especificadores de formato.
Para evitar que un carácter se interprete como un especificador de formato, puede precederlo con una barra
diagonal inversa, que es el carácter de escape. El carácter de escape significa que el siguiente carácter es un
carácter literal que se debe incluir en la cadena de resultado sin modificar.
Para incluir una barra diagonal inversa en una cadena de resultado, debe indicar su secuencia de escape con
otra barra diagonal inversa ( \\ ).

NOTE
Algunos compiladores, como los compiladores de C# y C++, también pueden interpretar un único carácter de barra
diagonal inversa como un carácter de escape. Para asegurarse de que una cadena se interpreta correctamente al darle
formato, puede usar el carácter literal de cadena textual (el carácter @) antes de la cadena en C# o puede agregar otro
carácter de barra diagonal inversa delante de cada barra diagonal inversa en C# y C++. En el siguiente ejemplo de C# se
muestran ambos enfoques.

En el ejemplo siguiente se usa el carácter de escape para evitar que la operación de formato interprete los
caracteres "#", "0" y "\" como caracteres de escape o especificadores de formato. En el ejemplo de C# se usa una
barra diagonal inversa adicional para asegurarse de que una barra diagonal inversa se interprete como un
carácter literal.

int value = 123;


Console::WriteLine(value.ToString("\\#\\#\\# ##0 dollars and \\0\\0 cents \\#\\#\\#"));
Console::WriteLine(String::Format("{0:\\#\\#\\# ##0 dollars and \\0\\0 cents \\#\\#\\#}",
value));
// Displays ### 123 dollars and 00 cents ###

Console::WriteLine(value.ToString("\\#\\#\\# ##0 dollars and \0\0 cents \\#\\#\\#"));


Console::WriteLine(String::Format("{0:\\#\\#\\# ##0 dollars and \0\0 cents \\#\\#\\#}",
value));
// Displays ### 123 dollars and 00 cents ###

Console::WriteLine(value.ToString("\\\\\\\\\\\\ ##0 dollars and \\0\\0 cents \\\\\\\\\\\\"));


Console::WriteLine(String::Format("{0:\\\\\\\\\\\\ ##0 dollars and \\0\\0 cents \\\\\\\\\\\\}",
value));
// Displays \\\ 123 dollars and 00 cents \\\

Console::WriteLine(value.ToString("\\\\\\ ##0 dollars and \0\0 cents \\\\\\"));


Console::WriteLine(String::Format("{0:\\\\\\ ##0 dollars and \0\0 cents \\\\\\}",
value));
// Displays \\\ 123 dollars and 00 cents \\\
int value = 123;
Console.WriteLine(value.ToString("\\#\\#\\# ##0 dollars and \\0\\0 cents \\#\\#\\#"));
Console.WriteLine(String.Format("{0:\\#\\#\\# ##0 dollars and \\0\\0 cents \\#\\#\\#}",
value));
// Displays ### 123 dollars and 00 cents ###

Console.WriteLine(value.ToString(@"\#\#\# ##0 dollars and \0\0 cents \#\#\#"));


Console.WriteLine(String.Format(@"{0:\#\#\# ##0 dollars and \0\0 cents \#\#\#}",
value));
// Displays ### 123 dollars and 00 cents ###

Console.WriteLine(value.ToString("\\\\\\\\\\\\ ##0 dollars and \\0\\0 cents \\\\\\\\\\\\"));


Console.WriteLine(String.Format("{0:\\\\\\\\\\\\ ##0 dollars and \\0\\0 cents \\\\\\\\\\\\}",
value));
// Displays \\\ 123 dollars and 00 cents \\\

Console.WriteLine(value.ToString(@"\\\\\\ ##0 dollars and \0\0 cents \\\\\\"));


Console.WriteLine(String.Format(@"{0:\\\\\\ ##0 dollars and \0\0 cents \\\\\\}",
value));
// Displays \\\ 123 dollars and 00 cents \\\

Dim value As Integer = 123


Console.WriteLine(value.ToString("\#\#\# ##0 dollars and \0\0 cents \#\#\#"))
Console.WriteLine(String.Format("{0:\#\#\# ##0 dollars and \0\0 cents \#\#\#}",
value))
' Displays ### 123 dollars and 00 cents ###

Console.WriteLine(value.ToString("\\\\\\ ##0 dollars and \0\0 cents \\\\\\"))


Console.WriteLine(String.Format("{0:\\\\\\ ##0 dollars and \0\0 cents \\\\\\}",
value))
' Displays \\\ 123 dollars and 00 cents \\\

Volver a la tabla

Separador de sección ";"


El punto y coma (;) es un especificador de formato condicional que aplica distinto formato a un número
dependiendo de si su valor es positivo, negativo o cero. Para generar este comportamiento, una cadena de
formato personalizado puede contener hasta tres secciones separadas por signos de punto y coma. Estas
secciones se describen en la siguiente tabla.

NÚMERO DE SECCIONES DESCRIPCIÓN

Una sección La cadena de formato se aplica a todos los valores.

Dos secciones La primera sección se aplica a valores positivos y ceros, y la


segunda, sólo a valores negativos.

Si el número al que se va a dar formato es negativo, pero se


convierte en cero después de redondearlo según el formato
de la segunda sección, se da formato al cero resultante
según la primera sección.
NÚMERO DE SECCIONES DESCRIPCIÓN

Tres secciones. La primera sección se aplica a valores positivos y ceros, la


segunda, sólo a valores negativos, y la tercera, a ceros.

La segunda sección se puede dejar vacía (no dejando nada


entre los signos de punto y coma) y, en ese caso, la primera
sección se aplica a los valores distintos de cero.

Si el número al que se va a dar formato es distinto de cero,


pero se convierte en cero después de redondearlo según el
formato de la primera o la segunda sección, se da formato al
cero resultante según la tercera sección.

Los separadores de sección omiten cualquier formato preexistente asociado a un número al dar formato al valor
final. Por ejemplo, los valores negativos se muestran siempre con signo menos cuando se utilizan separadores
de sección. Si se desea que el valor con formato final tenga un signo menos, debe incluir explícitamente el signo
menos como parte del especificador de formato personalizado.
En el ejemplo siguiente se usa el especificador de formato ";" para aplicar un formato diferente a los números
positivos, negativos y cero.

double posValue = 1234;


double negValue = -1234;
double zeroValue = 0;

String^ fmt2 = "##;(##)";


String^ fmt3 = "##;(##);**Zero**";

Console::WriteLine(posValue.ToString(fmt2));
Console::WriteLine(String::Format("{0:" + fmt2 + "}", posValue));
// Displays 1234

Console::WriteLine(negValue.ToString(fmt2));
Console::WriteLine(String::Format("{0:" + fmt2 + "}", negValue));
// Displays (1234)

Console::WriteLine(zeroValue.ToString(fmt3));
Console::WriteLine(String::Format("{0:" + fmt3 + "}", zeroValue));
// Displays **Zero**

double posValue = 1234;


double negValue = -1234;
double zeroValue = 0;

string fmt2 = "##;(##)";


string fmt3 = "##;(##);**Zero**";

Console.WriteLine(posValue.ToString(fmt2));
Console.WriteLine(String.Format("{0:" + fmt2 + "}", posValue));
// Displays 1234

Console.WriteLine(negValue.ToString(fmt2));
Console.WriteLine(String.Format("{0:" + fmt2 + "}", negValue));
// Displays (1234)

Console.WriteLine(zeroValue.ToString(fmt3));
Console.WriteLine(String.Format("{0:" + fmt3 + "}", zeroValue));
// Displays **Zero**
Dim posValue As Double = 1234
Dim negValue As Double = -1234
Dim zeroValue As Double = 0

Dim fmt2 As String = "##;(##)"


Dim fmt3 As String = "##;(##);**Zero**"

Console.WriteLine(posValue.ToString(fmt2))
Console.WriteLine(String.Format("{0:" + fmt2 + "}", posValue))
' Displays 1234

Console.WriteLine(negValue.ToString(fmt2))
Console.WriteLine(String.Format("{0:" + fmt2 + "}", negValue))
' Displays (1234)

Console.WriteLine(zeroValue.ToString(fmt3))
Console.WriteLine(String.Format("{0:" + fmt3 + "}", zeroValue))
' Displays **Zero**

Volver a la tabla

Literales de carácter
Los especificadores de formato que aparecen en una cadena de formato numérico personalizado siempre se
interpretan como caracteres de formato y no como caracteres literales. Se incluyen los caracteres siguientes:
0
#
%

'
\
.
,
E o e, según su posición en la cadena de formato.
Todos los demás caracteres se interpretan siempre como literales de carácter y, en una operación de formato, se
incluyen en la cadena de resultado sin modificar. En una operación de análisis, deben coincidir exactamente con
los caracteres de la cadena de entrada; la comparación distingue entre mayúsculas y minúsculas.
En el ejemplo siguiente se muestra un uso habitual de las unidades de carácter literal (en este caso, los millares):

double n = 123.8;
Console.WriteLine($"{n:#,##0.0K}");
// The example displays the following output:
// 123.8K

Dim n As Double = 123.8


Console.WriteLine($"{n:#,##0.0K}")
' The example displays the following output:
' 123.8K

Hay dos formas de indicar que los caracteres se han de interpretar como caracteres literales y no como
caracteres de formato, para que se puedan incluir en una cadena de resultado o analizarse correctamente en una
cadena de entrada:
Mediante el escape de un carácter de formato. Para obtener más información, vea Carácter de escape "\".
Mediante la inclusión de toda la cadena literal entre comillas o apóstrofes.
En el ejemplo siguiente se usan los dos enfoques para incluir caracteres reservados en una cadena de formato
numérico personalizada.

double n = 9.3;
Console.WriteLine($@"{n:##.0\%}");
Console.WriteLine($@"{n:\'##\'}");
Console.WriteLine($@"{n:\\##\\}");
Console.WriteLine();
Console.WriteLine($"{n:##.0'%'}");
Console.WriteLine($@"{n:'\'##'\'}");
// The example displays the following output:
// 9.3%
// '9'
// \9\
//
// 9.3%
// \9\

Dim n As Double = 9.3


Console.WriteLine($"{n:##.0\%}")
Console.WriteLine($"{n:\'##\'}")
Console.WriteLine($"{n:\\##\\}")
Console.WriteLine()
Console.WriteLine($"{n:##.0'%'}")
Console.WriteLine($"{n:'\'##'\'}")
' The example displays the following output:
' 9.3%
' '9'
' \9\
'
' 9.3%
' \9\

Notas
Infinitos de punto flotante y NaN
Independientemente de la cadena de formato, si el valor de un tipo de punto flotante Single o Double es infinito
positivo, infinito negativo o NaN (Not a Number, no es un número), la cadena con formato será el valor de la
propiedad PositiveInfinitySymbol, NegativeInfinitySymbolo NaNSymbol respectiva especificada por el objeto
NumberFormatInfo aplicable actualmente.
Configuración del Panel de control
Los valores de configuración del elemento Configuración regional y de idioma del Panel de control influyen
en la cadena de resultado generada por una operación de formato. Estos valores de configuración se utilizan
para inicializar el objeto NumberFormatInfo asociado a la referencia cultural del subproceso actual, y la
referencia cultural del subproceso actual proporciona valores que se utilizan para controlar el formato. Los
equipos que usan configuraciones diferentes generarán cadenas de resultado distintas.
Asimismo, si se usa el constructor CultureInfo.CultureInfo(String) para crear instancias de un nuevo objeto
CultureInfo que representa la misma referencia cultural que la referencia cultural del sistema actual, cualquier
personalización establecida por el elemento Configuración regional y de idioma del Panel de control se
aplicará al nuevo objeto CultureInfo . Puede usar el constructor CultureInfo.CultureInfo(String, Boolean) para
crear un objeto CultureInfo que no refleje las personalizaciones de un sistema.
Cadenas de formato de punto fijo y redondeo
Para las cadenas de formato de punto fijo (es decir, las cadenas de formato que no contienen caracteres de
formato de notación científica), los números se redondean hasta tantos decimales como marcadores de posición
de dígitos haya a la derecha del separador decimal. Si la cadena de formato no contiene ningún separador
decimal, el número se redondea al entero más próximo. Si el número tiene más dígitos que marcadores de
posición de dígitos a la izquierda del separador decimal, los dígitos adicionales se copian en la cadena de
resultado justo antes del primer marcador de posición de dígitos.
Volver a la tabla

Ejemplo
En el siguiente ejemplo se muestran dos cadenas de formato numérico personalizado. En ambos casos, el
marcador de posición de dígitos ( # ) muestra los datos numéricos, y todos los demás caracteres se copian en la
cadena de resultado.

double number1 = 1234567890;


String^ value1 = number1.ToString("(###) ###-####");
Console::WriteLine(value1);

int number2 = 42;


String^ value2 = number2.ToString("My Number = #");
Console::WriteLine(value2);
// The example displays the following output:
// (123) 456-7890
// My Number = 42

double number1 = 1234567890;


string value1 = number1.ToString("(###) ###-####");
Console.WriteLine(value1);

int number2 = 42;


string value2 = number2.ToString("My Number = #");
Console.WriteLine(value2);
// The example displays the following output:
// (123) 456-7890
// My Number = 42

Dim number1 As Double = 1234567890


Dim value1 As String = number1.ToString("(###) ###-####")
Console.WriteLine(value1)

Dim number2 As Integer = 42


Dim value2 As String = number2.ToString("My Number = #")
Console.WriteLine(value2)
' The example displays the following output:
' (123) 456-7890
' My Number = 42

Volver a la tabla

Vea también
System.Globalization.NumberFormatInfo
Aplicación de formato a tipos
Standard Numeric Format Strings
Cómo: Rellenar un número con ceros a la izquierda
Ejemplo: Utilidad de formato WinForms de .NET Core (C#)
Ejemplo: Utilidad de formato WinForms de .NET Core (Visual Basic)
Cadenas con formato de fecha y hora estándar
13/01/2020 • 53 minutes to read • Edit Online

Una cadena de formato de fecha y hora estándar usa un único especificador de formato para definir la
representación de texto de un valor de fecha y hora. Cualquier cadena con formato de fecha y hora que contenga
más de un carácter, incluido un espacio en blanco, se interpreta como una cadena con formato de fecha y hora
personalizado; para obtener más información, consulte Cadenas con formato de fecha y hora personalizado. Una
cadena de formato estándar o personalizado se puede usar de dos maneras:
Para definir la cadena resultante una operación de formato.
Para definir la representación de texto de un valor de fecha y hora que se puede convertir en un valor
DateTime o DateTimeOffset mediante una operación de análisis.

TIP
Puede descargar la Utilidad de formato, que es una aplicación de .NET Core Windows Forms que permite aplicar cadenas
de formato a valores numéricos o de fecha y hora, y que muestra la cadena de resultado. El código fuente está disponible
para C# y Visual Basic.

Las cadenas con formato de fecha y hora estándar se pueden utilizar tanto con valores DateTime como con
valores DateTimeOffset.

NOTE
Algunos de los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET.
Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código,
puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la
ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes de
error del compilador de C#.
La zona horaria local del ejecutor de código en línea de Try.NET y del área de juegos es la hora universal coordinada o UTC.
Esto puede afectar al comportamiento y la salida de ejemplos que ilustran los tipos DateTime, DateTimeOffset y
TimeZoneInfo y sus miembros.

En la tabla siguiente se describen los especificadores de formato de fecha y hora estándar. A menos que se
indique lo contrario, un determinado especificador de formato de fecha y hora estándar genera una
representación de cadena idéntica independientemente de que se use con un valor DateTime o DateTimeOffset.
Consulte la sección Notas para obtener información adicional sobre cómo usar cadenas de formato de fecha y
hora estándar.

ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"d" Patrón de fecha corta. 2009-06-15T13:45:30 -> 6/15/2009


(en-US)
Más información: El especificador de
formato de fecha corta ("d"). 2009-06-15T13:45:30 -> 15/06/2009
(fr-FR)

2009-06-15T13:45:30 -> 2009/06/15


(ja-JP)
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"D" Patrón de fecha larga. 2009-06-15T13:45:30 -> Monday,


June 15, 2009 (en-US)
Más información: El especificador de
formato de fecha larga ("D"). 2009-06-15T13:45:30 -> 15 июня
2009 г. (ru-RU)

2009-06-15T13:45:30 -> Montag, 15.


Juni 2009 (de-DE)

"f" Patrón de fecha y hora completa (hora 2009-06-15T13:45:30 -> Monday,


corta). June 15, 2009 1:45 PM (en-US)

Más información: El especificador de 2009-06-15T13:45:30 -> den 15 juni


formato de fecha completa y hora 2009 13:45 (sv-SE)
corta ("f").
2009-06-15T13:45:30 -> Δευτέρα, 15
Ιουνίου 2009 1:45 μμ (el-GR)

"F" Patrón de fecha y hora completa (hora 2009-06-15T13:45:30 -> Monday,


larga). June 15, 2009 1:45:30 PM (en-US)

Más información: El especificador de 2009-06-15T13:45:30 -> den 15 juni


formato de fecha completa y hora larga 2009 13:45:30 (sv-SE)
("F").
2009-06-15T13:45:30 -> Δευτέρα, 15
Ιουνίου 2009 1:45:30 μμ (el-GR)

"g" Patrón de fecha y hora general (hora 2009-06-15T13:45:30 -> 6/15/2009


corta). 1:45 PM (en-US)

Más información: El especificador de 2009-06-15T13:45:30 -> 15/06/2009


formato de fecha general y hora corta 13:45 (es-ES)
("g").
2009-06-15T13:45:30 -> 2009/6/15
13:45 (zh-CN)

"G" Patrón de fecha y hora general (hora 2009-06-15T13:45:30 -> 6/15/2009


larga). 1:45:30 PM (en-US)

Más información: El especificador de 2009-06-15T13:45:30 -> 15/06/2009


formato de fecha general y hora larga 13:45:30 (es-ES)
("G").
2009-06-15T13:45:30 -> 2009/6/15
13:45:30 (zh-CN)

"M", "m" Patrón de mes/día. 2009-06-15T13:45:30 -> June 15 (en-


US)
Más información: El especificador de
formato de mes ("M", "m"). 2009-06-15T13:45:30 -> 15. juni (da-
DK)

2009-06-15T13:45:30 -> 15 Juni (id-


ID)
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"O", "o" Patrón de fecha y hora de ida y vuelta. Valores de DateTime:

Más información: El especificador de 2009-06-15T13:45:30


formato de operación de ida y vuelta (DateTimeKind.Local) --> 2009-06-
("O", "o"). 15T13:45:30.0000000-07:00

2009-06-15T13:45:30
(DateTimeKind.Utc) --> 2009-06-
15T13:45:30.0000000Z

2009-06-15T13:45:30
(DateTimeKind.Unspecified) --> 2009-
06-15T13:45:30.0000000

Valores de DateTimeOffset:

2009-06-15T13:45:30-07:00 -->
2009-06-15T13:45:30.0000000-07:00

"R", "r" Patrón RFC1123. 2009-06-15T13:45:30 -> Mon, 15 Jun


2009 20:45:30 GMT
Más información: El especificador de
formato RFC1123 ("R", "r").

"s" Patrón de fecha y hora que se puede 2009-06-15T13:45:30


ordenar. (DateTimeKind.Local) -> 2009-06-
15T13:45:30
Más información: El especificador de
formato que se puede ordenar ("s"). 2009-06-15T13:45:30
(DateTimeKind.Utc) -> 2009-06-
15T13:45:30

"t" Patrón de hora corta. 2009-06-15T13:45:30 -> 1:45 PM (en-


US)
Más información: El especificador de
formato de hora corta ("t"). 2009-06-15T13:45:30 -> 13:45 (hr-
HR)

2009-06-15T13:45:30 -> 01:45 ‫( م‬ar-


EG)

"T" Patrón de hora larga. 2009-06-15T13:45:30 -> 1:45:30 PM


(en-US)
Más información: El especificador de
formato de hora larga ("T"). 2009-06-15T13:45:30 -> 13:45:30 (hr-
HR)

2009-06-15T13:45:30 -> 01:45:30 ‫م‬


(ar-EG)

"u" Patrón de fecha y hora universal que se Con un valor DateTime de: 2009-06-
puede ordenar. 15T13:45:30 -> 2009-06-15
13:45:30Z
Más información: El especificador de
formato universal que se puede Con un valor DateTimeOffset de: 2009-
ordenar ("u"). 06-15T13:45:30 -> 2009-06-15
20:45:30Z
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"U" Patrón de fecha y hora completa 2009-06-15T13:45:30 -> Monday,


universal. June 15, 2009 8:45:30 PM (en-US)

Más información: El especificador de 2009-06-15T13:45:30 -> den 15 juni


formato completo universal ("U"). 2009 20:45:30 (sv-SE)

2009-06-15T13:45:30 -> Δευτέρα, 15


Ιουνίου 2009 8:45:30 μμ (el-GR)

"Y", "y" Patrón de mes y año. 2009-06-15T13:45:30 -> June, 2009


(en-US)
Más información: El especificador de
formato de mes y año ("Y"). 2009-06-15T13:45:30 -> juni 2009
(da-DK)

2009-06-15T13:45:30 -> Juni 2009


(id-ID)

Cualquier otro carácter único Especificador desconocido. Produce una excepción


FormatException en tiempo de
ejecución.

Cómo funcionan las cadenas con formato estándar


En una operación de formato, una cadena de formato estándar es simplemente un alias de una cadena con
formato personalizado. La ventaja de usar un alias para referirse a una cadena de formato personalizado es que,
aunque el alias permanece invariable, la propia cadena de formato personalizado puede variar. Esto es
importante, porque las representaciones de cadena de valores de fecha y hora suelen variar con las referencias
culturales. Por ejemplo, la cadena de formato estándar "d" indica que un valor de fecha y hora se va a mostrar
utilizando un patrón de fecha corta. En la referencia cultural de todos los idiomas, este patrón es "MM/dd/aaaa".
En la referencia cultural fr-FR, es "dd/MM/aaaa". En la referencia cultural ja-JP, es "aaaa/MM/dd."
Si una cadena con formato estándar en una operación de formato se asigna a una cadena con formato
personalizado de una referencia cultural específica, la aplicación puede definir la referencia cultural concreta
cuyas cadenas con formato personalizado se usan de uno de los modos siguientes:
Puede utilizar la referencia cultural predeterminada (o la actual). En el ejemplo siguiente se muestra una
fecha con el formato de fecha abreviado de la referencia cultural. En este caso, la referencia cultural actual
es en-US.

// Display using current (en-us) culture's short date format


DateTime thisDate = new DateTime(2008, 3, 15);
Console.WriteLine(thisDate.ToString("d")); // Displays 3/15/2008

' Display using current (en-us) culture's short date format


Dim thisDate As Date = #03/15/2008#
Console.WriteLine(thisDate.ToString("d")) ' Displays 3/15/2008

Puede pasar un objeto CultureInfo que represente la referencia cultural cuyo formato se va a usar a un
método que tenga un parámetro IFormatProvider. En el ejemplo siguiente se muestra una fecha con el
formato de fecha abreviado de la referencia cultural pt-BR.
// Display using pt-BR culture's short date format
DateTime thisDate = new DateTime(2008, 3, 15);
CultureInfo culture = new CultureInfo("pt-BR");
Console.WriteLine(thisDate.ToString("d", culture)); // Displays 15/3/2008

' Display using pt-BR culture's short date format


Dim thisDate As Date = #03/15/2008#
Dim culture As New CultureInfo("pt-BR")
Console.WriteLine(thisDate.ToString("d", culture)) ' Displays 15/3/2008

Puede pasar un objeto DateTimeFormatInfo que proporcione información sobre el formato a un método
que tenga un parámetro IFormatProvider. En el ejemplo siguiente se muestra una fecha con el formato de
fecha abreviado de un objeto DateTimeFormatInfo en la referencia cultural hr-HR.

// Display using date format information from hr-HR culture


DateTime thisDate = new DateTime(2008, 3, 15);
DateTimeFormatInfo fmt = (new CultureInfo("hr-HR")).DateTimeFormat;
Console.WriteLine(thisDate.ToString("d", fmt)); // Displays 15.3.2008

' Display using date format information from hr-HR culture


Dim thisDate As Date = #03/15/2008#
Dim fmt As DateTimeFormatInfo = (New CultureInfo("hr-HR")).DateTimeFormat
Console.WriteLine(thisDate.ToString("d", fmt)) ' Displays 15.3.2008

NOTE
Para obtener información sobre la personalización de patrones o cadenas usadas para dar formato a valores de fecha y
hora, vea el tema sobre la clase NumberFormatInfo.

En algunos casos, la cadena con formato estándar actúa como la abreviatura correspondiente de una cadena con
formato personalizado más larga que es invariable. Hay cuatro cadenas de formato estándar que pertenecen a
esta categoría: "O" (u "o"), "R" (o "r"), "s" y "u". Estas cadenas se corresponden con las cadenas de formato
personalizado definidas en la referencia cultural de todos los idiomas. Generan representaciones de cadena de
valores de fecha y hora que están pensados para que sean idénticos en todas las referencias culturales. En la
tabla siguiente se proporciona información sobre estas cuatro cadenas de formato de fecha y hora estándar.

SE DEFINE EN LA PROPIEDAD
CADENA CON FORMATO ESTÁNDAR DATETIMEFORMATINFO.INVARIANTINFO CADENA CON FORMATO PERSONALIZADO

"O" u "o" None yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzz

"R" o "r" RFC1123Pattern ddd, dd MMM yyyy HH':'mm':'ss 'GMT'

"s" SortableDateTimePattern yyyy'-'MM'-'dd'T'HH':'mm':'ss

"u" UniversalSortableDateTimePattern yyyy'-'MM'-'dd HH':'mm':'ss'Z'

Las cadenas de formato estándar también se pueden usar en operaciones de análisis con los métodos
DateTime.ParseExact o DateTimeOffset.ParseExact, que necesitan que una cadena de entrada se ajuste
exactamente a un patrón determinado para que la operación de análisis se realice correctamente. Muchas
cadenas de formato estándar se asignan a varias cadenas de formato personalizado, por lo que un valor de fecha
y hora se pueden representar en diversos formatos y la operación de análisis todavía se realizará correctamente.
Puede determinar la cadena o las cadenas con formato personalizado correspondientes a una cadena con
formato estándar llamando al método DateTimeFormatInfo.GetAllDateTimePatterns(Char). En el ejemplo
siguiente se muestran las cadenas con formato personalizado que se asignan a la cadena de formato estándar "d"
(patrón de fecha corta).

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
Console.WriteLine("'d' standard format string:");
foreach (var customString in DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns('d'))
Console.WriteLine(" {0}", customString);
}
}
// The example displays the following output:
// 'd' standard format string:
// M/d/yyyy
// M/d/yy
// MM/dd/yy
// MM/dd/yyyy
// yy/MM/dd
// yyyy-MM-dd
// dd-MMM-yy

Imports System.Globalization

Module Example
Public Sub Main()
Console.WriteLine("'d' standard format string:")
For Each customString In DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns("d"c)
Console.WriteLine(" {0}", customString)
Next
End Sub
End Module
' The example displays the following output:
' 'd' standard format string:
' M/d/yyyy
' M/d/yy
' MM/dd/yy
' MM/dd/yyyy
' yy/MM/dd
' yyyy-MM-dd
' dd-MMM-yy

En las próximas secciones se describen los especificadores de formato estándar para los valores DateTime y
DateTimeOffset.

El especificador de formato de fecha corta ("d")


El especificador de formato estándar "d" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.ShortDatePattern de una referencia cultural concreta. Por
ejemplo, la cadena de formato personalizado devuelta por la propiedad ShortDatePattern de la referencia
cultural de todos los idiomas es "MM/dd/yyyy".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que controlan el formato de la
cadena devuelta.
PROPIEDAD. DESCRIPCIÓN

ShortDatePattern Define el formato global de la cadena de resultado.

DateSeparator Define la cadena que separa los componentes de año, mes y


día de una fecha.

En el ejemplo siguiente se usa el especificador de formato "d" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008,4, 10);


Console.WriteLine(date1.ToString("d", DateTimeFormatInfo.InvariantInfo));
// Displays 04/10/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays 4/10/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("en-NZ")));
// Displays 10/04/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("de-DE")));
// Displays 10.04.2008

Dim date1 As Date = #4/10/2008#


Console.WriteLine(date1.ToString("d", DateTimeFormatInfo.InvariantInfo))
' Displays 04/10/2008
Console.WriteLine(date1.ToString("d", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays 4/10/2008
Console.WriteLine(date1.ToString("d", _
CultureInfo.CreateSpecificCulture("en-NZ")))
' Displays 10/04/2008
Console.WriteLine(date1.ToString("d", _
CultureInfo.CreateSpecificCulture("de-DE")))
' Displays 10.04.2008

Volver a la tabla

El especificador de formato de fecha larga ("D")


El especificador de formato estándar "D" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.LongDatePattern actual. Por ejemplo, la cadena de formato
personalizado para la referencia cultural de todos los idiomas es "dddd, dd MMMM yyyy".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que controlan el formato de la
cadena devuelta.

PROPIEDAD. DESCRIPCIÓN

LongDatePattern Define el formato global de la cadena de resultado.

DayNames Define los nombres de días traducidos que pueden aparecer


en la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

En el ejemplo siguiente se usa el especificador de formato "D" para mostrar un valor de fecha y hora.
DateTime date1 = new DateTime(2008, 4, 10);
Console.WriteLine(date1.ToString("D",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Thursday, April 10, 2008
Console.WriteLine(date1.ToString("D",
CultureInfo.CreateSpecificCulture("pt-BR")));
// Displays quinta-feira, 10 de abril de 2008
Console.WriteLine(date1.ToString("D",
CultureInfo.CreateSpecificCulture("es-MX")));
// Displays jueves, 10 de abril de 2008

Dim date1 As Date = #4/10/2008#


Console.WriteLine(date1.ToString("D", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Thursday, April 10, 2008
Console.WriteLine(date1.ToString("D", _
CultureInfo.CreateSpecificCulture("pt-BR")))
' Displays quinta-feira, 10 de abril de 2008
Console.WriteLine(date1.ToString("D", _
CultureInfo.CreateSpecificCulture("es-MX")))
' Displays jueves, 10 de abril de 2008

Volver a la tabla

El especificador de formato de fecha completa y hora corta ("f")


El especificador de formato estándar "f" representa una combinación de los patrones de fecha larga ("D") y hora
corta ("t"), separados por un espacio.
La información de formato de un objeto DateTimeFormatInfo específico afecta a la cadena de resultado. En la
tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el formato de
la cadena devuelta. El especificador de formato personalizado devuelto por las propiedades
DateTimeFormatInfo.LongDatePattern y DateTimeFormatInfo.ShortTimePattern de algunas referencias
culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

LongDatePattern Define el formato del componente de fecha de la cadena de


resultado.

ShortTimePattern Define el formato del componente de hora de la cadena de


resultado.

DayNames Define los nombres de días traducidos que pueden aparecer


en la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.
PROPIEDAD. DESCRIPCIÓN

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "f" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("f",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Thursday, April 10, 2008 6:30 AM
Console.WriteLine(date1.ToString("f",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays jeudi 10 avril 2008 06:30

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("f", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Thursday, April 10, 2008 6:30 AM
Console.WriteLine(date1.ToString("f", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays jeudi 10 avril 2008 06:30

Volver a la tabla

El especificador de formato de fecha completa y hora larga ("F")


El especificador de formato estándar "F" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.FullDateTimePattern actual. Por ejemplo, la cadena de
formato personalizado para la referencia cultural de todos los idiomas es "dddd, dd MMMM yyyy HH:mm:ss".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el
formato de la cadena devuelta. El especificador de formato personalizado devuelto por la propiedad
FullDateTimePattern de algunas referencias culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

FullDateTimePattern Define el formato global de la cadena de resultado.

DayNames Define los nombres de días traducidos que pueden aparecer


en la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "F" para mostrar un valor de fecha y hora.
DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);
Console.WriteLine(date1.ToString("F",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Thursday, April 10, 2008 6:30:00 AM
Console.WriteLine(date1.ToString("F",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays jeudi 10 avril 2008 06:30:00

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("F", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Thursday, April 10, 2008 6:30:00 AM
Console.WriteLine(date1.ToString("F", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays jeudi 10 avril 2008 06:30:00

Volver a la tabla

El especificador de formato de fecha general y hora corta ("g")


El especificador de formato estándar "g" representa una combinación de los patrones de fecha corta ("d") y hora
corta ("t"), separados por un espacio.
La información de formato de un objeto DateTimeFormatInfo específico afecta a la cadena de resultado. En la
tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el formato de
la cadena devuelta. El especificador de formato personalizado devuelto por las propiedades
DateTimeFormatInfo.ShortDatePattern y DateTimeFormatInfo.ShortTimePattern de algunas referencias
culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

ShortDatePattern Define el formato del componente de fecha de la cadena de


resultado.

ShortTimePattern Define el formato del componente de hora de la cadena de


resultado.

DateSeparator Define la cadena que separa los componentes de año, mes y


día de una fecha.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "g" para mostrar un valor de fecha y hora.
DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);
Console.WriteLine(date1.ToString("g",
DateTimeFormatInfo.InvariantInfo));
// Displays 04/10/2008 06:30
Console.WriteLine(date1.ToString("g",
CultureInfo.CreateSpecificCulture("en-us")));
// Displays 4/10/2008 6:30 AM
Console.WriteLine(date1.ToString("g",
CultureInfo.CreateSpecificCulture("fr-BE")));
// Displays 10/04/2008 6:30

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("g", _
DateTimeFormatInfo.InvariantInfo))
' Displays 04/10/2008 06:30
Console.WriteLine(date1.ToString("g", _
CultureInfo.CreateSpecificCulture("en-us")))
' Displays 4/10/2008 6:30 AM
Console.WriteLine(date1.ToString("g", _
CultureInfo.CreateSpecificCulture("fr-BE")))
' Displays 10/04/2008 6:30

Volver a la tabla

El especificador de formato de fecha general y hora larga ("G")


El especificador de formato estándar "G" representa una combinación de los patrones de fecha corta ("d") y hora
larga ("T"), separados por un espacio.
La información de formato de un objeto DateTimeFormatInfo específico afecta a la cadena de resultado. En la
tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el formato de
la cadena devuelta. El especificador de formato personalizado devuelto por las propiedades
DateTimeFormatInfo.ShortDatePattern y DateTimeFormatInfo.LongTimePattern de algunas referencias
culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

ShortDatePattern Define el formato del componente de fecha de la cadena de


resultado.

LongTimePattern Define el formato del componente de hora de la cadena de


resultado.

DateSeparator Define la cadena que separa los componentes de año, mes y


día de una fecha.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "G" para mostrar un valor de fecha y hora.
DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);
Console.WriteLine(date1.ToString("G",
DateTimeFormatInfo.InvariantInfo));
// Displays 04/10/2008 06:30:00
Console.WriteLine(date1.ToString("G",
CultureInfo.CreateSpecificCulture("en-us")));
// Displays 4/10/2008 6:30:00 AM
Console.WriteLine(date1.ToString("G",
CultureInfo.CreateSpecificCulture("nl-BE")));
// Displays 10/04/2008 6:30:00

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("G", _
DateTimeFormatInfo.InvariantInfo))
' Displays 04/10/2008 06:30:00
Console.WriteLine(date1.ToString("G", _
CultureInfo.CreateSpecificCulture("en-us")))
' Displays 4/10/2008 6:30:00 AM
Console.WriteLine(date1.ToString("G", _
CultureInfo.CreateSpecificCulture("nl-BE")))
' Displays 10/04/2008 6:30:00

Volver a la tabla

El especificador de formato de mes ("M", "m")


El especificador de formato estándar "M" o "m" representa una cadena de formato de fecha y hora personalizado
que está definida por la propiedad DateTimeFormatInfo.MonthDayPattern actual. Por ejemplo, la cadena de
formato personalizado para la referencia cultural de todos los idiomas es "MMMM dd".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que controlan el formato de la
cadena devuelta.

PROPIEDAD. DESCRIPCIÓN

MonthDayPattern Define el formato global de la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

En el ejemplo siguiente se usa el especificador de formato "m" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("m",
CultureInfo.CreateSpecificCulture("en-us")));
// Displays April 10
Console.WriteLine(date1.ToString("m",
CultureInfo.CreateSpecificCulture("ms-MY")));
// Displays 10 April

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("m", _
CultureInfo.CreateSpecificCulture("en-us")))
' Displays April 10
Console.WriteLine(date1.ToString("m", _
CultureInfo.CreateSpecificCulture("ms-MY")))
' Displays 10 April
Volver a la tabla

El especificador de formato de operación de ida y vuelta ("O", "o")


El especificador de formato estándar "O" u "o" representa una cadena de formato de fecha y hora personalizado
mediante un patrón que conserva la información de la zona horaria y emite una cadena de resultado que cumple
con la norma ISO 8601. En los valores DateTime, este especificador de formato está diseñado para conservar los
valores de fecha y hora junto con la propiedad DateTime.Kind en el texto. La cadena con formato se puede
recuperar usando el método DateTime.Parse(String, IFormatProvider, DateTimeStyles) o DateTime.ParseExact si
el parámetro styles está establecido en DateTimeStyles.RoundtripKind.
El especificador de formato estándar "O" u "o" corresponde a la cadena de formato personalizado "yyyy'-'MM'-
'dd'T'HH':'mm':'ss'.'fffffffK" para los valores DateTime y a "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" para los
valores DateTimeOffset. En esta cadena, los pares de comillas que delimitan los caracteres individuales (como
guiones, signos de dos puntos y la letra "T") indican que el carácter individual es un literal que no se puede
cambiar. Los apóstrofos no aparecen en la cadena de salida.
El especificador de formato estándar "O" u "o" (y la cadena de formato personalizado "yyyy'-'MM'-
'dd'T'HH':'mm':'ss'.'fffffffK") aprovecha los tres modos en que se representa la información de zona horaria en
ISO 8601 para conservar la propiedad Kind de valores DateTime:
El componente de zona horaria de valores de fecha y hora DateTimeKind.Local es un desfase con respecto
a la hora UTC (por ejemplo, +01:00, -07:00). Todos los valores DateTimeOffset también se representan en
este formato.
El componente de zona horaria de valores de fecha y hora DateTimeKind.Utc usa "Z" (que es un desfase
cero) para representar la hora UTC.
Los valores de fecha y hora DateTimeKind.Unspecified no tienen información de zona horaria.
Dado que el especificador de formato estándar "O" u "o" se ajusta a un estándar internacional, la operación de
formato o análisis que utiliza el especificador siempre usa la referencia cultural de todos los idiomas y el
calendario gregoriano.
Las cadenas que se pasan a los métodos Parse , TryParse , ParseExact y TryParseExact de DateTime y
DateTimeOffset se pueden analizar con el especificador de formato "O" u "o" si están en uno de estos formatos.
En el caso de objetos DateTime, la sobrecarga de análisis a la que llama también debe incluir un parámetro
styles con un valor de DateTimeStyles.RoundtripKind. Observe que si llama a un método de análisis con la
cadena de formato personalizado que se corresponde con el especificador de formato "O" u "o", no obtendrá los
mismos resultados que "O" u "o". Esto se debe a que los métodos de análisis que usan una cadena de formato
personalizado no pueden analizar la representación de cadena de aquellos valores de fecha y hora que carecen
de un componente de zona horaria o que usan "Z" para indicar la hora UTC.
En el ejemplo siguiente se utiliza el especificador de formato "o" para mostrar una serie de valores DateTime y un
valor DateTimeOffset en un sistema de la zona horaria del Pacífico de EE. UU.
using System;

public class Example


{
public static void Main()
{
DateTime dat = new DateTime(2009, 6, 15, 13, 45, 30,
DateTimeKind.Unspecified);
Console.WriteLine("{0} ({1}) --> {0:O}", dat, dat.Kind);

DateTime uDat = new DateTime(2009, 6, 15, 13, 45, 30,


DateTimeKind.Utc);
Console.WriteLine("{0} ({1}) --> {0:O}", uDat, uDat.Kind);

DateTime lDat = new DateTime(2009, 6, 15, 13, 45, 30,


DateTimeKind.Local);
Console.WriteLine("{0} ({1}) --> {0:O}\n", lDat, lDat.Kind);

DateTimeOffset dto = new DateTimeOffset(lDat);


Console.WriteLine("{0} --> {0:O}", dto);
}
}
// The example displays the following output:
// 6/15/2009 1:45:30 PM (Unspecified) --> 2009-06-15T13:45:30.0000000
// 6/15/2009 1:45:30 PM (Utc) --> 2009-06-15T13:45:30.0000000Z
// 6/15/2009 1:45:30 PM (Local) --> 2009-06-15T13:45:30.0000000-07:00
//
// 6/15/2009 1:45:30 PM -07:00 --> 2009-06-15T13:45:30.0000000-07:00

Module Example
Public Sub Main()
Dim dat As New Date(2009, 6, 15, 13, 45, 30,
DateTimeKind.Unspecified)
Console.WriteLine("{0} ({1}) --> {0:O}", dat, dat.Kind)

Dim uDat As New Date(2009, 6, 15, 13, 45, 30, DateTimeKind.Utc)


Console.WriteLine("{0} ({1}) --> {0:O}", uDat, uDat.Kind)

Dim lDat As New Date(2009, 6, 15, 13, 45, 30, DateTimeKind.Local)


Console.WriteLine("{0} ({1}) --> {0:O}", lDat, lDat.Kind)
Console.WriteLine()

Dim dto As New DateTimeOffset(lDat)


Console.WriteLine("{0} --> {0:O}", dto)
End Sub
End Module
' The example displays the following output:
' 6/15/2009 1:45:30 PM (Unspecified) --> 2009-06-15T13:45:30.0000000
' 6/15/2009 1:45:30 PM (Utc) --> 2009-06-15T13:45:30.0000000Z
' 6/15/2009 1:45:30 PM (Local) --> 2009-06-15T13:45:30.0000000-07:00
'
' 6/15/2009 1:45:30 PM -07:00 --> 2009-06-15T13:45:30.0000000-07:00

En el ejemplo siguiente se usa el especificador de formato "o" para crear una cadena con formato y, a
continuación, se restaura el valor de fecha y hora original llamando a un método Parse de fecha y hora.
// Round-trip DateTime values.
DateTime originalDate, newDate;
string dateString;
// Round-trip a local time.
originalDate = DateTime.SpecifyKind(new DateTime(2008, 4, 10, 6, 30, 0), DateTimeKind.Local);
dateString = originalDate.ToString("o");
newDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind,
newDate, newDate.Kind);
// Round-trip a UTC time.
originalDate = DateTime.SpecifyKind(new DateTime(2008, 4, 12, 9, 30, 0), DateTimeKind.Utc);
dateString = originalDate.ToString("o");
newDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind,
newDate, newDate.Kind);
// Round-trip time in an unspecified time zone.
originalDate = DateTime.SpecifyKind(new DateTime(2008, 4, 13, 12, 30, 0), DateTimeKind.Unspecified);
dateString = originalDate.ToString("o");
newDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind,
newDate, newDate.Kind);

// Round-trip a DateTimeOffset value.


DateTimeOffset originalDTO = new DateTimeOffset(2008, 4, 12, 9, 30, 0, new TimeSpan(-8, 0, 0));
dateString = originalDTO.ToString("o");
DateTimeOffset newDTO = DateTimeOffset.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Round-tripped {0} to {1}.", originalDTO, newDTO);
// The example displays the following output:
// Round-tripped 4/10/2008 6:30:00 AM Local to 4/10/2008 6:30:00 AM Local.
// Round-tripped 4/12/2008 9:30:00 AM Utc to 4/12/2008 9:30:00 AM Utc.
// Round-tripped 4/13/2008 12:30:00 PM Unspecified to 4/13/2008 12:30:00 PM Unspecified.
// Round-tripped 4/12/2008 9:30:00 AM -08:00 to 4/12/2008 9:30:00 AM -08:00.
' Round-trip DateTime values.
Dim originalDate, newDate As Date
Dim dateString As String
' Round-trip a local time.
originalDate = Date.SpecifyKind(#4/10/2008 6:30AM#, DateTimeKind.Local)
dateString = originalDate.ToString("o")
newDate = Date.Parse(dateString, Nothing, DateTimeStyles.RoundtripKind)
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind, _
newDate, newDate.Kind)
' Round-trip a UTC time.
originalDate = Date.SpecifyKind(#4/12/2008 9:30AM#, DateTimeKind.Utc)
dateString = originalDate.ToString("o")
newDate = Date.Parse(dateString, Nothing, DateTimeStyles.RoundtripKind)
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind, _
newDate, newDate.Kind)
' Round-trip time in an unspecified time zone.
originalDate = Date.SpecifyKind(#4/13/2008 12:30PM#, DateTimeKind.Unspecified)
dateString = originalDate.ToString("o")
newDate = Date.Parse(dateString, Nothing, DateTimeStyles.RoundtripKind)
Console.WriteLine("Round-tripped {0} {1} to {2} {3}.", originalDate, originalDate.Kind, _
newDate, newDate.Kind)

' Round-trip a DateTimeOffset value.


Dim originalDTO As New DateTimeOffset(#4/12/2008 9:30AM#, New TimeSpan(-8, 0, 0))
dateString = originalDTO.ToString("o")
Dim newDTO As DateTimeOffset = DateTimeOffset.Parse(dateString, Nothing, DateTimeStyles.RoundtripKind)
Console.WriteLine("Round-tripped {0} to {1}.", originalDTO, newDTO)
' The example displays the following output:
' Round-tripped 4/10/2008 6:30:00 AM Local to 4/10/2008 6:30:00 AM Local.
' Round-tripped 4/12/2008 9:30:00 AM Utc to 4/12/2008 9:30:00 AM Utc.
' Round-tripped 4/13/2008 12:30:00 PM Unspecified to 4/13/2008 12:30:00 PM Unspecified.
' Round-tripped 4/12/2008 9:30:00 AM -08:00 to 4/12/2008 9:30:00 AM -08:00.

Volver a la tabla

El especificador de formato RFC1123 ("R", "r")


El especificador de formato estándar "R" o "r" representa una cadena de formato de fecha y hora personalizado
que está definida por la propiedad DateTimeFormatInfo.RFC1123Pattern. El patrón refleja una norma definida y
la propiedad es de solo lectura. Por consiguiente, siempre es el mismo, sea cual fuere la referencia cultural
utilizada o el proveedor de formato proporcionado. La cadena de formato personalizado es "ddd, dd MMM yyyy
HH':'mm':'ss 'GMT'". Cuando se utiliza este especificador de formato estándar, la operación de formato o análisis
utiliza siempre la referencia cultural de todos los idiomas.
Las siguientes propiedades del objeto DateTimeFormatInfo devuelto por la propiedad
DateTimeFormatInfo.InvariantInfo que representa la referencia cultural de todos los idiomas afectan a la cadena
de resultado.

PROPIEDAD. DESCRIPCIÓN

RFC1123Pattern Define el formato de la cadena de resultado.

AbbreviatedDayNames Define los nombres de días abreviados que pueden aparecer


en la cadena de resultado.

AbbreviatedMonthNames Define los nombres de meses abreviados que pueden


aparecer en la cadena de resultado.

Aunque la norma RFC 1123 expresa una hora según la hora universal coordinada (hora UTC ), la operación de
formato no modifica el valor del objeto DateTime al que se está dando formato. Por consiguiente, debe convertir
el valor DateTime en una hora UTC llamando al método DateTime.ToUniversalTime antes de realizar la
operación de formato. En cambio, los valores DateTimeOffset realizan esta conversión automáticamente; no es
necesario llamar al método DateTimeOffset.ToUniversalTime antes de la operación de formato.
En el ejemplo siguiente se utiliza el especificador de formato "r" para mostrar un DateTime y un
valor DateTimeOffset en un sistema de la zona horaria del Pacífico de EE. UU.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


DateTimeOffset dateOffset = new DateTimeOffset(date1,
TimeZoneInfo.Local.GetUtcOffset(date1));
Console.WriteLine(date1.ToUniversalTime().ToString("r"));
// Displays Thu, 10 Apr 2008 13:30:00 GMT
Console.WriteLine(dateOffset.ToUniversalTime().ToString("r"));
// Displays Thu, 10 Apr 2008 13:30:00 GMT

Dim date1 As Date = #4/10/2008 6:30AM#


Dim dateOffset As New DateTimeOffset(date1, TimeZoneInfo.Local.GetUtcOFfset(date1))
Console.WriteLine(date1.ToUniversalTime.ToString("r"))
' Displays Thu, 10 Apr 2008 13:30:00 GMT
Console.WriteLine(dateOffset.ToUniversalTime.ToString("r"))
' Displays Thu, 10 Apr 2008 13:30:00 GMT

Volver a la tabla

El especificador de formato que se puede ordenar ("s")


El especificador de formato estándar "s" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.SortableDateTimePattern. El patrón refleja una norma
definida (ISO 8601) y la propiedad es de solo lectura. Por consiguiente, siempre es el mismo, sea cual fuere la
referencia cultural utilizada o el proveedor de formato proporcionado. La cadena de formato personalizado es
"yyyy'-'MM'-'dd'T'HH':'mm':'ss".
La finalidad del especificador de formato "s" es generar cadenas de resultado de forma coherente en orden
ascendente o descendente según los valores de fecha y hora. Como resultado, aunque el especificador de
formato estándar "s" representa un valor de fecha y hora en un formato coherente, la operación de formato no
modifica el valor del objeto de fecha y hora al que se está dando formato para reflejar su propiedad
DateTime.Kind o su valor DateTimeOffset.Offset. Por ejemplo, las cadenas de resultado que se producen al dar
formato a los valores de fecha y hora 2014-11-15T18:32:17+00:00 y 2014-11-15T18:32:17+08:00 son idénticas.
Cuando se utiliza este especificador de formato estándar, la operación de formato o análisis utiliza siempre la
referencia cultural de todos los idiomas.
En el ejemplo siguiente se utiliza el especificador de formato "s" para mostrar un valor DateTime y
DateTimeOffset en un sistema de la zona horaria del Pacífico de EE. UU.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("s"));
// Displays 2008-04-10T06:30:00

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("s"))
' Displays 2008-04-10T06:30:00

Volver a la tabla
El especificador de formato de hora corta ("t")
El especificador de formato estándar "t" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.ShortTimePattern actual. Por ejemplo, la cadena de formato
personalizado para la referencia cultural de todos los idiomas es "HH:mm".
La información de formato de un objeto DateTimeFormatInfo específico afecta a la cadena de resultado. En la
tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el formato de
la cadena devuelta. El especificador de formato personalizado devuelto por la propiedad
DateTimeFormatInfo.ShortTimePattern de algunas referencias culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

ShortTimePattern Define el formato del componente de hora de la cadena de


resultado.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "t" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("t",
CultureInfo.CreateSpecificCulture("en-us")));
// Displays 6:30 AM
Console.WriteLine(date1.ToString("t",
CultureInfo.CreateSpecificCulture("es-ES")));
// Displays 6:30

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("t", _
CultureInfo.CreateSpecificCulture("en-us")))
' Displays 6:30 AM
Console.WriteLine(date1.ToString("t", _
CultureInfo.CreateSpecificCulture("es-ES")))
' Displays 6:30

Volver a la tabla

El especificador de formato de hora larga ("T")


El especificador de formato estándar "T" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.LongTimePattern de una referencia cultural concreta. Por
ejemplo, la cadena de formato personalizado para la referencia cultural de todos los idiomas es "HH:mm:ss".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el
formato de la cadena devuelta. El especificador de formato personalizado devuelto por la propiedad
DateTimeFormatInfo.LongTimePattern de algunas referencias culturales quizás no use todas las propiedades.
PROPIEDAD. DESCRIPCIÓN

LongTimePattern Define el formato del componente de hora de la cadena de


resultado.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

En el ejemplo siguiente se usa el especificador de formato "T" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("T",
CultureInfo.CreateSpecificCulture("en-us")));
// Displays 6:30:00 AM
Console.WriteLine(date1.ToString("T",
CultureInfo.CreateSpecificCulture("es-ES")));
// Displays 6:30:00

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("T", _
CultureInfo.CreateSpecificCulture("en-us")))
' Displays 6:30:00 AM
Console.WriteLine(date1.ToString("T", _
CultureInfo.CreateSpecificCulture("es-ES")))
' Displays 6:30:00

Volver a la tabla

El especificador de formato universal que se puede ordenar ("u")


El especificador de formato estándar "u" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.UniversalSortableDateTimePattern. El patrón refleja una
norma definida y la propiedad es de solo lectura. Por consiguiente, siempre es el mismo, sea cual fuere la
referencia cultural utilizada o el proveedor de formato proporcionado. La cadena de formato personalizado es
"yyyy'-'MM'-'dd HH':'mm':'ss'Z'". Cuando se utiliza este especificador de formato estándar, la operación de
formato o análisis utiliza siempre la referencia cultural de todos los idiomas.
Aunque la cadena de resultado debe expresar una hora como una hora universal coordinada (hora UTC ), no se
realiza ninguna conversión del valor DateTime original durante la operación de formato. Por consiguiente, debe
convertir un valor DateTime en una hora UTC llamando al método DateTime.ToUniversalTime antes de aplicarle
formato. En cambio, los valores DateTimeOffset realizan esta conversión automáticamente; no es necesario
llamar al método DateTimeOffset.ToUniversalTime antes de la operación de formato.
En el ejemplo siguiente se usa el especificador de formato "u" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToUniversalTime().ToString("u"));
// Displays 2008-04-10 13:30:00Z
Dim date1 As Date = #4/10/2008 6:30AM#
Console.WriteLine(date1.ToUniversalTime.ToString("u"))
' Displays 2008-04-10 13:30:00Z

Volver a la tabla

El especificador de formato completo universal ("U")


El especificador de formato estándar "U" representa una cadena de formato de fecha y hora personalizado que
está definida por la propiedad DateTimeFormatInfo.FullDateTimePattern de una referencia cultural especificada.
El patrón es igual que el patrón de "F". Sin embargo, el valor DateTime se convierte automáticamente en una
hora UTC antes de darle formato.
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que pueden controlar el
formato de la cadena devuelta. El especificador de formato personalizado devuelto por la propiedad
FullDateTimePattern de algunas referencias culturales quizás no use todas las propiedades.

PROPIEDAD. DESCRIPCIÓN

FullDateTimePattern Define el formato global de la cadena de resultado.

DayNames Define los nombres de días traducidos que pueden aparecer


en la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

TimeSeparator Define la cadena que separa los componentes de hora,


minutos y segundos de una hora.

AMDesignator Define la cadena que indica las horas comprendidas desde


medianoche hasta antes del mediodía en un reloj de 12
horas.

PMDesignator Define la cadena que indica las horas comprendidas desde el


mediodía hasta antes de medianoche en un reloj de 12 horas.

El especificador de formato "U" no es compatible con el tipo DateTimeOffset y provoca una excepción
FormatException si se usa para dar formato a un valor DateTimeOffset.
En el ejemplo siguiente se usa el especificador de formato "U" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("U",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Thursday, April 10, 2008 1:30:00 PM
Console.WriteLine(date1.ToString("U",
CultureInfo.CreateSpecificCulture("sv-FI")));
// Displays den 10 april 2008 13:30:00

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("U", CultureInfo.CreateSpecificCulture("en-US")))
' Displays Thursday, April 10, 2008 1:30:00 PM
Console.WriteLine(date1.ToString("U", CultureInfo.CreateSpecificCulture("sv-FI")))
' Displays den 10 april 2008 13:30:00
Volver a la tabla

El especificador de formato de mes y año ("Y", "y")


El especificador de formato estándar "Y" o "y" representa una cadena de formato de fecha y hora personalizado
que está definida por la propiedad DateTimeFormatInfo.YearMonthPattern de una referencia cultural
especificada. Por ejemplo, la cadena de formato personalizado para la referencia cultural de todos los idiomas es
"yyyy MMMM".
En la tabla siguiente se enumeran las propiedades del objeto DateTimeFormatInfo que controlan el formato de la
cadena devuelta.

PROPIEDAD. DESCRIPCIÓN

YearMonthPattern Define el formato global de la cadena de resultado.

MonthNames Define los nombres de meses traducidos que pueden


aparecer en la cadena de resultado.

En el ejemplo siguiente se usa el especificador de formato "y" para mostrar un valor de fecha y hora.

DateTime date1 = new DateTime(2008, 4, 10, 6, 30, 0);


Console.WriteLine(date1.ToString("Y",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays April, 2008
Console.WriteLine(date1.ToString("y",
CultureInfo.CreateSpecificCulture("af-ZA")));
// Displays April 2008

Dim date1 As Date = #4/10/2008 6:30AM#


Console.WriteLine(date1.ToString("Y", CultureInfo.CreateSpecificCulture("en-US")))
' Displays April, 2008
Console.WriteLine(date1.ToString("y", CultureInfo.CreateSpecificCulture("af-ZA")))
' Displays April 2008

Volver a la tabla

Notas
Configuración del Panel de control
Los valores de configuración del elemento Configuración regional y de idioma del Panel de control influyen
en la cadena de resultado generada por una operación de formato. Estas configuraciones se utilizan para
inicializar el objeto DateTimeFormatInfo asociado a la referencia cultural del subproceso actual, que proporciona
valores que se utilizan para controlar el formato. Los equipos que usan configuraciones diferentes generarán
cadenas de resultado distintas.
Asimismo, si se usa el constructor CultureInfo.CultureInfo(String) para crear instancias de un nuevo objeto
CultureInfo que representa la misma referencia cultural que la referencia cultural del sistema actual, cualquier
personalización establecida por el elemento Configuración regional y de idioma del Panel de control se
aplicará al nuevo objeto CultureInfo . Puede usar el constructor CultureInfo.CultureInfo(String, Boolean) para
crear un objeto CultureInfo que no refleje las personalizaciones de un sistema.
Propiedades de DateTimeFormatInfo
El formato se ve influenciado por las propiedades del objeto DateTimeFormatInfo actual, proporcionado
implícitamente por la referencia cultural del subproceso actual o explícitamente por el parámetro
IFormatProvider del método que invoca el formato. En el parámetro IFormatProvider, la aplicación debe
especificar un objeto CultureInfo, que representa una referencia cultural, o un objeto DateTimeFormatInfo, que
representa las convenciones de formato de fecha y hora de una determinada referencia cultural. Muchos de los
especificadores de formato de fecha y hora estándar son alias de patrones de formato definidos en las
propiedades del objeto DateTimeFormatInfo actual. La aplicación puede modificar el resultado generado por
algunos especificadores de formato de fecha y hora estándar al cambiar los patrones de formato de fecha y hora
correspondientes de la propiedad DateTimeFormatInfo apropiada.

Vea también
System.DateTime
System.DateTimeOffset
Aplicación de formato a tipos
Custom Date and Time Format Strings
Ejemplo: Utilidad de formato WinForms de .NET Core (C#)
Ejemplo: Utilidad de formato WinForms de .NET Core (Visual Basic)
Cadenas con formato de fecha y hora personalizado
13/01/2020 • 94 minutes to read • Edit Online

Una cadena con formato de fecha y hora define la representación de texto de un valor DateTime o
DateTimeOffset que es el resultado de una operación de formato. También puede definir la representación de un
valor de fecha y hora que se necesite en una operación de análisis para convertir correctamente la cadena en una
fecha y hora. Una cadena de formato personalizado consta de uno o varios especificadores de formato de fecha
y hora personalizado. Una cadena que no sea una cadena con formato de fecha y hora estándar se interpreta
como una cadena con formato de fecha y hora personalizado.

TIP
Puede descargar la Utilidad de formato, que es una aplicación de .NET Core Windows Forms que permite aplicar cadenas
de formato a valores numéricos o de fecha y hora, y que muestra la cadena de resultado. El código fuente está disponible
para C# y Visual Basic.

Las cadenas con formato de fecha y hora personalizado se pueden utilizar tanto con valores DateTime como con
valores DateTimeOffset.

NOTE
Algunos de los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET.
Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva. Una vez que se ejecuta el código,
puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar. El código modificado se ejecuta en la
ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes
de error del compilador de C#.
La zona horaria local del ejecutor de código en línea de Try.NET y del área de juegos es la hora universal coordinada o UTC.
Esto puede afectar al comportamiento y la salida de ejemplos que ilustran los tipos DateTime, DateTimeOffset y
TimeZoneInfo y sus miembros.

En operaciones de formato, las cadenas de formato de fecha y hora personalizado se pueden usar con el método
ToString de una instancia de fecha y hora o con un método que admita formato compuesto. En el ejemplo
siguiente se muestran ambos usos.

DateTime thisDate1 = new DateTime(2011, 6, 10);


Console.WriteLine("Today is " + thisDate1.ToString("MMMM dd, yyyy") + ".");

DateTimeOffset thisDate2 = new DateTimeOffset(2011, 6, 10, 15, 24, 16,


TimeSpan.Zero);
Console.WriteLine("The current date and time: {0:MM/dd/yy H:mm:ss zzz}",
thisDate2);
// The example displays the following output:
// Today is June 10, 2011.
// The current date and time: 06/10/11 15:24:16 +00:00
Dim thisDate1 As Date = #6/10/2011#
Console.WriteLine("Today is " + thisDate1.ToString("MMMM dd, yyyy") + ".")

Dim thisDate2 As New DateTimeOffset(2011, 6, 10, 15, 24, 16, TimeSpan.Zero)


Console.WriteLine("The current date and time: {0:MM/dd/yy H:mm:ss zzz}",
thisDate2)
' The example displays the following output:
' Today is June 10, 2011.
' The current date and time: 06/10/11 15:24:16 +00:00

En las operaciones de análisis, las cadenas de formato de fecha y hora personalizado se pueden usar con los
métodos DateTime.ParseExact, DateTime.TryParseExact, DateTimeOffset.ParseExact y
DateTimeOffset.TryParseExact. Estos métodos necesitan que una cadena de entrada se ajuste exactamente a un
modelo determinado para que la operación de análisis se realice correctamente. En el ejemplo siguiente se
muestra una llamada al método DateTimeOffset.ParseExact(String, String, IFormatProvider) para analizar una
fecha que debe incluir un día, un mes y un año de dos dígitos.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
string[] dateValues = { "30-12-2011", "12-30-2011",
"30-12-11", "12-30-11" };
string pattern = "MM-dd-yy";
DateTime parsedDate;

foreach (var dateValue in dateValues) {


if (DateTime.TryParseExact(dateValue, pattern, null,
DateTimeStyles.None, out parsedDate))
Console.WriteLine("Converted '{0}' to {1:d}.",
dateValue, parsedDate);
else
Console.WriteLine("Unable to convert '{0}' to a date and time.",
dateValue);
}
}
}
// The example displays the following output:
// Unable to convert '30-12-2011' to a date and time.
// Unable to convert '12-30-2011' to a date and time.
// Unable to convert '30-12-11' to a date and time.
// Converted '12-30-11' to 12/30/2011.
Imports System.Globalization

Module Example
Public Sub Main()
Dim dateValues() As String = { "30-12-2011", "12-30-2011",
"30-12-11", "12-30-11" }
Dim pattern As String = "MM-dd-yy"
Dim parsedDate As Date

For Each dateValue As String In dateValues


If DateTime.TryParseExact(dateValue, pattern, Nothing,
DateTimeStyles.None, parsedDate) Then
Console.WriteLine("Converted '{0}' to {1:d}.",
dateValue, parsedDate)
Else
Console.WriteLine("Unable to convert '{0}' to a date and time.",
dateValue)
End If
Next
End Sub
End Module
' The example displays the following output:
' Unable to convert '30-12-2011' to a date and time.
' Unable to convert '12-30-2011' to a date and time.
' Unable to convert '30-12-11' to a date and time.
' Converted '12-30-11' to 12/30/2011.

En la tabla siguiente se describen los especificadores de formato de fecha y hora personalizados, y se muestra la
cadena de resultado producida por cada especificador de formato. De forma predeterminada, las cadenas de
resultado reflejan las convenciones de formato de la referencia cultural en-us. Si un especificador de formato
determinado genera una cadena de resultado localizada, el ejemplo también indica la referencia cultural a la que
se aplica dicha cadena. Para más información sobre cómo usar cadenas de formato de fecha y hora
personalizado, vea la sección Notas.

ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"d" El día del mes, de 1 a 31. 2009-06-01T13:45:30 -> 1

Más información: Especificador de 2009-06-15T13:45:30 -> 15


formato personalizado "d".

"dd" El día del mes, de 01 a 31. 2009-06-01T13:45:30 -> 01

Más información: Especificador de 2009-06-15T13:45:30 -> 15


formato personalizado "dd".

"ddd" El nombre abreviado del día de la 2009-06-15T13:45:30 -> Mon (en-US)


semana.
2009-06-15T13:45:30 -> Пн (ru-RU)
Más información: Especificador de
formato personalizado "ddd". 2009-06-15T13:45:30 -> lun. (fr-FR)

"dddd" El nombre completo del día de la 2009-06-15T13:45:30 -> Monday (en-


semana. US)

Más información: Especificador de 2009-06-15T13:45:30 ->


formato personalizado "dddd". понедельник (ru-RU)

2009-06-15T13:45:30 -> lundi (fr-FR)


ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"f" Las décimas de segundo de un valor 2009-06-15T13:45:30.6170000 -> 6


de fecha y hora.
2009-06-15T13:45:30.05 -> 0
Más información: Especificador de
formato personalizado "f".

"ff" Las centésimas de segundo de un valor 2009-06-15T13:45:30.6170000 -> 61


de fecha y hora.
2009-06-15T13:45:30.0050000 -> 00
Más información: Especificador de
formato personalizado "ff".

"fff" Los milisegundos de un valor de fecha 6/15/2009 13:45:30.617 -> 617


y hora.
6/15/2009 13:45:30.0005 -> 000
Más información: Especificador de
formato personalizado "fff".

"ffff" Las diezmilésimas de segundo de un 2009-06-15T13:45:30.6175000 ->


valor de fecha y hora. 6175

Más información: Especificador de 2009-06-15T13:45:30.0000500 ->


formato personalizado "ffff". 0000

"fffff" Las cienmilésimas de segundo de un 2009-06-15T13:45:30.6175400 ->


valor de fecha y hora. 61754

Más información: Especificador de 6/15/2009 13:45:30.000005 -> 00000


formato personalizado "fffff".

"ffffff" Las millonésimas de segundo de un 2009-06-15T13:45:30.6175420 ->


valor de fecha y hora. 617542

Más información: Especificador de 2009-06-15T13:45:30.0000005 ->


formato personalizado "ffffff". 000000

"fffffff" Las diezmillonésimas de segundo de 2009-06-15T13:45:30.6175425 ->


un valor de fecha y hora. 6175425

Más información: Especificador de 2009-06-15T13:45:30.0001150 ->


formato personalizado "fffffff". 0001150

"F" Si es distinto de cero, las décimas de 2009-06-15T13:45:30.6170000 -> 6


segundo de un valor de fecha y hora.
2009-06-15T13:45:30.0500000 ->
Más información: Especificador de (ninguna salida)
formato personalizado "F".

"FF" Si es distinto de cero, las centésimas de 2009-06-15T13:45:30.6170000 -> 61


segundo de un valor de fecha y hora.
2009-06-15T13:45:30.0050000 ->
Más información: Especificador de (ninguna salida)
formato personalizado "FF".
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"FFF" Si es distinto de cero, los milisegundos 2009-06-15T13:45:30.6170000 ->


de un valor de fecha y hora. 617

Más información: Especificador de 2009-06-15T13:45:30.0005000 ->


formato personalizado "FFF". (ninguna salida)

"FFFF" Si es distinto de cero, las diezmilésimas 2009-06-15T13:45:30.5275000 ->


de segundo de un valor de fecha y 5275
hora.
2009-06-15T13:45:30.0000500 ->
Más información: Especificador de (ninguna salida)
formato personalizado "FFFF".

"FFFFF" Si es distinto de cero, las cienmilésimas 2009-06-15T13:45:30.6175400 ->


de segundo de un valor de fecha y 61754
hora.
2009-06-15T13:45:30.0000050 ->
Más información: Especificador de (ninguna salida)
formato personalizado "FFFFF".

"FFFFFF" Si es distinto de cero, las millonésimas 2009-06-15T13:45:30.6175420 ->


de segundo de un valor de fecha y 617542
hora.
2009-06-15T13:45:30.0000050 ->
Más información: Especificador de (ninguna salida)
formato personalizado "FFFFFF".

"FFFFFFF" Si es distinto de cero, las 2009-06-15T13:45:30.6175425 ->


diezmillonésimas de segundo de un 6175425
valor de fecha y hora.
2009-06-15T13:45:30.0001150 ->
Más información: Especificador de 000115
formato personalizado "FFFFFFF".

"g", "gg" El período o la era. 2009-06-15T13:45:30.6170000 ->


A.D.
Más información: Especificador de
formato personalizado "g" o "gg".

"h" La hora, usando un reloj de 12 horas 2009-06-15T01:45:30 -> 1


de 1 a 12.
2009-06-15T13:45:30 -> 1
Más información: Especificador de
formato personalizado "h".

"hh" La hora, usando un reloj de 12 horas 2009-06-15T01:45:30 -> 01


de 01 a 12.
2009-06-15T13:45:30 -> 01
Más información: Especificador de
formato personalizado "hh".

"H" La hora, usando un reloj de 24 horas 2009-06-15T01:45:30 -> 1


de 0 a 23.
2009-06-15T13:45:30 -> 13
Más información: Especificador de
formato personalizado "H".
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"HH" La hora, usando un reloj de 24 horas 2009-06-15T01:45:30 -> 01


de 00 a 23.
2009-06-15T13:45:30 -> 13
Más información: Especificador de
formato personalizado "HH".

"K" Información de la zona horaria. Con valores DateTime:

Más información: Especificador de 2009-06-15T13:45:30, Kind


formato personalizado "K". Unspecified ->

2009-06-15T13:45:30, Kind Utc -> Z

2009-06-15T13:45:30, Kind Local -> -


07:00 (depende de la configuración del
equipo local)

Con valores DateTimeOffset:

2009-06-15T01:45:30-07:00 --> -
07:00

2009-06-15T08:45:30+00:00 -->
+00:00

"m" Minutos, de 0 a 59. 2009-06-15T01:09:30 -> 9

Más información: Especificador de 2009-06-15T13:29:30 -> 29


formato personalizado "m".

"mm" El minuto, de 00 a 59. 2009-06-15T01:09:30 -> 09

Más información: Especificador de 2009-06-15T01:45:30 -> 45


formato personalizado "mm".

"M" El mes, de 1 a 12. 2009-06-15T13:45:30 -> 6

Más información: Especificador de


formato personalizado "M".

"MM" El mes, de 01 a 12. 2009-06-15T13:45:30 -> 06

Más información: Especificador de


formato personalizado "MM".

"MMM" El nombre abreviado del mes. 2009-06-15T13:45:30 -> Jun (en-US)

Más información: Especificador de 2009-06-15T13:45:30 -> juin (fr-FR)


formato personalizado "MMM".
2009-06-15T13:45:30 -> Jun (zu-ZA)

"MMMM" El nombre completo del mes. 2009-06-15T13:45:30 -> June (en-US)

Más información: Especificador de 2009-06-15T13:45:30 -> juni (da-DK)


formato personalizado "MMMM".
2009-06-15T13:45:30 -> uJuni (zu-
ZA)
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"s" El segundo, de 0 a 59. 2009-06-15T13:45:09 -> 9

Más información: Especificador de


formato personalizado "s".

"ss" El segundo, de 00 a 59. 2009-06-15T13:45:09 -> 09

Más información: Especificador de


formato personalizado "ss".

"t" El primer carácter del designador 2009-06-15T13:45:30 -> P (en-US)


AM/PM.
2009-06-15T13:45:30 -> 午 (ja-JP)
Más información: Especificador de
formato personalizado "t". 2009-06-15T13:45:30 -> (fr-FR)

"tt" El designador AM/PM. 2009-06-15T13:45:30 -> PM (en-US)

Más información: Especificador de 2009-06-15T13:45:30 -> 午後 (ja-JP)


formato personalizado "tt".
2009-06-15T13:45:30 -> (fr-FR)

"y" El año, de 0 a 99. 0001-01-01T00:00:00 -> 1

Más información: Especificador de 0900-01-01T00:00:00 -> 0


formato personalizado "y".
1900-01-01T00:00:00 -> 0

2009-06-15T13:45:30 -> 9

2019-06-15T13:45:30 -> 19

"yy" El año, de 00 a 99. 0001-01-01T00:00:00 -> 01

Más información: Especificador de 0900-01-01T00:00:00 -> 00


formato personalizado "yy".
1900-01-01T00:00:00 -> 00

2019-06-15T13:45:30 -> 19

"yyy" El año, con un mínimo de tres dígitos. 0001-01-01T00:00:00 -> 001

Más información: Especificador de 0900-01-01T00:00:00 -> 900


formato personalizado "yyy".
1900-01-01T00:00:00 -> 1900

2009-06-15T13:45:30 -> 2009

"yyyy" El año como un número de cuatro 0001-01-01T00:00:00 -> 0001


dígitos.
0900-01-01T00:00:00 -> 0900
Más información: Especificador de
formato personalizado "yyyy". 1900-01-01T00:00:00 -> 1900

2009-06-15T13:45:30 -> 2009


ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

"yyyyy" El año como un número de cinco 0001-01-01T00:00:00 -> 00001


dígitos.
2009-06-15T13:45:30 -> 02009
Más información: Especificador de
formato personalizado "yyyyy".

"z" Desfase de horas con respecto a la 2009-06-15T13:45:30-07:00 -> -7


hora UTC, sin ceros iniciales.

Más información: Especificador de


formato personalizado "z".

"zz" Desfase de horas con respecto a la 2009-06-15T13:45:30-07:00 -> -07


hora UTC, con un cero inicial para un
valor de un solo dígito.

Más información: Especificador de


formato personalizado "zz".

"zzz" Desfase de horas y minutos con 2009-06-15T13:45:30-07:00 -> -


respecto a la hora UTC. 07:00

Más información: Especificador de


formato personalizado "zzz".

":" El separador de hora. 2009-06-15T13:45:30 -> : (en-US)

Más información: Especificador de 2009-06-15T13:45:30 -> . (it-IT)


formato personalizado ":".
2009-06-15T13:45:30 -> : (ja-JP)

"/" El separador de fecha. 2009-06-15T13:45:30 -> / (en-US)

Más información: Especificador de 2009-06-15T13:45:30 -> - (ar-DZ)


formato personalizado "/".
2009-06-15T13:45:30 -> . (tr-TR)

"cadena" Delimitador de cadena literal. 2009-06-15T13:45:30 ("arr:" h:m t) ->


arr: 1:45 P
'cadena' Más información: Literales de carácter.
2009-06-15T13:45:30 ('arr:' h:m t) ->
arr: 1:45 P

% Define el siguiente carácter como un 2009-06-15T13:45:30 (%h) -> 1


especificador de formato
personalizado.

Más información:Usar especificadores


de formato personalizado únicos.

\ El carácter de escape. 2009-06-15T13:45:30 (h \h) -> 1 h

Más información: Literales de


caracteres y Usar el carácter de escape.
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLOS

Cualquier otro carácter El carácter se copia en la cadena de 2009-06-15T01:45:30 (arr hh:mm t) -


resultado sin modificar. > arr 01:45 A

Más información: Literales de carácter.

En las secciones siguientes se proporciona información adicional sobre cada especificador de formato de fecha y
hora personalizado. A menos que se indique lo contrario, cada especificador genera una representación de
cadena idéntica independientemente de que se use con un valor DateTime o DateTimeOffset.

Especificador de formato personalizado "d"


El especificador de formato personalizado "d" representa el día del mes como un número de 1 a 31. Un día con
un solo dígito tiene un formato sin un cero inicial.
Si el especificador de formato "d" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "d". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "d" en varias cadenas de formato.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15);

Console.WriteLine(date1.ToString("d, M",
CultureInfo.InvariantCulture));
// Displays 29, 8

Console.WriteLine(date1.ToString("d MMMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays 29 August
Console.WriteLine(date1.ToString("d MMMM",
CultureInfo.CreateSpecificCulture("es-MX")));
// Displays 29 agosto

Dim date1 As Date = #08/29/2008 7:27:15PM#

Console.WriteLine(date1.ToString("d, M", _
CultureInfo.InvariantCulture))
' Displays 29, 8

Console.WriteLine(date1.ToString("d MMMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays 29 August
Console.WriteLine(date1.ToString("d MMMM", _
CultureInfo.CreateSpecificCulture("es-MX")))
' Displays 29 agosto

Volver a la tabla

Especificador de formato personalizado "dd"


La cadena de formato personalizado "dd" representa el día del mes como un número de 01 a 31. Un día con un
solo dígito tiene un formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "dd" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(2008, 1, 2, 6, 30, 15);

Console.WriteLine(date1.ToString("dd, MM",
CultureInfo.InvariantCulture));
// 02, 01

Dim date1 As Date = #1/2/2008 6:30:15AM#

Console.WriteLine(date1.ToString("dd, MM", _
CultureInfo.InvariantCulture))
' 02, 01

Volver a la tabla

Especificador de formato personalizado "ddd"


El especificador de formato personalizado "ddd" representa el nombre abreviado del día de la semana. El
nombre abreviado adaptado del día de la semana se recupera de la propiedad
DateTimeFormatInfo.AbbreviatedDayNames de la referencia cultural actual o especificada.
En el ejemplo siguiente se incluye el especificador de formato personalizado "ddd" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15);

Console.WriteLine(date1.ToString("ddd d MMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Fri 29 Aug
Console.WriteLine(date1.ToString("ddd d MMM",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays ven. 29 août

Dim date1 As Date = #08/29/2008 7:27:15PM#

Console.WriteLine(date1.ToString("ddd d MMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Fri 29 Aug
Console.WriteLine(date1.ToString("ddd d MMM", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays ven. 29 août

Volver a la tabla

Especificador de formato personalizado "dddd"


El especificador de formato personalizado "dddd" (más cualquier número de especificadores "d" adicionales)
representa el nombre completo del día de la semana. El nombre adaptado del día de la semana se recupera de la
propiedad DateTimeFormatInfo.DayNames de la referencia cultural actual o especificada.
En el ejemplo siguiente se incluye el especificador de formato personalizado "dddd" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15);

Console.WriteLine(date1.ToString("dddd dd MMMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Friday 29 August
Console.WriteLine(date1.ToString("dddd dd MMMM",
CultureInfo.CreateSpecificCulture("it-IT")));
// Displays venerdì 29 agosto

Dim date1 As Date = #08/29/2008 7:27:15PM#

Console.WriteLine(date1.ToString("dddd dd MMMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Friday 29 August
Console.WriteLine(date1.ToString("dddd dd MMMM", _
CultureInfo.CreateSpecificCulture("it-IT")))
' Displays venerdì 29 agosto

Volver a la tabla

Especificador de formato personalizado "f"


El especificador de formato personalizado "f" representa el dígito más significativo de la fracción de segundos; es
decir, representa las décimas de segundo de un valor de fecha y hora.
Si el especificador de formato "f" se usa sin otros especificadores de formato, se interpreta como el especificador
de formato de fecha y hora estándar "f". Para más información sobre cómo usar un especificador de formato
único, vea Usar especificadores de formato personalizado únicos más adelante en este artículo.
Cuando se usan especificadores de formato "f" como parte de una cadena de formato que se proporciona a los
métodos ParseExact, TryParseExact, ParseExact u TryParseExact, el número de especificadores de formato "f"
indica el número de dígitos más significativos de la fracción de segundos que debe haber presentes para analizar
la cadena correctamente.
En el ejemplo siguiente se incluye el especificador de formato personalizado "f" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);


CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018
Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)
Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla

Especificador de formato personalizado "ff"


El especificador de formato personalizado "ff" representa los dos dígitos más significativos de la fracción de
segundos; es decir, representa las centésimas de segundo de un valor de fecha y hora.
En el ejemplo siguiente se incluye el especificador de formato personalizado "ff" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);


CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018

Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)


Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla
Especificador de formato personalizado "fff"
El especificador de formato personalizado "fff" representa los tres dígitos más significativos de la fracción de
segundos; es decir, representa los milisegundos de un valor de fecha y hora.
En el ejemplo siguiente se incluye el especificador de formato personalizado "fff" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);


CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018

Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)


Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla

Especificador de formato personalizado "ffff"


El especificador de formato personalizado "ffff" representa los cuatro dígitos más significativos de la fracción de
segundos; es decir, representa las diezmilésimas de segundo de un valor de fecha y hora.
Si bien se puede mostrar el componente correspondiente a las diezmilésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "fffff"


El especificador de formato personalizado "fffff" representa los cinco dígitos más significativos de la fracción de
segundo; es decir, representa las cienmilésimas de segundo de un valor de fecha y hora.
Si bien se puede mostrar el componente correspondiente a las cienmilésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "ffffff"


El especificador de formato personalizado "ffffff" representa los seis dígitos más significativos de la fracción de
segundos; es decir, representa las millonésimas de segundo de un valor de fecha y hora.
Si bien se puede mostrar el componente correspondiente a las millonésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "fffffff"


El especificador de formato personalizado "fffffff" representa los siete dígitos más significativos de la fracción de
segundos; es decir, representa las diezmillonésimas de segundo de un valor de fecha y hora.
Si bien se puede mostrar el componente correspondiente a las diezmillonésimas de segundo de un valor de
hora, es muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "F"


El especificador de formato personalizado "F" representa el dígito más significativo de la fracción de segundos;
es decir, representa las décimas de segundo de un valor de fecha y hora. Si el dígito es cero, no se muestra nada.
Si el especificador de formato "F" se usa sin otros especificadores de formato, se interpreta como el
especificador de formato de fecha y hora estándar "F". Para más información sobre cómo usar un especificador
de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este artículo.
El número de especificadores de formato "F" que se usan con los métodos ParseExact, TryParseExact, ParseExact
u TryParseExact indica el número máximo de dígitos más significativos de la fracción de segundos que pueden
estar presentes para analizar correctamente la cadena.
En el ejemplo siguiente se incluye el especificador de formato personalizado "F" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);
CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018

Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)


Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla

Especificador de formato personalizado "FF"


El especificador de formato personalizado "FF" representa los dos dígitos más significativos de la fracción de
segundos; es decir, representa las centésimas de segundo de un valor de fecha y hora. Sin embargo, no se
muestran los ceros finales ni los dígitos de dos ceros.
En el ejemplo siguiente se incluye el especificador de formato personalizado "FF" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);


CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018
Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)
Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla

Especificador de formato personalizado "FFF"


El especificador de formato personalizado "FFF" representa los tres dígitos más significativos de la fracción de
segundos; es decir, representa los milisegundos de un valor de fecha y hora. Sin embargo, no se muestran los
ceros finales ni los dígitos de tres ceros.
En el ejemplo siguiente se incluye el especificador de formato personalizado "FFF" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15, 18);


CultureInfo ci = CultureInfo.InvariantCulture;

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci));
// Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci));
// Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci));
// Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci));
// Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci));
// Displays 07:27:15.018

Dim date1 As New Date(2008, 8, 29, 19, 27, 15, 018)


Dim ci As CultureInfo = CultureInfo.InvariantCulture

Console.WriteLine(date1.ToString("hh:mm:ss.f", ci))
' Displays 07:27:15.0
Console.WriteLine(date1.ToString("hh:mm:ss.F", ci))
' Displays 07:27:15
Console.WriteLine(date1.ToString("hh:mm:ss.ff", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.FF", ci))
' Displays 07:27:15.01
Console.WriteLine(date1.ToString("hh:mm:ss.fff", ci))
' Displays 07:27:15.018
Console.WriteLine(date1.ToString("hh:mm:ss.FFF", ci))
' Displays 07:27:15.018

Volver a la tabla
Especificador de formato personalizado "FFFF"
El especificador de formato personalizado "FFFF" representa los cuatro dígitos más significativos de la fracción
de segundos; es decir, representa las diezmilésimas de segundo de un valor de fecha y hora. Sin embargo, no se
muestran los ceros finales ni los dígitos de cuatro ceros.
Si bien se puede mostrar el componente correspondiente a las diezmilésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "FFFFF"


El especificador de formato personalizado "FFFFF" representa los cinco dígitos más significativos de la fracción
de segundos; es decir, representa las cienmilésimas de segundo de un valor de fecha y hora. Sin embargo, no se
muestran los ceros finales ni los dígitos de cinco ceros.
Si bien se puede mostrar el componente correspondiente a las cienmilésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "FFFFFF"


El especificador de formato personalizado "FFFFFF" representa los seis dígitos más significativos de la fracción
de segundos; es decir, representa las millonésimas de segundo de un valor de fecha y hora. Sin embargo, no se
muestran los ceros finales ni los dígitos de seis ceros.
Si bien se puede mostrar el componente correspondiente a las millonésimas de segundo de un valor de hora, es
muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "FFFFFFF"


El especificador de formato personalizado "FFFFFFF" representa los siete dígitos más significativos de la
fracción de segundos; es decir, representa las diezmillonésimas de segundo de un valor de fecha y hora. Sin
embargo, no se muestran los ceros finales ni los dígitos de siete ceros.
Si bien se puede mostrar el componente correspondiente a las diezmillonésimas de segundo de un valor de
hora, es muy posible que ese valor no sea significativo. La precisión de los valores de fecha y hora depende de la
resolución del reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y
Windows Vista, la resolución del reloj es aproximadamente de 10 a 15 milisegundos.
Volver a la tabla

Especificador de formato personalizado "g" o "gg"


Los especificadores de formato personalizado "g" o "gg" (más cualquier número de especificadores "g"
adicionales) representan el período o la era, como d.C. La operación de formato hace caso omiso de este
especificador si la fecha a la que se va a dar formato no tiene una cadena de período o de era asociada.
Si el especificador de formato "g" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "g". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "g" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(70, 08, 04);

Console.WriteLine(date1.ToString("MM/dd/yyyy g",
CultureInfo.InvariantCulture));
// Displays 08/04/0070 A.D.
Console.WriteLine(date1.ToString("MM/dd/yyyy g",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays 08/04/0070 ap. J.-C.

Dim date1 As Date = #08/04/0070#

Console.WriteLine(date1.ToString("MM/dd/yyyy g", _
CultureInfo.InvariantCulture))
' Displays 08/04/0070 A.D.
Console.WriteLine(date1.ToString("MM/dd/yyyy g", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays 08/04/0070 ap. J.-C.

Volver a la tabla

Especificador de formato personalizado "h"


El especificador de formato personalizado "h" representa la hora como un número del 1 al 12; es decir, la hora se
representa como en un reloj de 12 horas que cuenta las horas enteras desde medianoche o mediodía. Una hora
determinada después de la medianoche no se distingue de la misma hora después del mediodía. No se
redondea la hora y las horas con un solo dígito no tienen un cero inicial. Por ejemplo, dada una hora de 5:43 de
la mañana o de la tarde, este especificador de formato personalizado muestra "5".
Si el especificador de formato "h" se usa sin otros especificadores de formato personalizado, se interpretará
como un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para
más información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "h" en una cadena de formato
personalizado.
DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1 µ
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1.5 µ

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1 µ
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1.5 µ

Volver a la tabla

Especificador de formato personalizado "hh"


El especificador de formato personalizado "hh" (más cualquier número de especificadores "h" adicionales)
representa la hora como un número del 01 al 12; es decir, la hora se representa como en un reloj de 12 horas
que cuenta las horas enteras desde medianoche o mediodía. Una hora determinada después de la medianoche
no se distingue de la misma hora después del mediodía. No se redondea la hora y las horas con un solo dígito
tienen un cero inicial. Por ejemplo, dada una hora de 5:43 de la mañana o de la tarde, este especificador de
formato muestra "05".
En el ejemplo siguiente se incluye el especificador de formato personalizado "hh" en una cadena de formato
personalizado.
DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01 du.
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01.50 du.

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01 du.
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01.50 du.

Volver a la tabla

Especificador de formato personalizado "H"


El especificador de formato personalizado "H" representa la hora como un número del 0 al 23; es decir, la hora se
representa como en un reloj de 24 horas de base cero que cuenta las horas desde medianoche. Una hora con un
solo dígito tiene un formato sin un cero inicial.
Si el especificador de formato "H" se usa sin otros especificadores de formato personalizado, se interpretará
como un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para
más información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "H" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 1, 1, 6, 9, 1);


Console.WriteLine(date1.ToString("H:mm:ss",
CultureInfo.InvariantCulture));
// Displays 6:09:01

Dim date1 As Date = #6:09:01AM#


Console.WriteLine(date1.ToString("H:mm:ss", _
CultureInfo.InvariantCulture))
' Displays 6:09:01
Volver a la tabla

Especificador de formato personalizado "HH"


El especificador de formato personalizado "HH" (más cualquier número de especificadores "H" adicionales)
representa la hora como un número del 00 al 23; es decir, la hora se representa como en un reloj de 24 horas de
base cero que cuenta las horas desde medianoche. Una hora con un solo dígito tiene un formato con un cero
inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "HH" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 1, 1, 6, 9, 1);


Console.WriteLine(date1.ToString("HH:mm:ss",
CultureInfo.InvariantCulture));
// Displays 06:09:01

Dim date1 As Date = #6:09:01AM#


Console.WriteLine(date1.ToString("HH:mm:ss", _
CultureInfo.InvariantCulture))
' Displays 06:09:01

Volver a la tabla

Especificador de formato personalizado "K"


El especificador de formato personalizado "K" representa la información de zona horaria de un valor de fecha y
hora. Cuando este formato se usa con valores DateTime, el valor de la propiedad DateTime.Kind define la
cadena de resultado.
En la zona horaria local (un valor de propiedad DateTime.Kind de DateTimeKind.Local), este especificador
es equivalente al especificador "zzz" y genera una cadena de resultado que contiene el desfase local con
respecto a la hora universal coordinada (UTC ); por ejemplo, "-07: 00".
En una hora UTC (un valor de propiedad DateTime.Kind de DateTimeKind.Utc), la cadena de resultado
incluye un carácter "Z" para representar una fecha UTC.
En una hora de una zona horaria no especificada (una hora cuya propiedad DateTime.Kind es igual a
DateTimeKind.Unspecified), el resultado es equivalente a String.Empty.
En los valores DateTimeOffset, el especificador de formato "K" es equivalente al especificador de formato "zzz" y
genera una cadena de resultado que contiene el desfase del valor DateTimeOffset con respecto a la hora UTC.
Si el especificador de formato "K" se usa sin otros especificadores de formato personalizado, se interpretará
como un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para
más información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
En el ejemplo siguiente se muestra la cadena que se obtiene al utilizar el especificador de formato personalizado
"K" con varios valores DateTime y DateTimeOffset en un sistema de la zona horaria del Pacífico de EE. UU.
Console.WriteLine(DateTime.Now.ToString("%K"));
// Displays -07:00
Console.WriteLine(DateTime.UtcNow.ToString("%K"));
// Displays Z
Console.WriteLine("'{0}'",
DateTime.SpecifyKind(DateTime.Now,
DateTimeKind.Unspecified).ToString("%K"));
// Displays ''
Console.WriteLine(DateTimeOffset.Now.ToString("%K"));
// Displays -07:00
Console.WriteLine(DateTimeOffset.UtcNow.ToString("%K"));
// Displays +00:00
Console.WriteLine(new DateTimeOffset(2008, 5, 1, 6, 30, 0,
new TimeSpan(5, 0, 0)).ToString("%K"));
// Displays +05:00

Console.WriteLine(Date.Now.ToString("%K"))
' Displays -07:00
Console.WriteLine(Date.UtcNow.ToString("%K"))
' Displays Z
Console.WriteLine("'{0}'", _
Date.SpecifyKind(Date.Now, _
DateTimeKind.Unspecified). _
ToString("%K"))
' Displays ''
Console.WriteLine(DateTimeOffset.Now.ToString("%K"))
' Displays -07:00
Console.WriteLine(DateTimeOffset.UtcNow.ToString("%K"))
' Displays +00:00
Console.WriteLine(New DateTimeOffset(2008, 5, 1, 6, 30, 0, _
New TimeSpan(5, 0, 0)). _
ToString("%K"))
' Displays +05:00

Volver a la tabla

Especificador de formato personalizado "m"


El especificador de formato personalizado "m" representa el minuto como un número de 0 a 59. El minuto
representa los minutos enteros que han transcurrido desde la última hora. Un minuto con un solo dígito tiene un
formato sin un cero inicial.
Si el especificador de formato "m" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "m". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "m" en una cadena de formato
personalizado.
DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1 µ
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1.5 µ

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1 µ
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1.5 µ

Volver a la tabla

Especificador de formato personalizado "mm"


El especificador de formato personalizado "mm" (más cualquier número de especificadores "m" adicionales)
representa el minuto como un número de 00 a 59. El minuto representa los minutos enteros que han
transcurrido desde la última hora. Un minuto con un solo dígito tiene un formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "mm" en una cadena de formato
personalizado.

DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01 du.
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01.50 du.
Dim date1 As Date
date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01 du.
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01.50 du.

Volver a la tabla

Especificador de formato personalizado "M"


El especificador de formato personalizado "M" representa el mes como un número del 1 al 12 (o del 1 al 13 para
los calendarios con 13 meses). Un mes con un solo dígito tiene un formato sin un cero inicial.
Si el especificador de formato "M" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "M". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "M" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 18);


Console.WriteLine(date1.ToString("(M) MMM, MMMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays (8) Aug, August
Console.WriteLine(date1.ToString("(M) MMM, MMMM",
CultureInfo.CreateSpecificCulture("nl-NL")));
// Displays (8) aug, augustus
Console.WriteLine(date1.ToString("(M) MMM, MMMM",
CultureInfo.CreateSpecificCulture("lv-LV")));
// Displays (8) Aug, augusts

Dim date1 As Date = #8/18/2008#


Console.WriteLine(date1.ToString("(M) MMM, MMMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays (8) Aug, August
Console.WriteLine(date1.ToString("(M) MMM, MMMM", _
CultureInfo.CreateSpecificCulture("nl-NL")))
' Displays (8) aug, augustus
Console.WriteLine(date1.ToString("(M) MMM, MMMM", _
CultureInfo.CreateSpecificCulture("lv-LV")))
' Displays (8) Aug, augusts

Volver a la tabla

Especificador de formato personalizado "MM"


El especificador de formato personalizado "MM" representa el mes como un número del 01 al 12 (o del 1 al 13
para los calendarios con 13 meses). Un mes con un solo dígito tiene un formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "MM" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 1, 2, 6, 30, 15);

Console.WriteLine(date1.ToString("dd, MM",
CultureInfo.InvariantCulture));
// 02, 01

Dim date1 As Date = #1/2/2008 6:30:15AM#

Console.WriteLine(date1.ToString("dd, MM", _
CultureInfo.InvariantCulture))
' 02, 01

Volver a la tabla

Especificador de formato personalizado "MMM"


El especificador de formato personalizado "MMM" representa el nombre abreviado del mes. El nombre
abreviado adaptado del mes se recupera de la propiedad DateTimeFormatInfo.AbbreviatedMonthNames de la
referencia cultural actual o especificada.
En el ejemplo siguiente se incluye el especificador de formato personalizado "MMM" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15);

Console.WriteLine(date1.ToString("ddd d MMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Fri 29 Aug
Console.WriteLine(date1.ToString("ddd d MMM",
CultureInfo.CreateSpecificCulture("fr-FR")));
// Displays ven. 29 août

Dim date1 As Date = #08/29/2008 7:27:15PM#

Console.WriteLine(date1.ToString("ddd d MMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Fri 29 Aug
Console.WriteLine(date1.ToString("ddd d MMM", _
CultureInfo.CreateSpecificCulture("fr-FR")))
' Displays ven. 29 août

Volver a la tabla

Especificador de formato personalizado "MMMM"


El especificador de formato personalizado "MMMM" representa el nombre completo del mes. El nombre
adaptado del mes se recupera de la propiedad DateTimeFormatInfo.MonthNames de la referencia cultural
actual o especificada.
En el ejemplo siguiente se incluye el especificador de formato personalizado "MMMM" en una cadena de
formato personalizado.
DateTime date1 = new DateTime(2008, 8, 29, 19, 27, 15);

Console.WriteLine(date1.ToString("dddd dd MMMM",
CultureInfo.CreateSpecificCulture("en-US")));
// Displays Friday 29 August
Console.WriteLine(date1.ToString("dddd dd MMMM",
CultureInfo.CreateSpecificCulture("it-IT")));
// Displays venerdì 29 agosto

Dim date1 As Date = #08/29/2008 7:27:15PM#

Console.WriteLine(date1.ToString("dddd dd MMMM", _
CultureInfo.CreateSpecificCulture("en-US")))
' Displays Friday 29 August
Console.WriteLine(date1.ToString("dddd dd MMMM", _
CultureInfo.CreateSpecificCulture("it-IT")))
' Displays venerdì 29 agosto

Volver a la tabla

Especificador de formato personalizado "s"


El especificador de formato personalizado "s" representa los segundos como un número de 0 a 59. El resultado
representa los segundos enteros que han transcurrido desde el último minuto. Un segundo con un solo dígito
tiene un formato sin un cero inicial.
Si el especificador de formato "s" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "s". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "s" en una cadena de formato
personalizado.

DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1 µ
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1.5 µ
Dim date1 As Date
date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1 µ
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1.5 µ

Volver a la tabla

Especificador de formato personalizado "ss"


El especificador de formato personalizado "ss" (más cualquier número de especificadores "s" adicionales)
representa los segundos como un número de 00 a 59. El resultado representa los segundos enteros que han
transcurrido desde el último minuto. Un segundo con un solo dígito tiene un formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "ss" en una cadena de formato
personalizado.

DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01 du.
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01.50 du.

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01 du.
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01.50 du.

Volver a la tabla
Especificador de formato personalizado "t"
El especificador de formato personalizado "t" representa el primer carácter del designador AM/PM. El
designador adaptado adecuado se recupera de la propiedad DateTimeFormatInfo.AMDesignator o
DateTimeFormatInfo.PMDesignator de la referencia cultural actual o especificada. El designador AM se usa para
todas las horas de 0:00:00 (medianoche) a 11:59:59.999. El designador PM se usa para todas las horas de
12:00:00 (mediodía) a 23:59:59.999.
Si el especificador de formato "t" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "t". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "t" en una cadena de formato
personalizado.

DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1 µ
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.InvariantCulture));
// Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t",
CultureInfo.CreateSpecificCulture("el-GR")));
// Displays 6:9:1.5 µ

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1 µ
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.InvariantCulture))
' Displays 6:9:1.5 P
Console.WriteLine(date1.ToString("h:m:s.F t", _
CultureInfo.CreateSpecificCulture("el-GR")))
' Displays 6:9:1.5 µ

Volver a la tabla

Especificador de formato personalizado "tt"


El especificador de formato personalizado "tt" (más cualquier número de especificadores "t" adicionales)
representa designador AM/PM completo. El designador adaptado adecuado se recupera de la propiedad
DateTimeFormatInfo.AMDesignator o DateTimeFormatInfo.PMDesignator de la referencia cultural actual o
especificada. El designador AM se usa para todas las horas de 0:00:00 (medianoche) a 11:59:59.999. El
designador PM se usa para todas las horas de 12:00:00 (mediodía) a 23:59:59.999.
Asegúrese de usar el especificador "tt" para aquellos idiomas en los que sea necesario mantener la distinción
entre a. m. y p. m. Un ejemplo es el japonés, en el que los designadores de a.m. y p.m. se diferencian en el
segundo carácter en vez de en el primero.
En el ejemplo siguiente se incluye el especificador de formato personalizado "tt" en una cadena de formato
personalizado.

DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01 du.
date1 = new DateTime(2008, 1, 1, 18, 9, 1, 500);
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt",
CultureInfo.CreateSpecificCulture("hu-HU")));
// Displays 06:09:01.50 du.

Dim date1 As Date


date1 = #6:09:01PM#
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01 PM
Console.WriteLine(date1.ToString("hh:mm:ss tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01 du.
date1 = New Date(2008, 1, 1, 18, 9, 1, 500)
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.InvariantCulture))
' Displays 06:09:01.50 PM
Console.WriteLine(date1.ToString("hh:mm:ss.ff tt", _
CultureInfo.CreateSpecificCulture("hu-HU")))
' Displays 06:09:01.50 du.

Volver a la tabla

Especificador de formato personalizado "y"


El especificador de formato personalizado "y" representa el año como un número de uno o dos dígitos. Si el año
tiene más de dos dígitos, en el resultado sólo aparecen los dos dígitos de orden inferior. Si el primer dígito de un
año de dos dígitos comienza con un cero (por ejemplo, 2008), se aplica formato al número sin el cero inicial.
Si el especificador de formato "y" se usa sin otros especificadores de formato personalizado, se interpretará
como el especificador de formato de fecha y hora estándar "y". Para más información sobre cómo usar un
especificador de formato único, vea Usar especificadores de formato personalizado únicos más adelante en este
artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "y" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(1, 12, 1);
DateTime date2 = new DateTime(2010, 1, 1);
Console.WriteLine(date1.ToString("%y"));
// Displays 1
Console.WriteLine(date1.ToString("yy"));
// Displays 01
Console.WriteLine(date1.ToString("yyy"));
// Displays 001
Console.WriteLine(date1.ToString("yyyy"));
// Displays 0001
Console.WriteLine(date1.ToString("yyyyy"));
// Displays 00001
Console.WriteLine(date2.ToString("%y"));
// Displays 10
Console.WriteLine(date2.ToString("yy"));
// Displays 10
Console.WriteLine(date2.ToString("yyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyyy"));
// Displays 02010

Dim date1 As Date = #12/1/0001#


Dim date2 As Date = #1/1/2010#
Console.WriteLine(date1.ToString("%y"))
' Displays 1
Console.WriteLine(date1.ToString("yy"))
' Displays 01
Console.WriteLine(date1.ToString("yyy"))
' Displays 001
Console.WriteLine(date1.ToString("yyyy"))
' Displays 0001
Console.WriteLine(date1.ToString("yyyyy"))
' Displays 00001
Console.WriteLine(date2.ToString("%y"))
' Displays 10
Console.WriteLine(date2.ToString("yy"))
' Displays 10
Console.WriteLine(date2.ToString("yyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyyy"))
' Displays 02010

Volver a la tabla

Especificador de formato personalizado "yy"


El especificador de formato personalizado "yy" representa el año como un número de dos dígitos. Si el año tiene
más de dos dígitos, en el resultado sólo aparecen los dos dígitos de orden inferior. Si el año de dos dígitos tiene
menos de dos dígitos significativos, el número se rellenará con ceros iniciales hasta obtener dos dígitos.
En una operación de análisis, un año de dos dígitos que se analiza mediante el especificador de formato
personalizado “yy” se interpreta basándose en la propiedad de Calendar.TwoDigitYearMax del calendario actual
del proveedor de formato. En el ejemplo siguiente se analiza la representación en forma de cadena de una fecha
con un año de dos dígitos utilizando el calendario gregoriano predeterminado de la referencia cultural actual (en
este caso, en-US ). Modifica el objeto CultureInfo de la referencia cultural actual para utilizar un objeto
GregorianCalendar cuya propiedad TwoDigitYearMax se ha modificado.
using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
string fmt = "dd-MMM-yy";
string value = "24-Jan-49";

Calendar cal = (Calendar) CultureInfo.CurrentCulture.Calendar.Clone();


Console.WriteLine("Two Digit Year Range: {0} - {1}",
cal.TwoDigitYearMax - 99, cal.TwoDigitYearMax);

Console.WriteLine("{0:d}", DateTime.ParseExact(value, fmt, null));


Console.WriteLine();

cal.TwoDigitYearMax = 2099;
CultureInfo culture = (CultureInfo) CultureInfo.CurrentCulture.Clone();
culture.DateTimeFormat.Calendar = cal;
Thread.CurrentThread.CurrentCulture = culture;

Console.WriteLine("Two Digit Year Range: {0} - {1}",


cal.TwoDigitYearMax - 99, cal.TwoDigitYearMax);
Console.WriteLine("{0:d}", DateTime.ParseExact(value, fmt, null));
}
}
// The example displays the following output:
// Two Digit Year Range: 1930 - 2029
// 1/24/1949
//
// Two Digit Year Range: 2000 - 2099
// 1/24/2049
Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim fmt As String = "dd-MMM-yy"
Dim value As String = "24-Jan-49"

Dim cal As Calendar = CType(CultureInfo.CurrentCulture.Calendar.Clone(), Calendar)


Console.WriteLine("Two Digit Year Range: {0} - {1}",
cal.TwoDigitYearMax - 99, cal.TwoDigitYearMax)

Console.WriteLine("{0:d}", DateTime.ParseExact(value, fmt, Nothing))


Console.WriteLine()

cal.TwoDigitYearMax = 2099
Dim culture As CultureInfo = CType(CultureInfo.CurrentCulture.Clone(), CultureInfo)
culture.DateTimeFormat.Calendar = cal
Thread.CurrentThread.CurrentCulture = culture

Console.WriteLine("Two Digit Year Range: {0} - {1}",


cal.TwoDigitYearMax - 99, cal.TwoDigitYearMax)
Console.WriteLine("{0:d}", DateTime.ParseExact(value, fmt, Nothing))
End Sub
End Module
' The example displays the following output:
' Two Digit Year Range: 1930 - 2029
' 1/24/1949
'
' Two Digit Year Range: 2000 - 2099
' 1/24/2049

En el ejemplo siguiente se incluye el especificador de formato personalizado "yy" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(1, 12, 1);


DateTime date2 = new DateTime(2010, 1, 1);
Console.WriteLine(date1.ToString("%y"));
// Displays 1
Console.WriteLine(date1.ToString("yy"));
// Displays 01
Console.WriteLine(date1.ToString("yyy"));
// Displays 001
Console.WriteLine(date1.ToString("yyyy"));
// Displays 0001
Console.WriteLine(date1.ToString("yyyyy"));
// Displays 00001
Console.WriteLine(date2.ToString("%y"));
// Displays 10
Console.WriteLine(date2.ToString("yy"));
// Displays 10
Console.WriteLine(date2.ToString("yyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyyy"));
// Displays 02010
Dim date1 As Date = #12/1/0001#
Dim date2 As Date = #1/1/2010#
Console.WriteLine(date1.ToString("%y"))
' Displays 1
Console.WriteLine(date1.ToString("yy"))
' Displays 01
Console.WriteLine(date1.ToString("yyy"))
' Displays 001
Console.WriteLine(date1.ToString("yyyy"))
' Displays 0001
Console.WriteLine(date1.ToString("yyyyy"))
' Displays 00001
Console.WriteLine(date2.ToString("%y"))
' Displays 10
Console.WriteLine(date2.ToString("yy"))
' Displays 10
Console.WriteLine(date2.ToString("yyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyyy"))
' Displays 02010

Volver a la tabla

Especificador de formato personalizado "yyy"


El especificador de formato personalizado "yyy" representa el año con un mínimo de tres dígitos. Si el año tiene
más de tres dígitos significativos, se incluyen en la cadena de resultado. Si el año tiene menos de tres dígitos, el
número se rellenará con ceros iniciales hasta obtener tres dígitos.

NOTE
Para el calendario budista tailandés, que puede tener años de cinco dígitos, este especificador de formato muestra todos
los dígitos significativos.

En el ejemplo siguiente se incluye el especificador de formato personalizado "yyy" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(1, 12, 1);
DateTime date2 = new DateTime(2010, 1, 1);
Console.WriteLine(date1.ToString("%y"));
// Displays 1
Console.WriteLine(date1.ToString("yy"));
// Displays 01
Console.WriteLine(date1.ToString("yyy"));
// Displays 001
Console.WriteLine(date1.ToString("yyyy"));
// Displays 0001
Console.WriteLine(date1.ToString("yyyyy"));
// Displays 00001
Console.WriteLine(date2.ToString("%y"));
// Displays 10
Console.WriteLine(date2.ToString("yy"));
// Displays 10
Console.WriteLine(date2.ToString("yyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyyy"));
// Displays 02010

Dim date1 As Date = #12/1/0001#


Dim date2 As Date = #1/1/2010#
Console.WriteLine(date1.ToString("%y"))
' Displays 1
Console.WriteLine(date1.ToString("yy"))
' Displays 01
Console.WriteLine(date1.ToString("yyy"))
' Displays 001
Console.WriteLine(date1.ToString("yyyy"))
' Displays 0001
Console.WriteLine(date1.ToString("yyyyy"))
' Displays 00001
Console.WriteLine(date2.ToString("%y"))
' Displays 10
Console.WriteLine(date2.ToString("yy"))
' Displays 10
Console.WriteLine(date2.ToString("yyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyyy"))
' Displays 02010

Volver a la tabla

Especificador de formato personalizado "yyyy"


El especificador de formato personalizado "Yyyy" representa el año con un mínimo de cuatro dígitos. Si el año
tiene más de cuatro dígitos significativos, se incluyen en la cadena resultante. Si el año tiene menos de cuatro
dígitos, el número se completa con ceros iniciales hasta obtener cuatro dígitos.

NOTE
En el calendario budista tailandés, que puede tener años de cinco dígitos, este especificador de formato muestra un
mínimo de cuatro dígitos.

En el ejemplo siguiente se incluye el especificador de formato personalizado "yyyy" en una cadena de formato
personalizado.

DateTime date1 = new DateTime(1, 12, 1);


DateTime date2 = new DateTime(2010, 1, 1);
Console.WriteLine(date1.ToString("%y"));
// Displays 1
Console.WriteLine(date1.ToString("yy"));
// Displays 01
Console.WriteLine(date1.ToString("yyy"));
// Displays 001
Console.WriteLine(date1.ToString("yyyy"));
// Displays 0001
Console.WriteLine(date1.ToString("yyyyy"));
// Displays 00001
Console.WriteLine(date2.ToString("%y"));
// Displays 10
Console.WriteLine(date2.ToString("yy"));
// Displays 10
Console.WriteLine(date2.ToString("yyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyyy"));
// Displays 02010

Dim date1 As Date = #12/1/0001#


Dim date2 As Date = #1/1/2010#
Console.WriteLine(date1.ToString("%y"))
' Displays 1
Console.WriteLine(date1.ToString("yy"))
' Displays 01
Console.WriteLine(date1.ToString("yyy"))
' Displays 001
Console.WriteLine(date1.ToString("yyyy"))
' Displays 0001
Console.WriteLine(date1.ToString("yyyyy"))
' Displays 00001
Console.WriteLine(date2.ToString("%y"))
' Displays 10
Console.WriteLine(date2.ToString("yy"))
' Displays 10
Console.WriteLine(date2.ToString("yyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyyy"))
' Displays 02010

Volver a la tabla

Especificador de formato personalizado "yyyyy"


El especificador de formato personalizado "yyyyy" (más cualquier número de especificadores "y" adicionales)
representa el año con un mínimo de cinco dígitos. Si el año tiene más de cinco dígitos significativos, se incluyen
en la cadena resultante. Si el año tiene menos de cinco dígitos, el número se rellenará con ceros iniciales hasta
obtener cinco dígitos.
Si hay especificadores "y" adicionales, el número se rellenará con tantos ceros iniciales como sean necesarios
para obtener el número de especificadores "y".
En el ejemplo siguiente se incluye el especificador de formato personalizado "yyyyy" en una cadena de formato
personalizado.
DateTime date1 = new DateTime(1, 12, 1);
DateTime date2 = new DateTime(2010, 1, 1);
Console.WriteLine(date1.ToString("%y"));
// Displays 1
Console.WriteLine(date1.ToString("yy"));
// Displays 01
Console.WriteLine(date1.ToString("yyy"));
// Displays 001
Console.WriteLine(date1.ToString("yyyy"));
// Displays 0001
Console.WriteLine(date1.ToString("yyyyy"));
// Displays 00001
Console.WriteLine(date2.ToString("%y"));
// Displays 10
Console.WriteLine(date2.ToString("yy"));
// Displays 10
Console.WriteLine(date2.ToString("yyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyy"));
// Displays 2010
Console.WriteLine(date2.ToString("yyyyy"));
// Displays 02010

Dim date1 As Date = #12/1/0001#


Dim date2 As Date = #1/1/2010#
Console.WriteLine(date1.ToString("%y"))
' Displays 1
Console.WriteLine(date1.ToString("yy"))
' Displays 01
Console.WriteLine(date1.ToString("yyy"))
' Displays 001
Console.WriteLine(date1.ToString("yyyy"))
' Displays 0001
Console.WriteLine(date1.ToString("yyyyy"))
' Displays 00001
Console.WriteLine(date2.ToString("%y"))
' Displays 10
Console.WriteLine(date2.ToString("yy"))
' Displays 10
Console.WriteLine(date2.ToString("yyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyy"))
' Displays 2010
Console.WriteLine(date2.ToString("yyyyy"))
' Displays 02010

Volver a la tabla

Especificador de formato personalizado "z"


Con valores DateTime, el especificador de formato personalizado "z" representa el desfase con signo de la zona
horaria del sistema operativo local respecto a la hora universal coordinada (UTC ), medido en horas. No refleja el
valor de la propiedad DateTime.Kind de una instancia. Por esta razón, no se recomienda usar el especificador de
formato "z" con valores DateTime.
Con valores DateTimeOffset, este especificador de formato representa el desfase en horas del valor
DateTimeOffset con respecto a la hora UTC.
La diferencia horaria se muestra siempre con un signo inicial. Un signo más (+) indica las horas de adelanto y un
signo menos (-) indica las horas de retraso con respecto a la hora UTC. Un desfase con un solo dígito tiene un
formato sin un cero inicial.
Si el especificador de formato "z" se usa sin otros especificadores de formato personalizado, se interpretará
como un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para
más información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
En el ejemplo siguiente se incluye el especificador de formato personalizado "z" en una cadena de formato
personalizado.

DateTime date1 = DateTime.UtcNow;


Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date1));
// Displays -7, -07, -07:00

DateTimeOffset date2 = new DateTimeOffset(2008, 8, 1, 0, 0, 0,


new TimeSpan(6, 0, 0));
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date2));
// Displays +6, +06, +06:00

Dim date1 As Date = Date.UtcNow


Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date1))
' Displays -7, -07, -07:00

Dim date2 As New DateTimeOffset(2008, 8, 1, 0, 0, 0, _


New Timespan(6, 0, 0))
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date2))
' Displays +6, +06, +06:00

Volver a la tabla

Especificador de formato personalizado "zz"


Con valores DateTime, el especificador de formato personalizado "zz" representa el desfase con signo de la zona
horaria del sistema operativo local respecto a la hora UTC, medido en horas. No refleja el valor de la propiedad
DateTime.Kind de una instancia. Por esta razón, no se recomienda usar el especificador de formato "zz" con
valores DateTime.
Con valores DateTimeOffset, este especificador de formato representa el desfase en horas del valor
DateTimeOffset con respecto a la hora UTC.
La diferencia horaria se muestra siempre con un signo inicial. Un signo más (+) indica las horas de adelanto y un
signo menos (-) indica las horas de retraso con respecto a la hora UTC. Un desfase con un solo dígito tiene un
formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "zz" en una cadena de formato
personalizado.
DateTime date1 = DateTime.UtcNow;
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date1));
// Displays -7, -07, -07:00

DateTimeOffset date2 = new DateTimeOffset(2008, 8, 1, 0, 0, 0,


new TimeSpan(6, 0, 0));
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date2));
// Displays +6, +06, +06:00

Dim date1 As Date = Date.UtcNow


Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date1))
' Displays -7, -07, -07:00

Dim date2 As New DateTimeOffset(2008, 8, 1, 0, 0, 0, _


New Timespan(6, 0, 0))
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date2))
' Displays +6, +06, +06:00

Volver a la tabla

Especificador de formato personalizado "zzz"


Con valores DateTime, el especificador de formato personalizado "zzz" representa el desfase con signo de la
zona horaria del sistema operativo local respecto a la hora UTC, medido en horas y minutos. No refleja el valor
de la propiedad DateTime.Kind de una instancia. Por esta razón, no se recomienda usar el especificador de
formato "zzz" con valores DateTime.
Con valores DateTimeOffset, este especificador de formato representa el desfase en horas y minutos del valor
DateTimeOffset con respecto a la hora UTC.
La diferencia horaria se muestra siempre con un signo inicial. Un signo más (+) indica las horas de adelanto y un
signo menos (-) indica las horas de retraso con respecto a la hora UTC. Un desfase con un solo dígito tiene un
formato con un cero inicial.
En el ejemplo siguiente se incluye el especificador de formato personalizado "zzz" en una cadena de formato
personalizado.

DateTime date1 = DateTime.UtcNow;


Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date1));
// Displays -7, -07, -07:00

DateTimeOffset date2 = new DateTimeOffset(2008, 8, 1, 0, 0, 0,


new TimeSpan(6, 0, 0));
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}",
date2));
// Displays +6, +06, +06:00
Dim date1 As Date = Date.UtcNow
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date1))
' Displays -7, -07, -07:00

Dim date2 As New DateTimeOffset(2008, 8, 1, 0, 0, 0, _


New Timespan(6, 0, 0))
Console.WriteLine(String.Format("{0:%z}, {0:zz}, {0:zzz}", _
date2))
' Displays +6, +06, +06:00

Volver a la tabla

Especificador de formato personalizado ":"


El especificador de formato personalizado ":" representa el separador de hora, que se usa para diferenciar horas,
minutos y segundos. El separador de hora adaptado adecuado se recupera de la propiedad
DateTimeFormatInfo.TimeSeparator de la referencia cultural actual o especificada.

NOTE
Para cambiar el separador de hora en una determinada cadena de fecha y hora, especifique el carácter separador en un
delimitador de cadena literal. Por ejemplo, la cadena de formato personalizado hh'_'dd'_'ss genera una cadena en que
"_" (guion bajo) siempre se utiliza como separador de hora. Para cambiar el separador de hora en todas las fechas de una
referencia cultural, cambie el valor de la propiedad DateTimeFormatInfo.TimeSeparator de la referencia cultural actual, o
cree una instancia de un objeto DateTimeFormatInfo, asigne el carácter a su propiedad TimeSeparator y llame a una
sobrecarga del método de formato que incluya un parámetro IFormatProvider.

Si el especificador de formato ":" se usa sin otros especificadores de formato personalizado, se interpretará como
un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para más
información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
Volver a la tabla

Especificador de formato personalizado "/"


El especificador de formato personalizado "/" representa el separador de fecha, que se usa para diferenciar años,
meses y días. El separador de fecha adaptado adecuado se recupera de la propiedad
DateTimeFormatInfo.DateSeparator de la referencia cultural actual o especificada.

NOTE
Para cambiar el separador de fecha en una determinada cadena de fecha y hora, especifique el carácter separador en un
delimitador de cadena literal. Por ejemplo, la cadena de formato personalizado mm'/'dd'/'yyyy genera una cadena en
que "/" siempre se utiliza como separador de fecha. Para cambiar el separador de fecha en todas las fechas de una
referencia cultural, cambie el valor de la propiedad DateTimeFormatInfo.DateSeparator de la referencia cultural actual, o
cree una instancia de un objeto DateTimeFormatInfo, asigne el carácter a su propiedad DateSeparator y llame a una
sobrecarga del método de formato que incluya un parámetro IFormatProvider.

Si el especificador de formato "/" se usa sin otros especificadores de formato personalizado, se interpretará
como un especificador de formato de fecha y hora estándar y producirá una excepción FormatException. Para
más información sobre cómo usar un especificador de formato único, vea Usar especificadores de formato
personalizado únicos más adelante en este artículo.
Volver a la tabla

Literales de carácter
Los siguientes caracteres de una cadena de formato de fecha y hora personalizado están reservados y siempre
se interpretan como caracteres de formato o, en el caso de ", ', / y \, como caracteres especiales.

F H K M d

f e h m s

m y z % :

/ " ' \

Todos los demás caracteres se interpretan siempre como literales de carácter y, en una operación de formato, se
incluyen en la cadena de resultado sin modificar. En una operación de análisis, deben coincidir exactamente con
los caracteres de la cadena de entrada; la comparación distingue entre mayúsculas y minúsculas.
En el ejemplo siguiente se incluyen los caracteres literales "PST" (para hora estándar del Pacífico) y "PDT" (para
horario de verano del Pacífico) para representar la zona horaria local en una cadena de formato. Tenga en cuenta
que la cadena se incluye en la cadena de resultado y que una cadena que incluye la cadena de zona horaria local
también se analiza correctamente.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
String[] formats = { "dd MMM yyyy hh:mm tt PST",
"dd MMM yyyy hh:mm tt PDT" };
var dat = new DateTime(2016, 8, 18, 16, 50, 0);
// Display the result string.
Console.WriteLine(dat.ToString(formats[1]));

// Parse a string.
String value = "25 Dec 2016 12:00 pm PST";
DateTime newDate;
if (DateTime.TryParseExact(value, formats, null,
DateTimeStyles.None, out newDate))
Console.WriteLine(newDate);
else
Console.WriteLine("Unable to parse '{0}'", value);
}
}
// The example displays the following output:
// 18 Aug 2016 04:50 PM PDT
// 12/25/2016 12:00:00 PM
Imports System.Globalization

Module Example
Public Sub Main()
Dim formats() As String = { "dd MMM yyyy hh:mm tt PST",
"dd MMM yyyy hh:mm tt PDT" }
Dim dat As New Date(2016, 8, 18, 16, 50, 0)
' Display the result string.
Console.WriteLine(dat.ToString(formats(1)))

' Parse a string.


Dim value As String = "25 Dec 2016 12:00 pm PST"
Dim newDate As Date
If Date.TryParseExact(value, formats, Nothing,
DateTimeStyles.None, newDate) Then
Console.WriteLine(newDate)
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If
End Sub
End Module
' The example displays the following output:
' 18 Aug 2016 04:50 PM PDT
' 12/25/2016 12:00:00 PM

Hay dos formas de indicar que los caracteres se han de interpretar como caracteres literales y no como
caracteres de reserva, para que se puedan incluir en una cadena de resultado o analizarse correctamente en una
cadena de entrada:
Al incluir un escape con cada carácter reservado. Para obtener más información, consulte Usar el carácter de
escape.
En el ejemplo siguiente se incluyen los caracteres literales "pst" (para hora estándar del Pacífico) para
representar la zona horaria local en una cadena de formato. Como "s" y "t" son cadenas de formato
personalizado, ambos caracteres deben incluir un escape para interpretarse como literales de carácter.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
String format = "dd MMM yyyy hh:mm tt p\\s\\t";
var dat = new DateTime(2016, 8, 18, 16, 50, 0);
// Display the result string.
Console.WriteLine(dat.ToString(format));

// Parse a string.
String value = "25 Dec 2016 12:00 pm pst";
DateTime newDate;
if (DateTime.TryParseExact(value, format, null,
DateTimeStyles.None, out newDate))
Console.WriteLine(newDate);
else
Console.WriteLine("Unable to parse '{0}'", value);
}
}
// The example displays the following output:
// 18 Aug 2016 04:50 PM PDT
// 12/25/2016 12:00:00 PM
Imports System.Globalization

Module Example
Public Sub Main()
Dim fmt As String = "dd MMM yyyy hh:mm tt p\s\t"
Dim dat As New Date(2016, 8, 18, 16, 50, 0)
' Display the result string.
Console.WriteLine(dat.ToString(fmt))

' Parse a string.


Dim value As String = "25 Dec 2016 12:00 pm pst"
Dim newDate As Date
If Date.TryParseExact(value, fmt, Nothing,
DateTimeStyles.None, newDate) Then
Console.WriteLine(newDate)
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If
End Sub
End Module
' The example displays the following output:
' 18 Aug 2016 04:50 PM pst
' 12/25/2016 12:00:00 PM

Al incluir toda la cadena literal entre comillas o apóstrofes. El siguiente ejemplo es igual al anterior, excepto
que "pst" se incluye entre comillas para indicar que toda la cadena delimitada debe interpretarse como
literales de carácter.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
String format = "dd MMM yyyy hh:mm tt \"pst\"";
var dat = new DateTime(2016, 8, 18, 16, 50, 0);
// Display the result string.
Console.WriteLine(dat.ToString(format));

// Parse a string.
String value = "25 Dec 2016 12:00 pm pst";
DateTime newDate;
if (DateTime.TryParseExact(value, format, null,
DateTimeStyles.None, out newDate))
Console.WriteLine(newDate);
else
Console.WriteLine("Unable to parse '{0}'", value);
}
}
// The example displays the following output:
// 18 Aug 2016 04:50 PM PDT
// 12/25/2016 12:00:00 PM
Imports System.Globalization

Module Example
Public Sub Main()
Dim fmt As String = "dd MMM yyyy hh:mm tt ""pst"""
Dim dat As New Date(2016, 8, 18, 16, 50, 0)
' Display the result string.
Console.WriteLine(dat.ToString(fmt))

' Parse a string.


Dim value As String = "25 Dec 2016 12:00 pm pst"
Dim newDate As Date
If Date.TryParseExact(value, fmt, Nothing,
DateTimeStyles.None, newDate) Then
Console.WriteLine(newDate)
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If
End Sub
End Module
' The example displays the following output:
' 18 Aug 2016 04:50 PM pst
' 12/25/2016 12:00:00 PM

Notas
Usar especificadores de formato personalizado únicos
Una cadena con formato de fecha y hora personalizado se compone de dos o más caracteres. Los métodos de
formato de fecha y hora interpretan cualquier cadena de un único carácter como una cadena de formato de
fecha y hora estándar. Si no reconocen el carácter como un especificador de formato válido, producen una
excepción FormatException. Por ejemplo, una cadena de formato que solo se compone del especificador "h" se
interpreta como una cadena de formato de fecha y hora estándar. Sin embargo, en este caso concreto, se
produce una excepción porque no existe ningún especificador de formato de fecha y hora estándar "h".
Para usar cualquiera de los especificadores de formato de fecha y hora personalizado como el único
especificador en una cadena de formato (es decir, usar el especificador de formato personalizado "d", "f", "F", "g",
"h", "H", "K", "m", "M", "s", "t", "y", "z", ":" o "/"), incluya un espacio delante o detrás del especificador, o incluya un
especificador de formato de porcentaje ("%") delante del único especificador de fecha y hora personalizado.
Por ejemplo, " %h" se interpreta como una cadena de formato de fecha y hora personalizado que muestra la
hora representada por el valor de fecha y hora actual. También puede usar la cadena de formato " h" o "h ",
aunque esto incluye un espacio en la cadena de resultado junto con la hora. En el ejemplo siguiente se muestran
estas tres cadenas de formato.

DateTime dat1 = new DateTime(2009, 6, 15, 13, 45, 0);

Console.WriteLine("'{0:%h}'", dat1);
Console.WriteLine("'{0: h}'", dat1);
Console.WriteLine("'{0:h }'", dat1);
// The example displays the following output:
// '1'
// ' 1'
// '1 '
Dim dat1 As Date = #6/15/2009 1:45PM#

Console.WriteLine("'{0:%h}'", dat1)
Console.WriteLine("'{0: h}'", dat1)
Console.WriteLine("'{0:h }'", dat1)
' The example displays the following output:
' '1'
' ' 1'
' '1 '

Usar el carácter de escape


Los caracteres "d", "f", "F", "g", "h", "H", "K", "m", "M", "s", "t", "y", "z", ":" o "/" en una cadena de formato se
interpretan como especificadores de formato personalizado en lugar de como caracteres literales. Para evitar que
un carácter se interprete como un especificador de formato, puede precederlo de una barra diagonal inversa (\),
que es el carácter de escape. El carácter de escape significa que el siguiente carácter es un carácter literal que se
debe incluir en la cadena de resultado sin modificar.
Para incluir una barra diagonal inversa en una cadena de resultado, debe indicar su secuencia de escape con otra
barra diagonal inversa ( \\ ).

NOTE
Algunos compiladores, como los compiladores de C# y C++, también pueden interpretar un único carácter de barra
diagonal inversa como un carácter de escape. Para asegurarse de que una cadena se interpreta correctamente al darle
formato, puede usar el carácter literal de cadena textual (el carácter @) antes de la cadena en C# o puede agregar otro
carácter de barra diagonal inversa delante de cada barra diagonal inversa en C# y C++. En el siguiente ejemplo de C# se
muestran ambos enfoques.

En el ejemplo siguiente se usa el carácter de escape para evitar que la operación de formato interprete los
caracteres "h" y "m" como especificadores de formato.

DateTime date = new DateTime(2009, 06, 15, 13, 45, 30, 90);
string fmt1 = "h \\h m \\m";
string fmt2 = @"h \h m \m";

Console.WriteLine("{0} ({1}) -> {2}", date, fmt1, date.ToString(fmt1));


Console.WriteLine("{0} ({1}) -> {2}", date, fmt2, date.ToString(fmt2));
// The example displays the following output:
// 6/15/2009 1:45:30 PM (h \h m \m) -> 1 h 45 m
// 6/15/2009 1:45:30 PM (h \h m \m) -> 1 h 45 m

Dim date1 As Date = #6/15/2009 13:45#


Dim fmt As String = "h \h m \m"

Console.WriteLine("{0} ({1}) -> {2}", date1, fmt, date1.ToString(fmt))


' The example displays the following output:
' 6/15/2009 1:45:00 PM (h \h m \m) -> 1 h 45 m

Configuración del Panel de control


La configuración de Configuración regional y de idioma del Panel de control influye en la cadena de
resultado generada por una operación de formato que incluye muchos de los especificadores de formato de
fecha y hora personalizado. Estas configuraciones se utilizan para inicializar el objeto DateTimeFormatInfo
asociado a la referencia cultural del subproceso actual, que proporciona valores que se utilizan para controlar el
formato. Los equipos que usan configuraciones diferentes generarán cadenas de resultado distintas.
Asimismo, si se usa el constructor CultureInfo.CultureInfo(String) para crear instancias de un nuevo objeto
CultureInfo que representa la misma referencia cultural que la referencia cultural del sistema actual, cualquier
personalización establecida por el elemento Configuración regional y de idioma del Panel de control se
aplicará al nuevo objeto CultureInfo . Puede usar el constructor CultureInfo.CultureInfo(String, Boolean) para
crear un objeto CultureInfo que no refleje las personalizaciones de un sistema.
Propiedades de DateTimeFormatInfo
El formato se ve influenciado por las propiedades del objeto DateTimeFormatInfo actual, proporcionado
implícitamente por la referencia cultural del subproceso actual o explícitamente por el parámetro
IFormatProvider del método que invoca el formato. Para el parámetro IFormatProvider, debe especificar un
objeto CultureInfo, que representa una referencia cultural, o un objeto DateTimeFormatInfo.
La cadena de resultado generada por muchos de los especificadores de formato de fecha y hora personalizado
también depende de las propiedades del objeto DateTimeFormatInfo actual. La aplicación puede modificar el
resultado generado por algunos de los especificadores de formato de fecha y hora personalizado al cambiar la
propiedad DateTimeFormatInfo correspondiente. Por ejemplo, el especificador de formato "ddd" agrega a la
cadena de resultado el nombre abreviado de un día de la semana que se encuentra en la matriz de cadenas
AbbreviatedDayNames. De igual forma, el especificador de formato "MMMM" agrega a la cadena de resultado
el nombre completo de un mes que se encuentra en la matriz de cadenas MonthNames.

Vea también
System.DateTime
System.IFormatProvider
Aplicación de formato a tipos
Standard Date and Time Format Strings
Ejemplo: Utilidad de formato WinForms de .NET Core (C#)
Ejemplo: Utilidad de formato WinForms de .NET Core (Visual Basic)
Cadenas de formato TimeSpan estándar
20/01/2020 • 15 minutes to read • Edit Online

Una cadena de formato estándar TimeSpan usa un único especificador de formato para definir la representación
de texto de un valor TimeSpan resultante de una operación de formato. Cualquier cadena de formato que
contenga más de un carácter, incluido el espacio en blanco, se interpreta como una cadena de formato TimeSpan
personalizado. Para más información, consulte Cadenas de formato TimeSpan personalizadas.
Las representaciones de cadena de los valores TimeSpan se generan mediante llamadas a las sobrecargas del
método TimeSpan.ToString, y también mediante métodos que admiten formatos compuestos, como
String.Format. Para obtener más información, consulte Aplicar formato a tipos y Formatos compuestos. En el
siguiente ejemplo se muestra el uso de cadenas de formato estándar en operaciones de formato.

using System;

public class Example


{
public static void Main()
{
TimeSpan duration = new TimeSpan(1, 12, 23, 62);
string output = "Time of Travel: " + duration.ToString("c");
Console.WriteLine(output);

Console.WriteLine("Time of Travel: {0:c}", duration);


}
}
// The example displays the following output:
// Time of Travel: 1.12:24:02
// Time of Travel: 1.12:24:02

Module Example
Public Sub Main()
Dim duration As New TimeSpan(1, 12, 23, 62)
Dim output As String = "Time of Travel: " + duration.ToString("c")
Console.WriteLine(output)

Console.WriteLine("Time of Travel: {0:c}", duration)


End Sub
End Module
' The example displays the following output:
' Time of Travel: 1.12:24:02
' Time of Travel: 1.12:24:02

Los métodos TimeSpan y TimeSpan.ParseExact también usan cadenas de formato TimeSpan.TryParseExact


estándar para definir el formato que deben tener las cadenas de entrada de las operaciones de análisis. (Estas
operaciones convierten la representación de cadena de un valor en ese valor.) En el siguiente ejemplo, se muestra
el uso de cadenas de formato estándar en operaciones de análisis.
using System;

public class Example


{
public static void Main()
{
string value = "1.03:14:56.1667";
TimeSpan interval;
try {
interval = TimeSpan.ParseExact(value, "c", null);
Console.WriteLine("Converted '{0}' to {1}", value, interval);
}
catch (FormatException) {
Console.WriteLine("{0}: Bad Format", value);
}
catch (OverflowException) {
Console.WriteLine("{0}: Out of Range", value);
}

if (TimeSpan.TryParseExact(value, "c", null, out interval))


Console.WriteLine("Converted '{0}' to {1}", value, interval);
else
Console.WriteLine("Unable to convert {0} to a time interval.",
value);
}
}
// The example displays the following output:
// Converted '1.03:14:56.1667' to 1.03:14:56.1667000
// Converted '1.03:14:56.1667' to 1.03:14:56.1667000

Module Example
Public Sub Main()
Dim value As String = "1.03:14:56.1667"
Dim interval As TimeSpan
Try
interval = TimeSpan.ParseExact(value, "c", Nothing)
Console.WriteLine("Converted '{0}' to {1}", value, interval)
Catch e As FormatException
Console.WriteLine("{0}: Bad Format", value)
Catch e As OverflowException
Console.WriteLine("{0}: Out of Range", value)
End Try

If TimeSpan.TryParseExact(value, "c", Nothing, interval) Then


Console.WriteLine("Converted '{0}' to {1}", value, interval)
Else
Console.WriteLine("Unable to convert {0} to a time interval.",
value)
End If
End Sub
End Module
' The example displays the following output:
' Converted '1.03:14:56.1667' to 1.03:14:56.1667000
' Converted '1.03:14:56.1667' to 1.03:14:56.1667000

En la tabla siguiente se muestran los especificadores de formato de intervalo de tiempo estándar.

ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS


ESPECIFICADOR DE FORMATO NOMBRE DESCRIPCIÓN EJEMPLOS

"c" Formato constante Este especificador no tiene TimeSpan.Zero ->


(invariable) en cuenta la referencia 00:00:00
cultural. Toma la forma
[-] New TimeSpan(0, 0, 30,
[d'.']hh':'mm':'ss['.'fffffff]0)
. -> 00:30:00
(Las cadenas de formato "t" New TimeSpan(3, 17, 25,
y "T" producen los mismos 30, 500)
resultados). -> 3.17:25:30.5000000

Más información:
Especificador de formato
constante ("c").

"g" Formato corto general Este especificador solo New TimeSpan(1, 3, 16,
genera lo necesario. Tiene en 50, 500)
cuenta la referencia cultural -> 1:3:16:50.5 (en-US)
y su forma es
[-] New TimeSpan(1, 3, 16,
[d':']h':'mm':'ss[.FFFFFFF] 50, 500)
. -> 1:3:16:50,5 (fr-FR)

Más información: New TimeSpan(1, 3, 16,


50, 599)
Especificador de formato
corto general ("g"). -> 1:3:16:50.599 (en-US)

New TimeSpan(1, 3, 16,


50, 599)
-> 1:3:16:50,599 (fr-FR)

"G" Formato general largo Este especificador siempre New TimeSpan(18, 30, 0)
genera días y siete dígitos -> 0:18:30:00.0000000 (en-
fraccionarios. Tiene en US)
cuenta la referencia cultural
y su forma es New TimeSpan(18, 30, 0)
[- -> 0:18:30:00,0000000 (fr-
]d':'hh':'mm':'ss.fffffff
FR)
.

Más información:
Especificador de formato
largo general ("G").

Especificador de formato constante ("c")


El especificador de formato "c" devuelve la representación de cadena de un valor TimeSpan de la siguiente forma:
[-][d.]hh:mm:ss[.fffffff]
Los elementos de los corchetes ([ y ]) son opcionales. El punto (.) y los dos puntos (:) son símbolos literales. En la
siguiente tabla se describen los elementos restantes.

ELEMENTO DESCRIPCIÓN

- Signo negativo opcional, que indica un intervalo de tiempo


negativo.

d Número opcional de días, sin ceros a la izquierda.


ELEMENTO DESCRIPCIÓN

hh Número de horas, entre "00" y "23".

mm Número de minutos, entre "00" y "59".

ss Número de segundos, entre "00" y "59".

fffffff La parte fraccionaria opcional de un segundo. Su valor puede


oscilar entre "0000001" (un tic o una diez millonésima de
segundo) y "9999999" (9.999.999 diez millonésimas de
segundo, o un segundo menos un tic).

A diferencia de los especificadores de formato de "g" y "G", el especificador de formato "c" no tiene en cuenta la
referencia cultural. Produce la representación de cadena de un valor TimeSpan que es invariable y común a todas
las versiones anteriores de .NET previas a .NET Framework 4. "c" es la cadena de formato TimeSpan
predeterminado; el método TimeSpan.ToString() da formato a un valor de intervalo de tiempo mediante la cadena
de formato "c".

NOTE
TimeSpan también admite las cadenas de formato estándar "t" y "T", cuyo comportamiento es idéntico al de la cadena de
formato estándar "c".

En el ejemplo siguiente se crea una instancia de dos objetos TimeSpan, que se usan para realizar operaciones
aritméticas y se muestra el resultado. En cada caso, se utiliza un formato compuesto para mostrar el valor
TimeSpan mediante el especificador de formato "c".

using System;

public class Example


{
public static void Main()
{
TimeSpan interval1, interval2;
interval1 = new TimeSpan(7, 45, 16);
interval2 = new TimeSpan(18, 12, 38);

Console.WriteLine("{0:c} - {1:c} = {2:c}", interval1,


interval2, interval1 - interval2);
Console.WriteLine("{0:c} + {1:c} = {2:c}", interval1,
interval2, interval1 + interval2);

interval1 = new TimeSpan(0, 0, 1, 14, 365);


interval2 = TimeSpan.FromTicks(2143756);
Console.WriteLine("{0:c} + {1:c} = {2:c}", interval1,
interval2, interval1 + interval2);
}
}
// The example displays the following output:
// 07:45:16 - 18:12:38 = -10:27:22
// 07:45:16 + 18:12:38 = 1.01:57:54
// 00:01:14.3650000 + 00:00:00.2143756 = 00:01:14.5793756
Module Example
Public Sub Main()
Dim interval1, interval2 As TimeSpan
interval1 = New TimeSpan(7, 45, 16)
interval2 = New TimeSpan(18, 12, 38)

Console.WriteLine("{0:c} - {1:c} = {2:c}", interval1,


interval2, interval1 - interval2)
Console.WriteLine("{0:c} + {1:c} = {2:c}", interval1,
interval2, interval1 + interval2)

interval1 = New TimeSpan(0, 0, 1, 14, 365)


interval2 = TimeSpan.FromTicks(2143756)
Console.WriteLine("{0:c} + {1:c} = {2:c}", interval1,
interval2, interval1 + interval2)
End Sub
End Module
' The example displays the following output:
' 07:45:16 - 18:12:38 = -10:27:22
' 07:45:16 + 18:12:38 = 1.01:57:54
' 00:01:14.3650000 + 00:00:00.2143756 = 00:01:14.5793756

Especificador de formato corto general ("g")


El especificador de formato TimeSpan "g" devuelve la representación de cadena de un valor TimeSpan en una
forma compacta, incluyendo únicamente los elementos que sean necesarios. Tiene la forma siguiente:
[-][d:]h:mm:ss[.FFFFFFF ]
Los elementos de los corchetes ([ y ]) son opcionales. Los dos puntos (:) son un símbolo literal. En la siguiente
tabla se describen los elementos restantes.

ELEMENTO DESCRIPCIÓN

- Signo negativo opcional, que indica un intervalo de tiempo


negativo.

d Número opcional de días, sin ceros a la izquierda.

h El número de horas, entre "0" a "23", sin ceros a la izquierda.

mm Número de minutos, entre "00" y "59".

ss Número de segundos, entre "00" y "59".

. Separador de fracciones de segundo. Es equivalente a la


propiedad NumberDecimalSeparator de la referencia cultural
especificada sin invalidaciones del usuario.

FFFFFFF Fracciones de segundo. Se muestra la menor cantidad de


dígitos posible.

Al igual que el especificador de formato "G", el especificador de formato "g" se localiza. Su separador de
fracciones de segundo se basa en la referencia cultural actual o en la propiedad NumberDecimalSeparator de una
referencia cultural especificada.
En el ejemplo siguiente se crea una instancia de dos objetos TimeSpan, que se usan para realizar operaciones
aritméticas y se muestra el resultado. En cada caso, se utiliza un formato compuesto para mostrar el valor
TimeSpan mediante el especificador de formato "g". Además, se da formato al valor TimeSpan mediante las
convenciones de formato de la referencia cultural del sistema actual (que, en este caso, es inglés - Estados Unidos
o en-US ) y la referencia cultural de Francia de francés (fr-FR ).

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
TimeSpan interval1, interval2;
interval1 = new TimeSpan(7, 45, 16);
interval2 = new TimeSpan(18, 12, 38);

Console.WriteLine("{0:g} - {1:g} = {2:g}", interval1,


interval2, interval1 - interval2);
Console.WriteLine(String.Format(new CultureInfo("fr-FR"),
"{0:g} + {1:g} = {2:g}", interval1,
interval2, interval1 + interval2));

interval1 = new TimeSpan(0, 0, 1, 14, 36);


interval2 = TimeSpan.FromTicks(2143756);
Console.WriteLine("{0:g} + {1:g} = {2:g}", interval1,
interval2, interval1 + interval2);
}
}
// The example displays the following output:
// 7:45:16 - 18:12:38 = -10:27:22
// 7:45:16 + 18:12:38 = 1:1:57:54
// 0:01:14.036 + 0:00:00.2143756 = 0:01:14.2503756

Imports System.Globalization

Module Example
Public Sub Main()
Dim interval1, interval2 As TimeSpan
interval1 = New TimeSpan(7, 45, 16)
interval2 = New TimeSpan(18, 12, 38)

Console.WriteLine("{0:g} - {1:g} = {2:g}", interval1,


interval2, interval1 - interval2)
Console.WriteLine(String.Format(New CultureInfo("fr-FR"),
"{0:g} + {1:g} = {2:g}", interval1,
interval2, interval1 + interval2))

interval1 = New TimeSpan(0, 0, 1, 14, 36)


interval2 = TimeSpan.FromTicks(2143756)
Console.WriteLine("{0:g} + {1:g} = {2:g}", interval1,
interval2, interval1 + interval2)
End Sub
End Module
' The example displays the following output:
' 7:45:16 - 18:12:38 = -10:27:22
' 7:45:16 + 18:12:38 = 1:1:57:54
' 0:01:14.036 + 0:00:00.2143756 = 0:01:14.2503756

Especificador de formato largo general ("G")


El especificador de formato TimeSpan "G" devuelve la representación de cadena de un valor TimeSpan en un
formato largo que siempre incluye los días y las fracciones de segundo. La cadena resultante del especificador de
formato estándar "G" tiene la forma siguiente:
[-]d:hh:mm:ss.fffffff
Los elementos de los corchetes ([ y ]) son opcionales. Los dos puntos (:) son un símbolo literal. En la siguiente
tabla se describen los elementos restantes.

ELEMENTO DESCRIPCIÓN

- Signo negativo opcional, que indica un intervalo de tiempo


negativo.

d Número de días, sin ceros a la izquierda.

hh Número de horas, entre "00" y "23".

mm Número de minutos, entre "00" y "59".

ss Número de segundos, entre "00" y "59".

. Separador de fracciones de segundo. Es equivalente a la


propiedad NumberDecimalSeparator de la referencia cultural
especificada sin invalidaciones del usuario.

fffffff Fracciones de segundo.

Al igual que el especificador de formato "G", el especificador de formato "g" se localiza. Su separador de
fracciones de segundo se basa en la referencia cultural actual o en la propiedad NumberDecimalSeparator de una
referencia cultural especificada.
En el ejemplo siguiente se crea una instancia de dos objetos TimeSpan, que se usan para realizar operaciones
aritméticas y se muestra el resultado. En cada caso, se utiliza un formato compuesto para mostrar el valor
TimeSpan mediante el especificador de formato "G". Además, se da formato al valor TimeSpan mediante las
convenciones de formato de la referencia cultural del sistema actual (que, en este caso, es inglés - Estados Unidos
o en-US ) y la referencia cultural de Francia de francés (fr-FR ).
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
TimeSpan interval1, interval2;
interval1 = new TimeSpan(7, 45, 16);
interval2 = new TimeSpan(18, 12, 38);

Console.WriteLine("{0:G} - {1:G} = {2:G}", interval1,


interval2, interval1 - interval2);
Console.WriteLine(String.Format(new CultureInfo("fr-FR"),
"{0:G} + {1:G} = {2:G}", interval1,
interval2, interval1 + interval2));

interval1 = new TimeSpan(0, 0, 1, 14, 36);


interval2 = TimeSpan.FromTicks(2143756);
Console.WriteLine("{0:G} + {1:G} = {2:G}", interval1,
interval2, interval1 + interval2);
}
}
// The example displays the following output:
// 0:07:45:16.0000000 - 0:18:12:38.0000000 = -0:10:27:22.0000000
// 0:07:45:16,0000000 + 0:18:12:38,0000000 = 1:01:57:54,0000000
// 0:00:01:14.0360000 + 0:00:00:00.2143756 = 0:00:01:14.2503756

Imports System.Globalization

Module Example
Public Sub Main()
Dim interval1, interval2 As TimeSpan
interval1 = New TimeSpan(7, 45, 16)
interval2 = New TimeSpan(18, 12, 38)

Console.WriteLine("{0:G} - {1:G} = {2:G}", interval1,


interval2, interval1 - interval2)
Console.WriteLine(String.Format(New CultureInfo("fr-FR"),
"{0:G} + {1:G} = {2:G}", interval1,
interval2, interval1 + interval2))

interval1 = New TimeSpan(0, 0, 1, 14, 36)


interval2 = TimeSpan.FromTicks(2143756)
Console.WriteLine("{0:G} + {1:G} = {2:G}", interval1,
interval2, interval1 + interval2)
End Sub
End Module
' The example displays the following output:
' 0:07:45:16.0000000 - 0:18:12:38.0000000 = -0:10:27:22.0000000
' 0:07:45:16,0000000 + 0:18:12:38,0000000 = 1:01:57:54,0000000
' 0:00:01:14.0360000 + 0:00:00:00.2143756 = 0:00:01:14.2503756

Vea también
Aplicación de formato a tipos
Cadenas de formato TimeSpan personalizado
Parsing Strings
Cadenas de formato TimeSpan personalizado
20/01/2020 • 63 minutes to read • Edit Online

Una cadena de formato TimeSpan define la representación de cadena de un valor TimeSpan generado por una
operación de formato. Una cadena de formato personalizado consta de uno o varios especificadores de formato
TimeSpan personalizado, además de un número de caracteres literales. Cualquier cadena que no sea una cadena
de formato TimeSpan estándar se interpreta como una cadena de formato TimeSpan personalizado.

IMPORTANT
Los especificadores de formato TimeSpan personalizado no incluyen símbolos de separador de marcadores de posición,
como los símbolos que separan los días de las horas, las horas de los minutos o los segundos de las fracciones de segundo.
Estos símbolos deben incluirse en la cadena de formato personalizado como literales de cadena. Por ejemplo,
"dd\.hh\:mm" define un punto (.) como separador entre los días y las horas, y un signo de dos puntos (:) como separador
entre las horas y los minutos.
Los especificadores de formato TimeSpan personalizado tampoco incluyen un símbolo de signo que permita distinguir entre
los intervalos de tiempo negativos y positivos. Para incluir un símbolo de signo, es necesario construir una cadena de
formato utilizando lógica condicional. En la sección Otros caracteres se incluye un ejemplo.

Las representaciones de cadena de los valores TimeSpan se generan mediante llamadas a las sobrecargas del
método TimeSpan.ToString, y también mediante métodos que admiten formatos compuestos, como
String.Format. Para obtener más información, consulte Aplicar formato a tipos y Formatos compuestos. En el
siguiente ejemplo, se muestra el uso de cadenas de formato personalizado en operaciones de formato.

using System;

public class Example


{
public static void Main()
{
TimeSpan duration = new TimeSpan(1, 12, 23, 62);

string output = null;


output = "Time of Travel: " + duration.ToString("%d") + " days";
Console.WriteLine(output);
output = "Time of Travel: " + duration.ToString(@"dd\.hh\:mm\:ss");
Console.WriteLine(output);

Console.WriteLine("Time of Travel: {0:%d} day(s)", duration);


Console.WriteLine("Time of Travel: {0:dd\\.hh\\:mm\\:ss} days", duration);
}
}
// The example displays the following output:
// Time of Travel: 1 days
// Time of Travel: 01.12:24:02
// Time of Travel: 1 day(s)
// Time of Travel: 01.12:24:02 days
Module Example
Public Sub Main()
Dim duration As New TimeSpan(1, 12, 23, 62)

Dim output As String = Nothing


output = "Time of Travel: " + duration.ToString("%d") + " days"
Console.WriteLine(output)
output = "Time of Travel: " + duration.ToString("dd\.hh\:mm\:ss")
Console.WriteLine(output)

Console.WriteLine("Time of Travel: {0:%d} day(s)", duration)


Console.WriteLine("Time of Travel: {0:dd\.hh\:mm\:ss} days", duration)
End Sub
End Module
' The example displays the following output:
' Time of Travel: 1 days
' Time of Travel: 01.12:24:02
' Time of Travel: 1 day(s)
' Time of Travel: 01.12:24:02 days

Los métodos TimeSpan y TimeSpan.ParseExact también usan cadenas de formato TimeSpan.TryParseExact


personalizadas para definir el formato que deben tener las cadenas de entrada de las operaciones de análisis.
(Estas operaciones convierten la representación de cadena de un valor en ese valor.) En el siguiente ejemplo, se
muestra el uso de cadenas de formato estándar en operaciones de análisis.

using System;

public class Example


{
public static void Main()
{
string value = null;
TimeSpan interval;

value = "6";
if (TimeSpan.TryParseExact(value, "%d", null, out interval))
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"));
else
Console.WriteLine("Unable to parse '{0}'", value);

value = "16:32.05";
if (TimeSpan.TryParseExact(value, @"mm\:ss\.ff", null, out interval))
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"));
else
Console.WriteLine("Unable to parse '{0}'", value);

value= "12.035";
if (TimeSpan.TryParseExact(value, "ss\\.fff", null, out interval))
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"));
else
Console.WriteLine("Unable to parse '{0}'", value);
}
}
// The example displays the following output:
// 6 --> 6.00:00:00
// 16:32.05 --> 00:16:32.0500000
// 12.035 --> 00:00:12.0350000
Module Example
Public Sub Main()
Dim value As String = Nothing
Dim interval As TimeSpan

value = "6"
If TimeSpan.TryParseExact(value, "%d", Nothing, interval) Then
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"))
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If

value = "16:32.05"
If TimeSpan.TryParseExact(value, "mm\:ss\.ff", Nothing, interval) Then
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"))
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If

value= "12.035"
If TimeSpan.TryParseExact(value, "ss\.fff", Nothing, interval) Then
Console.WriteLine("{0} --> {1}", value, interval.ToString("c"))
Else
Console.WriteLine("Unable to parse '{0}'", value)
End If
End Sub
End Module
' The example displays the following output:
' 6 --> 6.00:00:00
' 16:32.05 --> 00:16:32.0500000
' 12.035 --> 00:00:12.0350000

En la siguiente tabla se describen los especificadores de formato de fecha y hora personalizado.

ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLO

"d", "%d" Número de días completos de un new TimeSpan(6, 14, 32, 17, 685):
intervalo de tiempo.
%d --> "6"
Más información: Especificador de
formato personalizado "d". d\.hh\:mm --> "6.14:32"

"dd"-"dddddddd" Número de días completos de un new TimeSpan(6, 14, 32, 17, 685):
intervalo de tiempo, que se completa
con tantos ceros iniciales como sean ddd --> "006"
necesarios.
dd\.hh\:mm --> "06.14:32"
Más información: Especificadores de
formato personalizado "dd"-
"dddddddd".

"h", "%h" Número de horas completas de un new TimeSpan(6, 14, 32, 17, 685):
intervalo de tiempo que no se cuentan
como parte de los días. Las horas con %h --> "14"
un solo dígito no se escriben con un
cero a la izquierda. hh\:mm --> "14:32"
Más información: Especificador de
formato personalizado "h".
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLO

"hh" Número de horas completas de un new TimeSpan(6, 14, 32, 17, 685):
intervalo de tiempo que no se cuentan
como parte de los días. Las horas con hh --> "14"
un solo dígito se escriben con un cero a
la izquierda. new TimeSpan(6, 8, 32, 17, 685):

Más información: Especificador de hh --> 08


formato personalizado "hh".

"m", "%m" Número de minutos completos de un new TimeSpan(6, 14, 8, 17, 685):
intervalo de tiempo que no se incluyen
como parte de las horas o los días. Los %m --> "8"
minutos con un solo dígito no se
escriben con un cero a la izquierda. h\:m --> "14:8"
Más información: Especificador de
formato personalizado "m".

"mm" Número de minutos completos de un new TimeSpan(6, 14, 8, 17, 685):


intervalo de tiempo que no se incluyen
como parte de las horas o los días. Los mm --> "08"
minutos con un solo dígito se escriben
con un cero a la izquierda. new TimeSpan(6, 8, 5, 17, 685):

Más información: Especificador de d\.hh\:mm\:ss --> 6.08:05:17


formato personalizado "mm".

"s", "%s" Número de segundos completos de un TimeSpan.FromSeconds(12.965) :


intervalo de tiempo que no se incluyen
como parte de las horas, los días o los %s --> 12
minutos. Los segundos con un solo
dígito no se escriben con un cero a la s\.fff --> 12.965
izquierda.

Más información: Especificador de


formato personalizado "s".

"ss" Número de segundos completos de un TimeSpan.FromSeconds(6.965) :


intervalo de tiempo que no se incluyen
como parte de las horas, los días o los ss --> 06
minutos. Los segundos con un solo
dígito se escriben con un cero a la ss\.fff --> 06.965
izquierda.

Más información: Especificador de


formato personalizado "ss".

"f", "%f" Décimas de segundo de un intervalo TimeSpan.FromSeconds(6.895) :


de tiempo.
f --> 8
Más información: Especificador de
formato personalizado "f". ss\.f --> 06.8

"ff" Centésimas de segundo de un TimeSpan.FromSeconds(6.895) :


intervalo de tiempo.
ff --> 89
Más información: Especificador de
formato personalizado "ff". ss\.ff --> 06.89
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLO

"fff" Milisegundos de un intervalo de TimeSpan.FromSeconds(6.895) :


tiempo.
fff --> 895
Más información: Especificador de
formato personalizado "fff". ss\.fff --> 06.895

"ffff" Diezmilésimas de segundo de un TimeSpan.Parse("0:0:6.8954321") :


intervalo de tiempo.
ffff --> 8954
Más información: Especificador de
formato personalizado "ffff". ss\.ffff --> 06.8954

"fffff" Cienmilésimas de segundo de un TimeSpan.Parse("0:0:6.8954321") :


intervalo de tiempo.
fffff --> 89543
Más información: Especificador de
formato personalizado "fffff". ss\.fffff --> 06.89543

"ffffff" Millonésimas de segundo de un TimeSpan.Parse("0:0:6.8954321") :


intervalo de tiempo.
ffffff --> 895432
Más información: Especificador de
formato personalizado "ffffff". ss\.ffffff --> 06.895432

"fffffff" Diezmillonésimas de segundo (o TimeSpan.Parse("0:0:6.8954321") :


fracciones de paso) de un intervalo de
tiempo. fffffff --> 8954321

Más información: Especificador de ss\.fffffff --> 06.8954321


formato personalizado "fffffff".

"F", "%F" Décimas de segundo de un intervalo TimeSpan.Parse("00:00:06.32") :


de tiempo. Si el dígito es cero, no se
muestra nada. %F :3

Más información: Especificador de TimeSpan.Parse("0:0:3.091") :


formato personalizado "F".
ss\.F : 03.

"FF" Centésimas de segundo de un TimeSpan.Parse("00:00:06.329") :


intervalo de tiempo. No se incluyen los
ceros finales fraccionarios ni los dígitos FF : 32
de dos ceros.
TimeSpan.Parse("0:0:3.101") :
Más información: Especificador de
formato personalizado "FF". ss\.FF : 03.1

"FFF" Milisegundos de un intervalo de TimeSpan.Parse("00:00:06.3291") :


tiempo. No se incluyen los ceros finales
fraccionarios. FFF : 329

Más información: TimeSpan.Parse("0:0:3.1009") :

ss\.FFF : 03.1
ESPECIFICADOR DE FORMATO DESCRIPCIÓN EJEMPLO

"FFFF" Diezmilésimas de segundo de un TimeSpan.Parse("00:00:06.32917") :


intervalo de tiempo. No se incluyen los
ceros finales fraccionarios. FFFFF : 3291

Más información: Especificador de TimeSpan.Parse("0:0:3.10009") :


formato personalizado "FFFF".
ss\.FFFF : 03.1

"FFFFF" Cienmilésimas de segundo de un TimeSpan.Parse("00:00:06.329179")


intervalo de tiempo. No se incluyen los :
ceros finales fraccionarios.
FFFFF : 32917
Más información: Especificador de
formato personalizado "FFFFF". TimeSpan.Parse("0:0:3.100009") :

ss\.FFFFF : 03.1

"FFFFFF" Millonésimas de segundo de un TimeSpan.Parse("00:00:06.3291791")


intervalo de tiempo. No se muestran :
los ceros finales fraccionarios.
FFFFFF : 329179
Más información: Especificador de
formato personalizado "FFFFFF". TimeSpan.Parse("0:0:3.1000009") :

ss\.FFFFFF : 03.1

"FFFFFFF" Diezmillonésimas de segundo de un TimeSpan.Parse("00:00:06.3291791")


intervalo de tiempo. No se muestran :
los ceros finales fraccionarios ni los
dígitos de siete ceros. FFFFFF : 3291791

Más información: Especificador de TimeSpan.Parse("0:0:3.1900000") :


formato personalizado "FFFFFFF".
ss\.FFFFFF : 03.19

'cadena' Delimitador de cadena literal. new TimeSpan(14, 32, 17):

Más información: Otros caracteres. hh':'mm':'ss --> "14:32:17"

\ El carácter de escape. new TimeSpan(14, 32, 17):

Más información: Otros caracteres. hh\:mm\:ss --> "14:32:17"

Cualquier otro carácter Cualquier otro carácter sin escape se new TimeSpan(14, 32, 17):
interpreta como especificador de
formato personalizado. hh\:mm\:ss --> "14:32:17"

Más información: Otros caracteres.

Especificador de formato personalizado "d"


El especificador de formato personalizado "d" presenta el valor de la propiedad TimeSpan.Days, que representa el
número de días completos de un intervalo de tiempo. Presenta el número completo de días de un valor
TimeSpan, incluso si el valor tiene más de un dígito. Si el valor de la propiedad TimeSpan.Days es cero, el
especificador presentará "0".
Si el especificador de formato personalizado "d" se utiliza solo, especifique "%d" de modo que no se interprete
por error como una cadena de formato estándar. Esto se muestra en el ejemplo siguiente.

TimeSpan ts1 = new TimeSpan(16, 4, 3, 17, 250);


Console.WriteLine(ts1.ToString("%d"));
// Displays 16

Dim ts As New TimeSpan(16, 4, 3, 17, 250)


Console.WriteLine(ts.ToString("%d"))
' Displays 16

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "d".

TimeSpan ts2 = new TimeSpan(4, 3, 17);


Console.WriteLine(ts2.ToString(@"d\.hh\:mm\:ss"));

TimeSpan ts3 = new TimeSpan(3, 4, 3, 17);


Console.WriteLine(ts3.ToString(@"d\.hh\:mm\:ss"));
// The example displays the following output:
// 0.04:03:17
// 3.04:03:17

Dim ts2 As New TimeSpan(4, 3, 17)


Console.WriteLine(ts2.ToString("d\.hh\:mm\:ss"))

Dim ts3 As New TimeSpan(3, 4, 3, 17)


Console.WriteLine(ts3.ToString("d\.hh\:mm\:ss"))
' The example displays the following output:
' 0.04:03:17
' 3.04:03:17

Volver a la tabla

Especificadores de formato personalizado "dd"-"dddddddd"


Los especificadores de formato personalizado "dd", "ddd", "dddd", "ddddd", "dddddd", "ddddddd" y "dddddddd"
presentan el valor de la propiedad TimeSpan.Days, que representa el número de días completos de un intervalo
de tiempo.
La cadena de salida incluye un número mínimo de dígitos que viene determinado por el número de caracteres "d"
en el especificador de formato y se completa con tantos ceros iniciales como sean necesarios. Si los dígitos del
número de días superan el número de caracteres "d" en el especificador de formato, la cadena de resultado
mostrará el número completo de días.
En el siguiente ejemplo, se utilizan estos especificadores de formato para mostrar la representación de cadena de
dos valores TimeSpan. El valor del componente de días en el primer intervalo de tiempo es cero; el valor del
componente de días en el segundo es 365.
TimeSpan ts1 = new TimeSpan(0, 23, 17, 47);
TimeSpan ts2 = new TimeSpan(365, 21, 19, 45);

for (int ctr = 2; ctr <= 8; ctr++)


{
string fmt = new String('d', ctr) + @"\.hh\:mm\:ss";
Console.WriteLine("{0} --> {1:" + fmt + "}", fmt, ts1);
Console.WriteLine("{0} --> {1:" + fmt + "}", fmt, ts2);
Console.WriteLine();
}
// The example displays the following output:
// dd\.hh\:mm\:ss --> 00.23:17:47
// dd\.hh\:mm\:ss --> 365.21:19:45
//
// ddd\.hh\:mm\:ss --> 000.23:17:47
// ddd\.hh\:mm\:ss --> 365.21:19:45
//
// dddd\.hh\:mm\:ss --> 0000.23:17:47
// dddd\.hh\:mm\:ss --> 0365.21:19:45
//
// ddddd\.hh\:mm\:ss --> 00000.23:17:47
// ddddd\.hh\:mm\:ss --> 00365.21:19:45
//
// dddddd\.hh\:mm\:ss --> 000000.23:17:47
// dddddd\.hh\:mm\:ss --> 000365.21:19:45
//
// ddddddd\.hh\:mm\:ss --> 0000000.23:17:47
// ddddddd\.hh\:mm\:ss --> 0000365.21:19:45
//
// dddddddd\.hh\:mm\:ss --> 00000000.23:17:47
// dddddddd\.hh\:mm\:ss --> 00000365.21:19:45

Dim ts1 As New TimeSpan(0, 23, 17, 47)


Dim ts2 As New TimeSpan(365, 21, 19, 45)

For ctr As Integer = 2 To 8


Dim fmt As String = New String("d"c, ctr) + "\.hh\:mm\:ss"
Console.WriteLine("{0} --> {1:" + fmt + "}", fmt, ts1)
Console.WriteLine("{0} --> {1:" + fmt + "}", fmt, ts2)
Console.WriteLine()
Next
' The example displays the following output:
' dd\.hh\:mm\:ss --> 00.23:17:47
' dd\.hh\:mm\:ss --> 365.21:19:45
'
' ddd\.hh\:mm\:ss --> 000.23:17:47
' ddd\.hh\:mm\:ss --> 365.21:19:45
'
' dddd\.hh\:mm\:ss --> 0000.23:17:47
' dddd\.hh\:mm\:ss --> 0365.21:19:45
'
' ddddd\.hh\:mm\:ss --> 00000.23:17:47
' ddddd\.hh\:mm\:ss --> 00365.21:19:45
'
' dddddd\.hh\:mm\:ss --> 000000.23:17:47
' dddddd\.hh\:mm\:ss --> 000365.21:19:45
'
' ddddddd\.hh\:mm\:ss --> 0000000.23:17:47
' ddddddd\.hh\:mm\:ss --> 0000365.21:19:45
'
' dddddddd\.hh\:mm\:ss --> 00000000.23:17:47
' dddddddd\.hh\:mm\:ss --> 00000365.21:19:45

Volver a la tabla
Especificador de formato personalizado "h"
El especificador de formato personalizado "h" presenta el valor de la propiedad TimeSpan.Hours, que representa
el número de horas completas de un intervalo de tiempo que no se cuentan como parte del componente de días.
Devuelve un valor de cadena de un dígito si el valor de la propiedad TimeSpan.Hours es de 0 a 9; devuelve un
valor de cadena de dos dígitos si el valor de la propiedad TimeSpan.Hours es de 10 a 23.
Si el especificador de formato personalizado "h" se utiliza solo, especifique "%h" de modo que no se interprete
por error como una cadena de formato estándar. Esto se muestra en el ejemplo siguiente.

TimeSpan ts = new TimeSpan(3, 42, 0);


Console.WriteLine("{0:%h} hours {0:%m} minutes", ts);
// The example displays the following output:
// 3 hours 42 minutes

Dim ts As New TimeSpan(3, 42, 0)


Console.WriteLine("{0:%h} hours {0:%m} minutes", ts)
' The example displays the following output:
' 3 hours 42 minutes

Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "%h"" para que la
cadena numérica se interprete como número de horas. Esto se muestra en el ejemplo siguiente.

string value = "8";


TimeSpan interval;
if (TimeSpan.TryParseExact(value, "%h", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
// The example displays the following output:
// 08:00:00

Dim value As String = "8"


Dim interval As TimeSpan
If TimeSpan.TryParseExact(value, "%h", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
' The example displays the following output:
' 08:00:00

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "h".

TimeSpan ts1 = new TimeSpan(14, 3, 17);


Console.WriteLine(ts1.ToString(@"d\.h\:mm\:ss"));

TimeSpan ts2 = new TimeSpan(3, 4, 3, 17);


Console.WriteLine(ts2.ToString(@"d\.h\:mm\:ss"));
// The example displays the following output:
// 0.14:03:17
// 3.4:03:17
Dim ts1 As New TimeSpan(14, 3, 17)
Console.WriteLine(ts1.ToString("d\.h\:mm\:ss"))

Dim ts2 As New TimeSpan(3, 4, 3, 17)


Console.WriteLine(ts2.ToString("d\.h\:mm\:ss"))
' The example displays the following output:
' 0.14:03:17
' 3.4:03:17

Volver a la tabla

Especificador de formato personalizado "hh"


El especificador de formato personalizado "hh" presenta el valor de la propiedad TimeSpan.Hours, que
representa el número de horas completas de un intervalo de tiempo que no se cuentan como parte del
componente de días. Para los valores de 0 a 9, la cadena de salida incluye un cero inicial.
Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "hh"" para que la
cadena numérica se interprete como número de horas. Esto se muestra en el ejemplo siguiente.

string value = "08";


TimeSpan interval;
if (TimeSpan.TryParseExact(value, "hh", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
// The example displays the following output:
// 08:00:00

Dim value As String = "08"


Dim interval As TimeSpan
If TimeSpan.TryParseExact(value, "hh", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
' The example displays the following output:
' 08:00:00

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "hh".

TimeSpan ts1 = new TimeSpan(14, 3, 17);


Console.WriteLine(ts1.ToString(@"d\.hh\:mm\:ss"));

TimeSpan ts2 = new TimeSpan(3, 4, 3, 17);


Console.WriteLine(ts2.ToString(@"d\.hh\:mm\:ss"));
// The example displays the following output:
// 0.14:03:17
// 3.04:03:17
Dim ts1 As New TimeSpan(14, 3, 17)
Console.WriteLine(ts1.ToString("d\.hh\:mm\:ss"))

Dim ts2 As New TimeSpan(3, 4, 3, 17)


Console.WriteLine(ts2.ToString("d\.hh\:mm\:ss"))
' The example displays the following output:
' 0.14:03:17
' 3.04:03:17

Volver a la tabla

Especificador de formato personalizado "m"


El especificador de formato personalizado "m" presenta el valor de la propiedad TimeSpan.Minutes, que
representa el número de minutos completos de un intervalo de tiempo que no se cuentan como parte del
componente de días. Devuelve un valor de cadena de un dígito si el valor de la propiedad TimeSpan.Minutes es
de 0 a 9; devuelve un valor de cadena de dos dígitos si el valor de la propiedad TimeSpan.Minutes es de 10 a 59.
Si el especificador de formato personalizado "m" se utiliza solo, especifique "%m" de modo que no se interprete
por error como una cadena de formato estándar. Esto se muestra en el ejemplo siguiente.

TimeSpan ts = new TimeSpan(3, 42, 0);


Console.WriteLine("{0:%h} hours {0:%m} minutes", ts);
// The example displays the following output:
// 3 hours 42 minutes

Dim ts As New TimeSpan(3, 42, 0)


Console.WriteLine("{0:%h} hours {0:%m} minutes", ts)
' The example displays the following output:
' 3 hours 42 minutes

Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "%m"" para que la
cadena numérica se interprete como número de minutos. Esto se muestra en el ejemplo siguiente.

string value = "3";


TimeSpan interval;
if (TimeSpan.TryParseExact(value, "%m", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
// The example displays the following output:
// 00:03:00

Dim value As String = "3"


Dim interval As TimeSpan
If TimeSpan.TryParseExact(value, "%m", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
' The example displays the following output:
' 00:03:00
En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "m".

TimeSpan ts1 = new TimeSpan(0, 6, 32);


Console.WriteLine("{0:m\\:ss} minutes", ts1);

TimeSpan ts2 = new TimeSpan(3, 4, 3, 17);


Console.WriteLine("Elapsed time: {0:m\\:ss}", ts2);
// The example displays the following output:
// 6:32 minutes
// Elapsed time: 18:44

Dim ts1 As New TimeSpan(0, 6, 32)


Console.WriteLine("{0:m\:ss} minutes", ts1)

Dim ts2 As New TimeSpan(0, 18, 44)


Console.WriteLine("Elapsed time: {0:m\:ss}", ts2)
' The example displays the following output:
' 6:32 minutes
' Elapsed time: 18:44

Volver a la tabla

Especificador de formato personalizado "mm"


El especificador de formato personalizado "mm" presenta el valor de la propiedad TimeSpan.Minutes, que
representa el número de minutos completos de un intervalo de tiempo que no se cuentan como parte del
componente de horas o días. Para los valores de 0 a 9, la cadena de salida incluye un cero inicial.
Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "mm"" para que la
cadena numérica se interprete como número de minutos. Esto se muestra en el ejemplo siguiente.

string value = "07";


TimeSpan interval;
if (TimeSpan.TryParseExact(value, "mm", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
// The example displays the following output:
// 00:07:00

Dim value As String = "05"


Dim interval As TimeSpan
If TimeSpan.TryParseExact(value, "mm", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
' The example displays the following output:
' 00:05:00

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "mm".


TimeSpan departTime = new TimeSpan(11, 12, 00);
TimeSpan arriveTime = new TimeSpan(16, 28, 00);
Console.WriteLine("Travel time: {0:hh\\:mm}",
arriveTime - departTime);
// The example displays the following output:
// Travel time: 05:16

Dim departTime As New TimeSpan(11, 12, 00)


Dim arriveTime As New TimeSpan(16, 28, 00)
Console.WriteLine("Travel time: {0:hh\:mm}",
arriveTime - departTime)
' The example displays the following output:
' Travel time: 05:16

Volver a la tabla

Especificador de formato personalizado "s"


El especificador de formato personalizado "s" presenta el valor de la propiedad TimeSpan.Seconds, que
representa el número de segundos completos de un intervalo de tiempo que no se cuentan como parte del
componente de horas, días o minutos. Devuelve un valor de cadena de un dígito si el valor de la propiedad
TimeSpan.Seconds es de 0 a 9; devuelve un valor de cadena de dos dígitos si el valor de la propiedad
TimeSpan.Seconds es de 10 a 59.
Si el especificador de formato personalizado "s" se utiliza solo, especifique "%s" de modo que no se interprete por
error como una cadena de formato estándar. Esto se muestra en el ejemplo siguiente.

TimeSpan ts = TimeSpan.FromSeconds(12.465);
Console.WriteLine(ts.ToString("%s"));
// The example displays the following output:
// 12

Dim ts As TimeSpan = TimeSpan.FromSeconds(12.465)


Console.WriteLine(ts.ToString("%s"))
' The example displays the following output:
' 12

Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "%s"" para que la
cadena numérica se interprete como número de segundos. Esto se muestra en el ejemplo siguiente.

string value = "9";


TimeSpan interval;
if (TimeSpan.TryParseExact(value, "%s", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
// The example displays the following output:
// 00:00:09
Dim value As String = "9"
Dim interval As TimeSpan
If TimeSpan.TryParseExact(value, "%s", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
' The example displays the following output:
' 00:00:09

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "s".

TimeSpan startTime = new TimeSpan(0, 12, 30, 15, 0);


TimeSpan endTime = new TimeSpan(0, 12, 30, 21, 3);
Console.WriteLine(@"Elapsed Time: {0:s\:fff} seconds",
endTime - startTime);
// The example displays the following output:
// Elapsed Time: 6:003 seconds

Dim startTime As New TimeSpan(0, 12, 30, 15, 0)


Dim endTime As New TimeSpan(0, 12, 30, 21, 3)
Console.WriteLine("Elapsed Time: {0:s\:fff} seconds",
endTime - startTime)
' The example displays the following output:
' Elapsed Time: 6:003 seconds

Volver a la tabla

Especificador de formato personalizado "ss"


El especificador de formato personalizado "ss" presenta el valor de la propiedad TimeSpan.Seconds, que
representa el número de segundos completos de un intervalo de tiempo que no se cuentan como parte del
componente de horas, días o minutos. Para los valores de 0 a 9, la cadena de salida incluye un cero inicial.
Normalmente, en las operaciones de análisis, una cadena de entrada que incluye solamente un número se
interpreta como número de días. Se puede utilizar el especificador de formato personalizado "ss"" para que la
cadena numérica se interprete como número de segundos. Esto se muestra en el ejemplo siguiente.

string[] values = { "49", "9", "06" };


TimeSpan interval;
foreach (string value in values)
{
if (TimeSpan.TryParseExact(value, "ss", null, out interval))
Console.WriteLine(interval.ToString("c"));
else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value);
}
// The example displays the following output:
// 00:00:49
// Unable to convert '9' to a time interval
// 00:00:06
Dim values() As String = { "49", "9", "06" }
Dim interval As TimeSpan
For Each value As String In values
If TimeSpan.TryParseExact(value, "ss", Nothing, interval) Then
Console.WriteLine(interval.ToString("c"))
Else
Console.WriteLine("Unable to convert '{0}' to a time interval",
value)
End If
Next
' The example displays the following output:
' 00:00:49
' Unable to convert '9' to a time interval
' 00:00:06

En el siguiente ejemplo, se muestra el uso del especificador de formato personalizado "ss".

TimeSpan interval1 = TimeSpan.FromSeconds(12.60);


Console.WriteLine(interval1.ToString(@"ss\.fff"));

TimeSpan interval2 = TimeSpan.FromSeconds(6.485);


Console.WriteLine(interval2.ToString(@"ss\.fff"));
// The example displays the following output:
// 12.600
// 06.485

Dim interval1 As TimeSpan = TimeSpan.FromSeconds(12.60)


Console.WriteLine(interval1.ToString("ss\.fff"))
Dim interval2 As TimeSpan = TimeSpan.FromSeconds(6.485)
Console.WriteLine(interval2.ToString("ss\.fff"))
' The example displays the following output:
' 12.600
' 06.485

Volver a la tabla

Especificador de formato personalizado "f"


El especificador de formato personalizado "f" presenta las décimas de segundo de un intervalo de tiempo. En una
operación de formato, se truncan los dígitos fraccionarios restantes. En una operación de análisis que llama al
método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada debe contener exactamente un
dígito fraccionario.
Si el especificador de formato personalizado "f" se utiliza solo, especifique "%f" de modo que no se interprete por
error como una cadena de formato estándar.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "f" para mostrar las décimas de
segundo de un valor TimeSpan. "f" se usa primero solo y luego junto con el especificador "s" en una cadena de
formato personalizado.
TimeSpan ts = new TimeSpan(1003498765432);
string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432

Dim ts As New TimeSpan(1003498765432)


Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432
Volver a la tabla

Especificador de formato personalizado "ff"


El especificador de formato personalizado "ff" presenta las centésimas de segundo de un intervalo de tiempo. En
una operación de formato, se truncan los dígitos fraccionarios restantes. En una operación de análisis que llama al
método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada debe contener exactamente dos
dígitos fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "ff" para mostrar las centésimas de
segundo de un valor TimeSpan. "ff" se usa primero solo luego junto con el especificador "s" en una cadena de
formato personalizado.

TimeSpan ts = new TimeSpan(1003498765432);


string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432
Dim ts As New TimeSpan(1003498765432)
Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432

Volver a la tabla

Especificador de formato personalizado "fff"


El especificador de formato personalizado "fff" (tres caracteres "f") presenta las milésimas de segundo de un
intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. En una
operación de análisis que llama al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada
debe contener exactamente tres dígitos fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "fff" para mostrar los milisegundos
de un valor TimeSpan. "fff" se usa primero solo y luego junto con el especificador "s" en una cadena de formato
personalizado.
TimeSpan ts = new TimeSpan(1003498765432);
string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432

Dim ts As New TimeSpan(1003498765432)


Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432
Volver a la tabla

Especificador de formato personalizado "ffff"


El especificador de formato personalizado "ffff" (cuatro caracteres "f") presenta las diezmilésimas de segundo de
un intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. En una
operación de análisis que llama al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada
debe contener exactamente cuatro dígitos fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "ffff" para mostrar las diezmilésimas
de segundo de un valor TimeSpan. "ffff" se usa primero solo y luego junto con el especificador "s" en una cadena
de formato personalizado.

TimeSpan ts = new TimeSpan(1003498765432);


string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432
Dim ts As New TimeSpan(1003498765432)
Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432

Volver a la tabla

Especificador de formato personalizado "fffff"


El especificador de formato personalizado "fffff" (cinco caracteres "f") presenta las cienmilésimas de segundo de
un intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. En una
operación de análisis que llama al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada
debe contener exactamente cinco dígitos fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "fffff" para mostrar las cienmilésimas
de segundo de un valor TimeSpan. "fffff" se usa primero solo y luego junto con el especificador "s" en una cadena
de formato personalizado.
TimeSpan ts = new TimeSpan(1003498765432);
string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432

Dim ts As New TimeSpan(1003498765432)


Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432
Volver a la tabla

Especificador de formato personalizado "ffffff"


El especificador de formato personalizado "ffffff" (seis caracteres "f") presenta las millonésimas de segundo de un
intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. En una
operación de análisis que llama al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada
debe contener exactamente seis dígitos fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "ffffff" para mostrar las millonésimas
de segundo de un valor TimeSpan. Este especificador de formato se utiliza primero solo y, a continuación, junto
con el especificador "s" en una cadena de formato personalizado.

TimeSpan ts = new TimeSpan(1003498765432);


string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432
Dim ts As New TimeSpan(1003498765432)
Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432

Volver a la tabla

Especificador de formato personalizado "fffffff"


El especificador de formato personalizado "fffffff" (siete caracteres "f") presenta las diezmillonésimas de segundo
(o fracciones de paso) de un intervalo de tiempo. En una operación de análisis que llama al método
TimeSpan.ParseExact o TimeSpan.TryParseExact, la cadena de entrada debe contener exactamente siete dígitos
fraccionarios.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "fffffff" para mostrar las fracciones de
paso de un valor TimeSpan. Este especificador de formato se utiliza primero solo y, a continuación, junto con el
especificador "s" en una cadena de formato personalizado.
TimeSpan ts = new TimeSpan(1003498765432);
string fmt;
Console.WriteLine(ts.ToString("c"));
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
if (fmt.Length == 1) fmt = "%" + fmt;
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts);
}
Console.WriteLine();

for (int ctr = 1; ctr <= 7; ctr++) {


fmt = new String('f', ctr);
Console.WriteLine("{0,10}: {1:s\\." + fmt + "}", "s\\." + fmt, ts);
}
// The example displays the following output:
// %f: 8
// ff: 87
// fff: 876
// ffff: 8765
// fffff: 87654
// ffffff: 876543
// fffffff: 8765432
//
// s\.f: 29.8
// s\.ff: 29.87
// s\.fff: 29.876
// s\.ffff: 29.8765
// s\.fffff: 29.87654
// s\.ffffff: 29.876543
// s\.fffffff: 29.8765432

Dim ts As New TimeSpan(1003498765432)


Dim fmt As String
Console.WriteLine(ts.ToString("c"))
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
If fmt.Length = 1 Then fmt = "%" + fmt
Console.WriteLine("{0,10}: {1:" + fmt + "}", fmt, ts)
Next
Console.WriteLine()

For ctr = 1 To 7
fmt = New String("f"c, ctr)
Console.WriteLine("{0,10}: {1:s\." + fmt + "}", "s\." + fmt, ts)
Next
' The example displays the following output:
' %f: 8
' ff: 87
' fff: 876
' ffff: 8765
' fffff: 87654
' ffffff: 876543
' fffffff: 8765432
'
' s\.f: 29.8
' s\.ff: 29.87
' s\.fff: 29.876
' s\.ffff: 29.8765
' s\.fffff: 29.87654
' s\.ffffff: 29.876543
' s\.fffffff: 29.8765432
Volver a la tabla

Especificador de formato personalizado "F"


El especificador de formato personalizado "F" presenta las décimas de segundo de un intervalo de tiempo. En una
operación de formato, se truncan los dígitos fraccionarios restantes. Si el valor de las décimas de segundo de un
intervalo de tiempo es cero, no se incluirá en la cadena de resultado. En una operación de análisis que llama al
método TimeSpan.ParseExact o TimeSpan.TryParseExact, la presencia de las décimas de segundo es opcional.
Si el especificador de formato personalizado "F" se utiliza solo, especifique "%F" de modo que no se interprete
por error como una cadena de formato estándar.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "F" para mostrar las décimas de
segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado en una operación
de análisis.

Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.669");
Console.WriteLine("{0} ('%F') --> {0:%F}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.091");


Console.WriteLine("{0} ('ss\\.F') --> {0:ss\\.F}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.1", "0:0:03.12" };
string fmt = @"h\:m\:ss\.F";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6690000 ('%F') --> 6
// 00:00:03.0910000 ('ss\.F') --> 03.
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.F') --> 00:00:03
// 0:0:03.1 ('h\:m\:ss\.F') --> 00:00:03.1000000
// Cannot parse 0:0:03.12 with 'h\:m\:ss\.F'.
Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.669")
Console.WriteLine("{0} ('%F') --> {0:%F}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.091")


Console.WriteLine("{0} ('ss\.F') --> {0:ss\.F}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.1", "0:0:03.12" }
Dim fmt As String = "h\:m\:ss\.F"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6690000 ('%F') --> 6
' 00:00:03.0910000 ('ss\.F') --> 03.
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.F') --> 00:00:03
' 0:0:03.1 ('h\:m\:ss\.F') --> 00:00:03.1000000
' Cannot parse 0:0:03.12 with 'h\:m\:ss\.F'.

Volver a la tabla

Especificador de formato personalizado "FF"


El especificador de formato personalizado "FF" presenta las centésimas de segundo de un intervalo de tiempo. En
una operación de formato, se truncan los dígitos fraccionarios restantes. Si hay ceros fraccionarios finales, estos
no se incluyen en la cadena de resultado. En una operación de análisis que llama al método TimeSpan.ParseExact
o TimeSpan.TryParseExact, la presencia de las décimas y centésimas de segundo es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FF" para mostrar las centésimas de
segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado en una operación
de análisis.
Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.697");
Console.WriteLine("{0} ('FF') --> {0:FF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.809");


Console.WriteLine("{0} ('ss\\.FF') --> {0:ss\\.FF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.1", "0:0:03.127" };
string fmt = @"h\:m\:ss\.FF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6970000 ('FF') --> 69
// 00:00:03.8090000 ('ss\.FF') --> 03.8
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FF') --> 00:00:03
// 0:0:03.1 ('h\:m\:ss\.FF') --> 00:00:03.1000000
// Cannot parse 0:0:03.127 with 'h\:m\:ss\.FF'.

Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.697")
Console.WriteLine("{0} ('FF') --> {0:FF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.809")


Console.WriteLine("{0} ('ss\.FF') --> {0:ss\.FF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.1", "0:0:03.127" }
Dim fmt As String = "h\:m\:ss\.FF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6970000 ('FF') --> 69
' 00:00:03.8090000 ('ss\.FF') --> 03.8
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FF') --> 00:00:03
' 0:0:03.1 ('h\:m\:ss\.FF') --> 00:00:03.1000000
' Cannot parse 0:0:03.127 with 'h\:m\:ss\.FF'.

Volver a la tabla
Especificador de formato personalizado "FFF"
El especificador de formato personalizado "FFF" (tres caracteres "F") presenta las milésimas de segundo de un
intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. Si hay ceros
fraccionarios finales, estos no se incluyen en la cadena de resultado. En una operación de análisis que llama al
método TimeSpan.ParseExact o TimeSpan.TryParseExact, la presencia de las décimas, centésimas y milésimas de
segundo es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FFF" para mostrar las milésimas de
segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado en una operación
de análisis.

Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.6974");
Console.WriteLine("{0} ('FFF') --> {0:FFF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.8009");


Console.WriteLine("{0} ('ss\\.FFF') --> {0:ss\\.FFF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.12", "0:0:03.1279" };
string fmt = @"h\:m\:ss\.FFF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6974000 ('FFF') --> 697
// 00:00:03.8009000 ('ss\.FFF') --> 03.8
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FFF') --> 00:00:03
// 0:0:03.12 ('h\:m\:ss\.FFF') --> 00:00:03.1200000
// Cannot parse 0:0:03.1279 with 'h\:m\:ss\.FFF'.
Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.6974")
Console.WriteLine("{0} ('FFF') --> {0:FFF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.8009")


Console.WriteLine("{0} ('ss\.FFF') --> {0:ss\.FFF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.12", "0:0:03.1279" }
Dim fmt As String = "h\:m\:ss\.FFF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6974000 ('FFF') --> 697
' 00:00:03.8009000 ('ss\.FFF') --> 03.8
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FFF') --> 00:00:03
' 0:0:03.12 ('h\:m\:ss\.FFF') --> 00:00:03.1200000
' Cannot parse 0:0:03.1279 with 'h\:m\:ss\.FFF'.

Volver a la tabla

Especificador de formato personalizado "FFFF"


El especificador de formato personalizado "FFFF" (cuatro caracteres "F") presenta las diezmilésimas de segundo
de un intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. Si hay
ceros fraccionarios finales, estos no se incluyen en la cadena de resultado. En una operación de análisis que llama
al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la presencia de las décimas, centésimas, milésimas y
diezmilésimas de segundo es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FFFF" para mostrar las
diezmilésimas de segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado
en una operación de análisis.
Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.69749");
Console.WriteLine("{0} ('FFFF') --> {0:FFFF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.80009");


Console.WriteLine("{0} ('ss\\.FFFF') --> {0:ss\\.FFFF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.12", "0:0:03.12795" };
string fmt = @"h\:m\:ss\.FFFF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6974900 ('FFFF') --> 6974
// 00:00:03.8000900 ('ss\.FFFF') --> 03.8
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FFFF') --> 00:00:03
// 0:0:03.12 ('h\:m\:ss\.FFFF') --> 00:00:03.1200000
// Cannot parse 0:0:03.12795 with 'h\:m\:ss\.FFFF'.

Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.69749")
Console.WriteLine("{0} ('FFFF') --> {0:FFFF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.80009")


Console.WriteLine("{0} ('ss\.FFFF') --> {0:ss\.FFFF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.12", "0:0:03.12795" }
Dim fmt As String = "h\:m\:ss\.FFFF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6974900 ('FFFF') --> 6974
' 00:00:03.8000900 ('ss\.FFFF') --> 03.8
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FFFF') --> 00:00:03
' 0:0:03.12 ('h\:m\:ss\.FFFF') --> 00:00:03.1200000
' Cannot parse 0:0:03.12795 with 'h\:m\:ss\.FFFF'.

Volver a la tabla
Especificador de formato personalizado "FFFFF"
El especificador de formato personalizado "FFFFF" (cinco caracteres "F") presenta las cienmilésimas de segundo
de un intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. Si hay
ceros fraccionarios finales, estos no se incluyen en la cadena de resultado. En una operación de análisis que llama
al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la presencia de las décimas, centésimas, milésimas,
diezmilésimas y cienmilésimas de segundo es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FFFFF" para mostrar las
cienmilésimas de segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado
en una operación de análisis.

Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.697497");
Console.WriteLine("{0} ('FFFFF') --> {0:FFFFF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.800009");


Console.WriteLine("{0} ('ss\\.FFFFF') --> {0:ss\\.FFFFF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.12", "0:0:03.127956" };
string fmt = @"h\:m\:ss\.FFFFF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6974970 ('FFFFF') --> 69749
// 00:00:03.8000090 ('ss\.FFFFF') --> 03.8
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FFFF') --> 00:00:03
// 0:0:03.12 ('h\:m\:ss\.FFFF') --> 00:00:03.1200000
// Cannot parse 0:0:03.127956 with 'h\:m\:ss\.FFFF'.
Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.697497")
Console.WriteLine("{0} ('FFFFF') --> {0:FFFFF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.800009")


Console.WriteLine("{0} ('ss\.FFFFF') --> {0:ss\.FFFFF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.12", "0:0:03.127956" }
Dim fmt As String = "h\:m\:ss\.FFFFF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6974970 ('FFFFF') --> 69749
' 00:00:03.8000090 ('ss\.FFFFF') --> 03.8
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FFFF') --> 00:00:03
' 0:0:03.12 ('h\:m\:ss\.FFFF') --> 00:00:03.1200000
' Cannot parse 0:0:03.127956 with 'h\:m\:ss\.FFFF'.

Volver a la tabla

Especificador de formato personalizado "FFFFFF"


El especificador de formato personalizado "FFFFFF" (seis caracteres "F") presenta las millonésimas de segundo
de un intervalo de tiempo. En una operación de formato, se truncan los dígitos fraccionarios restantes. Si hay
ceros fraccionarios finales, estos no se incluyen en la cadena de resultado. En una operación de análisis que llama
al método TimeSpan.ParseExact o TimeSpan.TryParseExact, la presencia de las décimas, centésimas, milésimas,
diezmilésimas, cienmilésimas y millonésimas de segundo es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FFFFFF" para mostrar las
millonésimas de segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado
en una operación de análisis.
Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.6974974");
Console.WriteLine("{0} ('FFFFFF') --> {0:FFFFFF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.8000009");


Console.WriteLine("{0} ('ss\\.FFFFFF') --> {0:ss\\.FFFFFF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.12", "0:0:03.1279569" };
string fmt = @"h\:m\:ss\.FFFFFF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6974974 ('FFFFFF') --> 697497
// 00:00:03.8000009 ('ss\.FFFFFF') --> 03.8
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FFFFFF') --> 00:00:03
// 0:0:03.12 ('h\:m\:ss\.FFFFFF') --> 00:00:03.1200000
// Cannot parse 0:0:03.1279569 with 'h\:m\:ss\.FFFFFF'.

Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.6974974")
Console.WriteLine("{0} ('FFFFFF') --> {0:FFFFFF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.8000009")


Console.WriteLine("{0} ('ss\.FFFFFF') --> {0:ss\.FFFFFF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.12", "0:0:03.1279569" }
Dim fmt As String = "h\:m\:ss\.FFFFFF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6974974 ('FFFFFF') --> 697497
' 00:00:03.8000009 ('ss\.FFFFFF') --> 03.8
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FFFFFF') --> 00:00:03
' 0:0:03.12 ('h\:m\:ss\.FFFFFF') --> 00:00:03.1200000
' Cannot parse 0:0:03.1279569 with 'h\:m\:ss\.FFFFFF'.

Volver a la tabla
Especificador de formato personalizado "FFFFFFF"
El especificador de formato personalizado "FFFFFFF" (siete caracteres "F") presenta las diezmillonésimas de
segundo (o fracciones de paso) de un intervalo de tiempo. Si hay ceros fraccionarios finales, estos no se incluyen
en la cadena de resultado. En una operación de análisis que llama al método TimeSpan.ParseExact or
TimeSpan.TryParseExact, la presencia de los siete dígitos fraccionarios en la cadena de entrada es opcional.
En el siguiente ejemplo, se utiliza el especificador de formato personalizado "FFFFFFF" para mostrar las
fracciones de segundo de un valor TimeSpan. También se utiliza este especificador de formato personalizado en
una operación de análisis.

Console.WriteLine("Formatting:");
TimeSpan ts1 = TimeSpan.Parse("0:0:3.6974974");
Console.WriteLine("{0} ('FFFFFFF') --> {0:FFFFFFF}", ts1);

TimeSpan ts2 = TimeSpan.Parse("0:0:3.9500000");


Console.WriteLine("{0} ('ss\\.FFFFFFF') --> {0:ss\\.FFFFFFF}", ts2);
Console.WriteLine();

Console.WriteLine("Parsing:");
string[] inputs = { "0:0:03.", "0:0:03.12", "0:0:03.1279569" };
string fmt = @"h\:m\:ss\.FFFFFFF";
TimeSpan ts3;

foreach (string input in inputs) {


if (TimeSpan.TryParseExact(input, fmt, null, out ts3))
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3);
else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt);
}
// The example displays the following output:
// Formatting:
// 00:00:03.6974974 ('FFFFFFF') --> 6974974
// 00:00:03.9500000 ('ss\.FFFFFFF') --> 03.95
//
// Parsing:
// 0:0:03. ('h\:m\:ss\.FFFFFFF') --> 00:00:03
// 0:0:03.12 ('h\:m\:ss\.FFFFFFF') --> 00:00:03.1200000
// 0:0:03.1279569 ('h\:m\:ss\.FFFFFFF') --> 00:00:03.1279569
Console.WriteLine("Formatting:")
Dim ts1 As TimeSpan = TimeSpan.Parse("0:0:3.6974974")
Console.WriteLine("{0} ('FFFFFFF') --> {0:FFFFFFF}", ts1)

Dim ts2 As TimeSpan = TimeSpan.Parse("0:0:3.9500000")


Console.WriteLine("{0} ('ss\.FFFFFFF') --> {0:ss\.FFFFFFF}", ts2)
Console.WriteLine()

Console.WriteLine("Parsing:")
Dim inputs() As String = { "0:0:03.", "0:0:03.12", "0:0:03.1279569" }
Dim fmt As String = "h\:m\:ss\.FFFFFFF"
Dim ts3 As TimeSpan

For Each input As String In inputs


If TimeSpan.TryParseExact(input, fmt, Nothing, ts3)
Console.WriteLine("{0} ('{1}') --> {2}", input, fmt, ts3)
Else
Console.WriteLine("Cannot parse {0} with '{1}'.",
input, fmt)
End If
Next
' The example displays the following output:
' Formatting:
' 00:00:03.6974974 ('FFFFFFF') --> 6974974
' 00:00:03.9500000 ('ss\.FFFFFFF') --> 03.95
'
' Parsing:
' 0:0:03. ('h\:m\:ss\.FFFFFFF') --> 00:00:03
' 0:0:03.12 ('h\:m\:ss\.FFFFFFF') --> 00:00:03.1200000
' 0:0:03.1279569 ('h\:m\:ss\.FFFFFFF') --> 00:00:03.1279569

Volver a la tabla

Otros caracteres
Cualquier otro carácter sin escape de una cadena de formato, incluido el carácter de espacio en blanco, se
interpreta como especificador de formato personalizado. En la mayoría de los casos, la presencia de cualquier
otro carácter sin escape da lugar a una excepción FormatException.
Para incluir un carácter literal en una cadena de formato, se puede proceder de dos formas:
Se puede escribirlo entre comillas sencillas (delimitador de cadena literal).
Se puede anteponer una barra diagonal inversa ("\"), que se interpreta como un carácter de escape. En C#,
esto significa que la cadena de formato debe ser @-quoted o que el carácter literal debe ir precedido de
una barra diagonal inversa adicional.
En algunos casos, puede que sea necesario usar lógica condicional para incluir un carácter literal de escape
en una cadena de formato. En el ejemplo siguiente se usa lógica condicional para incluir un símbolo de
signo para los intervalos de tiempo negativos.
using System;

public class Example


{
public static void Main()
{
TimeSpan result = new DateTime(2010, 01, 01) - DateTime.Now;
String fmt = (result < TimeSpan.Zero ? "\\-" : "") + "dd\\.hh\\:mm";

Console.WriteLine(result.ToString(fmt));
Console.WriteLine("Interval: {0:" + fmt + "}", result);
}
}
// The example displays output like the following:
// -1291.10:54
// Interval: -1291.10:54

Module Example
Public Sub Main()
Dim result As TimeSpan = New DateTime(2010, 01, 01) - Date.Now
Dim fmt As String = If(result < TimeSpan.Zero, "\-", "") + "dd\.hh\:mm"

Console.WriteLine(result.ToString(fmt))
Console.WriteLine("Interval: {0:" + fmt + "}", result)
End Sub
End Module
' The example displays output like the following:
' -1291.10:54
' Interval: -1291.10:54

.NET no define ninguna gramática para los separadores en los intervalos de tiempo. Esto significa que los
separadores entre los días y las horas, las horas y los minutos, los minutos y los segundos, y los segundos y las
fracciones de segundo deben tratarse todos como literales de carácter en una cadena de formato.
En el siguiente ejemplo, se utilizan el carácter de escape y la comilla simple para definir una cadena de formato
personalizado que incluye la palabra "minutes" en la cadena de salida.

TimeSpan interval = new TimeSpan(0, 32, 45);


// Escape literal characters in a format string.
string fmt = @"mm\:ss\ \m\i\n\u\t\e\s";
Console.WriteLine(interval.ToString(fmt));
// Delimit literal characters in a format string with the ' symbol.
fmt = "mm':'ss' minutes'";
Console.WriteLine(interval.ToString(fmt));
// The example displays the following output:
// 32:45 minutes
// 32:45 minutes

Dim interval As New TimeSpan(0, 32, 45)


' Escape literal characters in a format string.
Dim fmt As String = "mm\:ss\ \m\i\n\u\t\e\s"
Console.WriteLine(interval.ToString(fmt))
' Delimit literal characters in a format string with the ' symbol.
fmt = "mm':'ss' minutes'"
Console.WriteLine(interval.ToString(fmt))
' The example displays the following output:
' 32:45 minutes
' 32:45 minutes

Volver a la tabla
Vea también
Aplicación de formato a tipos
Cadenas de formato TimeSpan estándar
Cadenas de formato de enumeración
13/01/2020 • 5 minutes to read • Edit Online

Puede usar el método Enum.ToString para crear un objeto de cadena que represente el valor de cadena, numérico
o hexadecimal del miembro de una enumeración. Este método toma una de las cadenas de formato de
enumeración para especificar el valor que quiere que se devuelva.
En las secciones siguientes se enumeran las cadenas de formato de enumeración y los valores que devuelven.
Estos especificadores de formato no distinguen mayúsculas de minúsculas.

Gog
Si es posible, muestra la entrada de enumeración como valor de cadena y, si no, muestra el valor entero de la
instancia actual. Si la enumeración se define con el conjunto de atributos Flags, los valores de cadena de cada
entrada válida se concatenan, separados por comas. Si no se establece el atributo Flags, se muestra un valor no
válido como entrada numérica. En el siguiente ejemplo se muestra el uso del especificador de formato G.

Console.WriteLine(ConsoleColor.Red.ToString("G")); // Displays Red


FileAttributes attributes = FileAttributes.Hidden |
FileAttributes.Archive;
Console.WriteLine(attributes.ToString("G")); // Displays Hidden, Archive

Console.WriteLine(ConsoleColor.Red.ToString("G")) ' Displays Red


Dim attributes As FileAttributes = FileAttributes.Hidden Or _
FileAttributes.Archive
Console.WriteLine(attributes.ToString("G")) ' Displays Hidden, Archive

Fof
Si es posible, muestra la entrada de enumeración como valor de cadena. Si el valor se puede mostrar por
completo como suma de las entradas de la enumeración (aunque el atributo Flags no esté presente), los valores
de cadena de cada entrada válida se concatenan, separados por comas. Si las entradas de enumeración no
pueden determinar completamente el valor, a este se le da formato como valor entero. En el siguiente ejemplo se
muestra el uso del especificador de formato F.

Console.WriteLine(ConsoleColor.Blue.ToString("F")); // Displays Blue


FileAttributes attributes = FileAttributes.Hidden |
FileAttributes.Archive;
Console.WriteLine(attributes.ToString("F")); // Displays Hidden, Archive

Console.WriteLine(ConsoleColor.Blue.ToString("F")) ' Displays Blue


Dim attributes As FileAttributes = FileAttributes.Hidden Or _
FileAttributes.Archive
Console.WriteLine(attributes.ToString("F")) ' Displays Hidden, Archive

Dod
Muestra la entrada de enumeración como valor entero en la representación más corta posible. En el siguiente
ejemplo se muestra el uso del especificador de formato D.
Console.WriteLine(ConsoleColor.Cyan.ToString("D")); // Displays 11
FileAttributes attributes = FileAttributes.Hidden |
FileAttributes.Archive;
Console.WriteLine(attributes.ToString("D")); // Displays 34

Console.WriteLine(ConsoleColor.Cyan.ToString("D")) ' Displays 11


Dim attributes As FileAttributes = FileAttributes.Hidden Or _
FileAttributes.Archive
Console.WriteLine(attributes.ToString("D")) ' Displays 34

Xox
Muestra la entrada de enumeración como valor hexadecimal. El valor se representa con ceros a la izquierda,
según sea necesario, para garantizar que la cadena de resultados tenga dos caracteres para cada byte en el tipo
numérico que subyace en el tipo de enumeración. En el siguiente ejemplo se muestra el uso del especificador de
formato X. En el ejemplo, el tipo subyacente tanto de ConsoleColor como de FileAttributes es Int32, o un entero
de 32 bits (o 4 bytes), que produce una cadena de resultados de ocho caracteres.

Console.WriteLine(ConsoleColor.Cyan.ToString("X")); // Displays 0000000B


FileAttributes attributes = FileAttributes.Hidden |
FileAttributes.Archive;
Console.WriteLine(attributes.ToString("X")); // Displays 00000022

Console.WriteLine(ConsoleColor.Cyan.ToString("X")) ' Displays 0000000B


Dim attributes As FileAttributes = FileAttributes.Hidden Or _
FileAttributes.Archive
Console.WriteLine(attributes.ToString("X")) ' Displays 00000022

Ejemplo
En el ejemplo siguiente se define una enumeración denominada Colors que consta de tres entradas: Red , Blue
y Green .

public enum Color {Red = 1, Blue = 2, Green = 3}

Public Enum Color


Red = 1
Blue = 2
Green = 3
End Enum

Una vez definida la enumeración, se puede declarar una instancia de la siguiente manera.

Color myColor = Color.Green;

Dim myColor As Color = Color.Green

Luego se puede usar el método Color.ToString(System.String) para mostrar el valor de enumeración de


maneras diferentes, según el especificador de formato pasado.
Console.WriteLine("The value of myColor is {0}.",
myColor.ToString("G"));
Console.WriteLine("The value of myColor is {0}.",
myColor.ToString("F"));
Console.WriteLine("The value of myColor is {0}.",
myColor.ToString("D"));
Console.WriteLine("The value of myColor is 0x{0}.",
myColor.ToString("X"));
// The example displays the following output to the console:
// The value of myColor is Green.
// The value of myColor is Green.
// The value of myColor is 3.
// The value of myColor is 0x00000003.

Console.WriteLine("The value of myColor is {0}.", _


myColor.ToString("G"))
Console.WriteLine("The value of myColor is {0}.", _
myColor.ToString("F"))
Console.WriteLine("The value of myColor is {0}.", _
myColor.ToString("D"))
Console.WriteLine("The value of myColor is 0x{0}.", _
myColor.ToString("X"))
' The example displays the following output to the console:
' The value of myColor is Green.
' The value of myColor is Green.
' The value of myColor is 3.
' The value of myColor is 0x00000003.

Vea también
Aplicación de formato a tipos
Formatos compuestos
22/01/2020 • 23 minutes to read • Edit Online

La característica de formato compuesto de .NET toma una lista de objetos y una cadena de formato
compuesto como entrada. Una cadena de formato compuesto está formada por texto fijo combinado con
marcadores de posición indizados, que reciben el nombre de elementos de formato, y que se corresponden
con los objetos de la lista. La operación de formato genera una cadena de resultado compuesta por el texto
fijo original combinado con la representación de cadena de los objetos de la lista.

IMPORTANT
En lugar de usar cadenas de formato compuesto, puede usar cadenas interpoladas si el idioma y la versión de idioma
que está usando son compatibles con ellos. Una cadena interpolada es una cadena que contiene expresiones
interpoladas. Cada expresión interpolada se resuelve con el valor de la expresión y se incluye en la cadena de
resultado cuando se asigna la cadena. Para obtener más información, vea Interpolación de cadenas (Referencia de C#)
y Cadenas interpoladas (referencia de Visual Basic).

La característica de formato compuesto se admite mediante métodos como los siguientes:


String.Format, que devuelve una cadena de resultado con formato.
StringBuilder.AppendFormat, que anexa una cadena de resultado con formato a un objeto
StringBuilder.
Algunas sobrecargas del método Console.WriteLine, que muestran una cadena de resultado con
formato en la consola.
Algunas sobrecargas del método TextWriter.WriteLine, que escriben la cadena de resultado con
formato en una secuencia o un archivo. Las clases derivadas de TextWriter, como StreamWriter y
HtmlTextWriter, también comparten esta funcionalidad.
Debug.WriteLine(String, Object[]), que genera un mensaje con formato para los agentes de escucha
de traza.
Los métodos Trace.TraceError(String, Object[]), Trace.TraceInformation(String, Object[]) y
Trace.TraceWarning(String, Object[]), que generan mensajes con formato para los agentes de escucha
de traza.
El método TraceSource.TraceInformation(String, Object[]), que escribe un método informativo para
los agentes de escucha de traza.

Cadena de formato compuesto


Los métodos compatibles con la característica de formato compuesto utilizan como argumentos una cadena
de formato compuesto y una lista de objetos. Una cadena de formato compuesto consta de cero o más
ejecuciones de texto fijo combinadas con uno o varios elementos de formato. El texto fijo es cualquier cadena
que elija y cada elemento de formato se corresponde con un objeto o estructura de conversión boxing de la
lista. La característica de formato compuesto devuelve una nueva cadena de resultado donde cada elemento
de formato se reemplaza por la representación de cadena del objeto correspondiente de la lista.
Observe el siguiente fragmento de código Format.
string name = "Fred";
String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now);

Dim name As String = "Fred"


String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now)

El texto fijo es " Name = " y " , hours = ". Los elementos de formato son " {0} ", cuyo índice es 0, que
corresponde al objeto name , y " {1:hh} ", cuyo índice es 1, que corresponde al objeto DateTime.Now .

Sintaxis de elemento de formato


Cada elemento de formato presenta la siguiente sintaxis, formada por los siguientes componentes:
{ index[ , alignment][ : formatString] }
Las llaves ("{" y "}") son necesarias.
Index (Componente )
El componente index obligatorio, denominado también especificador de parámetros, es un número que
empieza por 0 que identifica un elemento correspondiente de la lista de objetos. O sea, el elemento de
formato cuyo especificador de parámetro es 0 da formato al primer objeto de la lista, el elemento de formato
cuyo especificador de parámetro es 1 da formato al segundo objeto de la lista, etc. En el ejemplo siguiente se
incluyen cuatro especificadores de parámetros, numerados del cero al tres, para representar números primos
menores que diez:

string primes;
primes = String.Format("Prime numbers less than 10: {0}, {1}, {2}, {3}",
2, 3, 5, 7 );
Console.WriteLine(primes);
// The example displays the following output:
// Prime numbers less than 10: 2, 3, 5, 7

Dim primes As String


primes = String.Format("Prime numbers less than 10: {0}, {1}, {2}, {3}",
2, 3, 5, 7 )
Console.WriteLine(primes)
' The example displays the following output:
' Prime numbers less than 10: 2, 3, 5, 7

Los elementos de formato múltiple se pueden referir al mismo elemento de la lista de objetos mediante la
especificación del mismo especificador de parámetro. Por ejemplo, se puede dar formato al mismo valor
numérico en formato hexadecimal, científico y de número mediante la especificación de una cadena de
formato compuesto como esta: "0x{0:X} {0:E } {0:N }", como se muestra en el ejemplo siguiente.

string multiple = String.Format("0x{0:X} {0:E} {0:N}",


Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
// 0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
Int64.MaxValue)
Console.WriteLine(multiple)
' The example displays the following output:
' 0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Cada elemento de formato puede hacer referencia a cualquier objeto de la lista. Por ejemplo, si existen tres
objetos, se puede dar formato al segundo, primero y tercer objeto mediante la especificación de una cadena
de formato compuesto como esta: "{1} {0} {2}". Un objeto al que no hace referencia ningún elemento de
formato se omite. Se produce una excepción FormatException en tiempo de ejecución si un especificador de
parámetro designa un elemento fuera de los límites de la lista de objetos.
Alignment (Componente )
El componente opcional alignment es un entero con signo que indica el ancho de campo con formato
preferido. Si el valor de alignment es menor que la longitud de la cadena con formato, se omite alignment y
se usa la longitud de la cadena con formato como el ancho de campo. Los datos con formato del campo
están alineados a la derecha si alignment es positivo y a la izquierda si alignment es negativo. Si hace falta
relleno, se utiliza un espacio en blanco. Si se especifica alignment, es necesaria la coma.
El siguiente ejemplo define dos matrices, que contiene los nombres de empleados y otra contiene las horas
que han trabajado en un período de dos semanas. La cadena de formato compuesto alinea a la izquierda los
nombres en un campo de 20 caracteres y alinea a la derecha las horas en un campo de 5 caracteres. Tenga
en cuenta que la cadena de formato estándar "N1" también se usa para dar formato a las horas con un dígito
fraccionario.

using System;

public class Example


{
public static void Main()
{
string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
"Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82, 40.333m, 80,
16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");


for (int ctr = 0; ctr < names.Length; ctr++)
Console.WriteLine("{0,-20} {1,5:N1}", names[ctr], hours[ctr]);
}
}
// The example displays the following output:
// Name Hours
//
// Adam 40.0
// Bridgette 6.7
// Carla 40.4
// Daniel 82.0
// Ebenezer 40.3
// Francine 80.0
// George 16.8
Module Example
Public Sub Main()
Dim names() As String = { "Adam", "Bridgette", "Carla", "Daniel",
"Ebenezer", "Francine", "George" }
Dim hours() As Decimal = { 40, 6.667d, 40.39d, 82, 40.333d, 80,
16.75d }

Console.WriteLine("{0,-20} {1,5}", "Name", "Hours")


Console.WriteLine()
For ctr As Integer = 0 To names.Length - 1
Console.WriteLine("{0,-20} {1,5:N1}", names(ctr), hours(ctr))
Next
End Sub
End Module
' The example displays the following output:
' Name Hours
'
' Adam 40.0
' Bridgette 6.7
' Carla 40.4
' Daniel 82.0
' Ebenezer 40.3
' Francine 80.0
' George 16.8

Format String (Componente )


El componente formatString opcional es una cadena de formato adecuada para el tipo de objeto al que se da
formato. Especifique una cadena de formato numérico estándar o personalizado si el objeto correspondiente
es un valor numérico, una cadena de formato de fecha y hora estándar o personalizado si el objeto
correspondiente es un objeto DateTime, o una cadena de formato de enumeración si el objeto
correspondiente es un valor de enumeración. Si no se especifica formatString, se usa el especificador de
formato general ("G") para un tipo numérico, de fecha y hora o de enumeración. Si se especifica
formatString, son necesarios los dos puntos.
En la tabla siguiente se enumeran los tipos o las categorías de tipo de la biblioteca de clases de .NET
Framework que admiten un conjunto predefinido de cadenas de formato, y se proporcionan vínculos a
temas que muestran las cadenas de formato admitidas. Observe que la asignación de formato a cadenas es
un mecanismo extensible que permite definir cadenas de formato nuevas para todos los tipos existentes, así
como definir un conjunto de cadenas de formato admitidas por un tipo definido por la aplicación. Para
obtener más información, consulte los temas sobre las interfaces IFormattable y ICustomFormatter.

TIPO O CATEGORÍA DE TIPO VEA

Tipos de fecha y hora (DateTime, DateTimeOffset) Cadenas con formato de fecha y hora estándar

Cadenas con formato de fecha y hora personalizado

Tipos de enumeración (todos los tipos derivados de Cadenas de formato de enumeración


System.Enum)

Tipos numéricos (BigInteger, Byte, Decimal, Double, Int16, Cadenas con formato numérico estándar
Int32, Int64, SByte, Single, UInt16, UInt32, UInt64)
Cadenas con formato numérico personalizado

Guid Guid.ToString(String)
TIPO O CATEGORÍA DE TIPO VEA

TimeSpan Cadenas de formato TimeSpan estándar

Cadenas de formato TimeSpan personalizado

Llaves de escape
Las llaves de apertura y de cierre se interpretan como el inicio y el final de un elemento de formato. Por lo
tanto, debe utilizar una secuencia de escape para que se muestre una llave de apertura o de cierre literal.
Especifique dos llaves de apertura ("{{") en el texto fijo para que se muestre una llave de apertura ("{"), o dos
llaves de cierre ("}}") para que se muestre una llave de cierre ("}"). Las llaves de un elemento de formato se
interpretan secuencialmente, en el orden en que se encuentran. No se admite la interpretación de llaves
anidadas.
El modo de interpretar las llaves de escape puede dar lugar a resultados inesperados. Tomemos como
ejemplo el elemento de formato "{{{0:D }}}", cuyo propósito es mostrar una llave de apertura, un valor
numérico con formato de número decimal y una llave de cierre; pero que, en la práctica, se interpreta de la
siguiente forma:
1. Las dos primeras llaves de apertura ("{{") son llaves de escape y dan lugar a en una llave de apertura.
2. Los tres caracteres siguientes ("{0:") se interpretan como el inicio de un elemento de formato.
3. El siguiente carácter ("D") se interpretaría como el especificador de formato numérico estándar
decimal, pero las dos llaves de escape siguientes ("}}") dan lugar a una única llave. Como la cadena
resultante ("D }") no es un especificador de formato numérico estándar, se interpreta como una cadena
de formato personalizado que significa que debe mostrarse la cadena literal "D }".
4. La última llave ("}") se interpreta como el final del elemento de formato.
5. Como resultado final, se muestra la cadena literal "{D }". No se muestra el valor numérico al que se
debía dar formato.
Una forma de escribir código e impedir que las llaves de escape y los elementos de formato se
malinterpreten consiste en dar formato a las llaves y elementos de formato por separado. Es decir, en la
primera operación de formato mostrar una llave de apertura literal, en la siguiente operación mostrar el
resultado del elemento de formato y, por último, en la operación final mostrar una llave de cierre literal. En el
ejemplo siguiente se muestra este enfoque.

int value = 6324;


string output = string.Format("{0}{1:D}{2}",
"{", value, "}");
Console.WriteLine(output);
// The example displays the following output:
// {6324}

Dim value As Integer = 6324


Dim output As String = String.Format("{0}{1:D}{2}", _
"{", value, "}")
Console.WriteLine(output)
' The example displays the following output:
' {6324}

Orden de procesamiento
Si la llamada al método de formato compuesto incluye un argumento IFormatProvider cuyo valor no es
null , el runtime llama al método IFormatProvider.GetFormat para solicitar una implementación de
ICustomFormatter. Si el método es capaz de devolver una implementación de ICustomFormatter, se
almacena en caché el tiempo que dure la llamada de método de formato compuesto.
Cada valor de la lista de parámetros que se corresponda con un elemento de formato se convierte en una
cadena del siguiente modo:
1. Si el valor al que se va a dar formato es null , se devuelve una cadena vacía String.Empty.
2. Si hay disponible una implementación de ICustomFormatter, el runtime llama al método Format.
Pasa al método el valor formatString del elemento de formato, si hay alguno, o null si no lo hay,
junto con la implementación de IFormatProvider. Si la llamada al método ICustomFormatter.Format
devuelve null , la ejecución avanza al siguiente paso; en caso contrario, se devuelve el resultado de la
llamada a ICustomFormatter.Format.
3. Si el valor implementa la interfaz IFormattable, se llama al método ToString(String, IFormatProvider)
de esta. Se pasa al método el valor formatString, si hubiera uno presente en el elemento de formato, o
null si no lo hubiera. El argumento IFormatProvider se determina de la siguiente forma:

Para un valor numérico, si se llama a un método de formato compuesto con un argumento


IFormatProvider que no sea null, el runtime solicita un objeto NumberFormatInfo a su método
IFormatProvider.GetFormat. En caso de no poder proporcionar uno, si el valor del argumento
es null , o si el método de formato compuesto no tiene un parámetro IFormatProvider, se usa
el objeto NumberFormatInfo para la referencia cultural del subproceso actual.
Para un valor de fecha y hora, si se llama a un método de formato compuesto con un
argumento IFormatProvider que no sea nulo, el runtime solicita un objeto
DateTimeFormatInfo a su método IFormatProvider.GetFormat. En caso de no poder
proporcionar uno, si el valor del argumento es null , o si el método de formato compuesto no
tiene un parámetro IFormatProvider, se usa el objeto DateTimeFormatInfo para la referencia
cultural del subproceso actual.
Para objetos de otros tipos, si se llama a un formato compuesto con un argumento
IFormatProvider, su valor se pasa directamente a la implementación IFormattable.ToString. En
caso contrario, null se pasa a la implementación IFormattable.ToString.
4. Se llama al método sin parámetros ToString del tipo, que reemplaza a Object.ToString() o hereda el
comportamiento de su clase base. En este caso, se omite la cadena de formato especificada por el
componente formatString en el elemento de formato, si estuviera presente.
La alineación se aplica después de que se hayan realizado los pasos anteriores.

Ejemplos de código
En el ejemplo siguiente se muestra una cadena creada mediante formato compuesto y otra creada mediante
el método ToString de un objeto. Los dos tipos de formato producen resultados equivalentes.

string FormatString1 = String.Format("{0:dddd MMMM}", DateTime.Now);


string FormatString2 = DateTime.Now.ToString("dddd MMMM");

Dim FormatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)


Dim FormatString2 As String = DateTime.Now.ToString("dddd MMMM")

Si tomamos como día actual un jueves del mes de mayo, el valor de ambas cadenas del ejemplo anterior
será Thursday May para la referencia cultural Inglés (Estados Unidos).
Console.WriteLine expone la misma funcionalidad que String.Format. La única diferencia que existe entre
estos dos métodos es que String.Format devuelve el resultado como una cadena, mientras que
Console.WriteLine escribe el resultado en el flujo de salida asociado al objeto Console. En el ejemplo
siguiente se usa el método Console.WriteLine para dar formato al valor de MyInt como un valor de divisa.

int MyInt = 100;


Console.WriteLine("{0:C}", MyInt);
// The example displays the following output
// if en-US is the current culture:
// $100.00

Dim MyInt As Integer = 100


Console.WriteLine("{0:C}", MyInt)
' The example displays the following output
' if en-US is the current culture:
' $100.00

En el siguiente ejemplo se muestra la aplicación de formato a objetos múltiples, incluida la aplicación de


formato a un objeto de dos formas diferentes.

string myName = "Fred";


Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
myName, DateTime.Now));
// Depending on the current time, the example displays output like the following:
// Name = Fred, hours = 11, minutes = 30

Dim myName As String = "Fred"


Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}", _
myName, DateTime.Now))
' Depending on the current time, the example displays output like the following:
' Name = Fred, hours = 11, minutes = 30

En el ejemplo siguiente se muestra el uso de la alineación en la aplicación de formato. Los argumentos a los
que se da formato se colocan entre caracteres verticales (|) para resaltar la alineación resultante.
string myFName = "Fred";
string myLName = "Opals";
int myInt = 100;
string FormatFName = String.Format("First Name = |{0,10}|", myFName);
string FormatLName = String.Format("Last Name = |{0,10}|", myLName);
string FormatPrice = String.Format("Price = |{0,10:C}|", myInt);
Console.WriteLine(FormatFName);
Console.WriteLine(FormatLName);
Console.WriteLine(FormatPrice);
Console.WriteLine();

FormatFName = String.Format("First Name = |{0,-10}|", myFName);


FormatLName = String.Format("Last Name = |{0,-10}|", myLName);
FormatPrice = String.Format("Price = |{0,-10:C}|", myInt);
Console.WriteLine(FormatFName);
Console.WriteLine(FormatLName);
Console.WriteLine(FormatPrice);
// The example displays the following output on a system whose current
// culture is en-US:
// First Name = | Fred|
// Last Name = | Opals|
// Price = | $100.00|
//
// First Name = |Fred |
// Last Name = |Opals |
// Price = |$100.00 |

Dim myFName As String = "Fred"


Dim myLName As String = "Opals"

Dim myInt As Integer = 100


Dim FormatFName As String = String.Format("First Name = |{0,10}|", myFName)
Dim FormatLName As String = String.Format("Last Name = |{0,10}|", myLName)
Dim FormatPrice As String = String.Format("Price = |{0,10:C}|", myInt)
Console.WriteLine(FormatFName)
Console.WriteLine(FormatLName)
Console.WriteLine(FormatPrice)
Console.WriteLine()

FormatFName = String.Format("First Name = |{0,-10}|", myFName)


FormatLName = String.Format("Last Name = |{0,-10}|", myLName)
FormatPrice = String.Format("Price = |{0,-10:C}|", myInt)
Console.WriteLine(FormatFName)
Console.WriteLine(FormatLName)
Console.WriteLine(FormatPrice)
' The example displays the following output on a system whose current
' culture is en-US:
' First Name = | Fred|
' Last Name = | Opals|
' Price = | $100.00|
'
' First Name = |Fred |
' Last Name = |Opals |
' Price = |$100.00 |

Vea también
WriteLine
String.Format
Interpolación de cadenas en C#
Cadenas interpoladas (referencia de Visual Basic)
Aplicación de formato a tipos
Cadenas con formato numérico estándar
Cadenas con formato numérico personalizado
Cadenas con formato de fecha y hora estándar
Cadenas con formato de fecha y hora personalizado
Cadenas de formato TimeSpan estándar
Cadenas de formato TimeSpan personalizado
Cadenas de formato de enumeración
Efectuar operaciones de formato
20/01/2020 • 2 minutes to read • Edit Online

En los temas siguientes se proporcionan instrucciones detalladas para realizar operaciones de formato concretas.
Cómo: Rellenar un número con ceros a la izquierda
Cómo: Definir y usar proveedores de formato numérico personalizado
Cómo: Extraer el día de la semana de una fecha concreta.
Cómo: Aplicar acciones de ida y vuelta a valores de fecha y hora
Cómo: Mostrar milisegundos en valores de fecha y hora
Cómo: Mostrar fechas en calendarios no gregorianos

Vea también
Aplicación de formato a tipos
Procedimiento para rellenar un número con ceros a
la izquierda
04/11/2019 • 10 minutes to read • Edit Online

Si quiere agregar ceros a la izquierda de un entero, puede hacerlo mediante la cadena de formato numérico
estándar "D" con un especificador de precisión. Para agregar ceros a la izquierda tanto de enteros como de
números de punto flotante, use una cadena de formato numérico personalizada. En este artículo se explica cómo
usar ambos métodos para rellenar un número con ceros a la izquierda.

Para rellenar un entero con ceros a la izquierda hasta una longitud


concreta
1. Determine el número mínimo de dígitos que desea que muestre el valor entero. Incluya los dígitos a la
izquierda en este número.
2. Determine si desea mostrar el entero como valor decimal o hexadecimal.
Para mostrar el entero como valor decimal, llame a su método ToString(String) y pase la cadena
"Dn" como valor del parámetro format , donde n representa la longitud mínima de la cadena.
Para mostrar el entero como valor hexadecimal, llame a su método ToString(String) y pase la
cadena "Xn" como valor del parámetro format, donde n representa la longitud mínima de la cadena.
También puede usar la cadena de formato en una cadena interpolada en ambos, C# y Visual Basic, o puede llamar
a un método, como String.Format o Console.WriteLine, que usa formato compuesto.
En el ejemplo siguiente se aplica formato a varios valores enteros con ceros a la izquierda de modo que la
longitud mínima total del número con formato sea de ocho caracteres.
byte byteValue = 254;
short shortValue = 10342;
int intValue = 1023983;
long lngValue = 6985321;
ulong ulngValue = UInt64.MaxValue;

// Display integer values by calling the ToString method.


Console.WriteLine("{0,22} {1,22}", byteValue.ToString("D8"), byteValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", shortValue.ToString("D8"), shortValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", intValue.ToString("D8"), intValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", lngValue.ToString("D8"), lngValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", ulngValue.ToString("D8"), ulngValue.ToString("X8"));
Console.WriteLine();

// Display the same integer values by using composite formatting.


Console.WriteLine("{0,22:D8} {0,22:X8}", byteValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", shortValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", intValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", lngValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", ulngValue);
// The example displays the following output:
// 00000254 000000FE
// 00010342 00002866
// 01023983 000F9FEF
// 06985321 006A9669
// 18446744073709551615 FFFFFFFFFFFFFFFF
//
// 00000254 000000FE
// 00010342 00002866
// 01023983 000F9FEF
// 06985321 006A9669
// 18446744073709551615 FFFFFFFFFFFFFFFF
// 18446744073709551615 FFFFFFFFFFFFFFFF
Dim byteValue As Byte = 254
Dim shortValue As Short = 10342
Dim intValue As Integer = 1023983
Dim lngValue As Long = 6985321
Dim ulngValue As ULong = UInt64.MaxValue

' Display integer values by calling the ToString method.


Console.WriteLine("{0,22} {1,22}", byteValue.ToString("D8"), byteValue.ToString("X8"))
Console.WriteLine("{0,22} {1,22}", shortValue.ToString("D8"), shortValue.ToString("X8"))
Console.WriteLine("{0,22} {1,22}", intValue.ToString("D8"), intValue.ToString("X8"))
Console.WriteLine("{0,22} {1,22}", lngValue.ToString("D8"), lngValue.ToString("X8"))
Console.WriteLine("{0,22} {1,22}", ulngValue.ToString("D8"), ulngValue.ToString("X8"))
Console.WriteLine()

' Display the same integer values by using composite formatting.


Console.WriteLine("{0,22:D8} {0,22:X8}", byteValue)
Console.WriteLine("{0,22:D8} {0,22:X8}", shortValue)
Console.WriteLine("{0,22:D8} {0,22:X8}", intValue)
Console.WriteLine("{0,22:D8} {0,22:X8}", lngValue)
Console.WriteLine("{0,22:D8} {0,22:X8}", ulngValue)
' The example displays the following output:
' 00000254 000000FE
' 00010342 00002866
' 01023983 000F9FEF
' 06985321 006A9669
' 18446744073709551615 FFFFFFFFFFFFFFFF
'
' 00000254 000000FE
' 00010342 00002866
' 01023983 000F9FEF
' 06985321 006A9669
' 18446744073709551615 FFFFFFFFFFFFFFFF

Para rellenar un entero con una determinada cantidad de ceros a la


izquierda
1. Determine cuántos ceros a la izquierda desea que muestre el valor entero.
2. Determine si desea mostrar el entero como valor decimal o hexadecimal.
Para darle formato como valor decimal, se requiere que use el especificador de formato estándar
"D".
Para darle formato como valor hexadecimal, se requiere que use el especificador de formato
estándar "X".
3. Determine la longitud de la cadena numérica sin rellenar mediante una llamada a los métodos
ToString("D").Length o ToString("X").Length del valor entero.

4. Agregue el número de ceros a la izquierda que desea incluir en la cadena con formato a la longitud de la
cadena numérica sin rellenar. Al agregar el número de ceros iniciales se define la longitud total de la cadena
rellenada.
5. Llame al método ToString(String) del valor entero y pase la cadena "Dn" para cadenas decimales y "Xn"
para cadenas hexadecimales, donde n representa la longitud total de la cadena rellenada. También puede
usar la cadena de formato "Dn" o "Xn" en un método que admita formato compuesto.
En el ejemplo siguiente se rellena un valor entero con cinco ceros a la izquierda.
int value = 160934;
int decimalLength = value.ToString("D").Length + 5;
int hexLength = value.ToString("X").Length + 5;
Console.WriteLine(value.ToString("D" + decimalLength.ToString()));
Console.WriteLine(value.ToString("X" + hexLength.ToString()));
// The example displays the following output:
// 00000160934
// 00000274A6

Dim value As Integer = 160934


Dim decimalLength As Integer = value.ToString("D").Length + 5
Dim hexLength As Integer = value.ToString("X").Length + 5
Console.WriteLine(value.ToString("D" + decimalLength.ToString()))
Console.WriteLine(value.ToString("X" + hexLength.ToString()))
' The example displays the following output:
' 00000160934
' 00000274A6

Para rellenar un valor numérico con ceros a la izquierda hasta una


longitud concreta
1. Determine con cuántos dígitos a la izquierda del decimal desea que se represente la cadena del número.
Incluya los ceros a la izquierda en este número total de dígitos.
2. Defina una cadena de formato numérico personalizado en la que se use el marcador de posición cero "0"
para representar el número mínimo de ceros.
3. Llame al método ToString(String) del número y pase la cadena de formato personalizado. También puede
usar la cadena de formato personalizado con interpolación de cadena o con un método que admita formato
compuesto.
En el ejemplo siguiente se da formato a varios valores numéricos con ceros iniciales. Como resultado, la longitud
total del número con formato es de al menos ocho dígitos a la izquierda del separador decimal.
string fmt = "00000000.##";
int intValue = 1053240;
decimal decValue = 103932.52m;
float sngValue = 1549230.10873992f;
double dblValue = 9034521202.93217412;

// Display the numbers using the ToString method.


Console.WriteLine(intValue.ToString(fmt));
Console.WriteLine(decValue.ToString(fmt));
Console.WriteLine(sngValue.ToString(fmt));
Console.WriteLine(dblValue.ToString(fmt));
Console.WriteLine();

// Display the numbers using composite formatting.


string formatString = " {0,15:" + fmt + "}";
Console.WriteLine(formatString, intValue);
Console.WriteLine(formatString, decValue);
Console.WriteLine(formatString, sngValue);
Console.WriteLine(formatString, dblValue);
// The example displays the following output:
// 01053240
// 00103932.52
// 01549230
// 9034521202.93
//
// 01053240
// 00103932.52
// 01549230
// 9034521202.93

Dim fmt As String = "00000000.##"


Dim intValue As Integer = 1053240
Dim decValue As Decimal = 103932.52d
Dim sngValue As Single = 1549230.10873992
Dim dblValue As Double = 9034521202.93217412

' Display the numbers using the ToString method.


Console.WriteLine(intValue.ToString(fmt))
Console.WriteLine(decValue.ToString(fmt))
Console.WriteLine(sngValue.ToString(fmt))
Console.WriteLine(dblValue.ToString(fmt))
Console.WriteLine()

' Display the numbers using composite formatting.


Dim formatString As String = " {0,15:" + fmt + "}"
Console.WriteLine(formatString, intValue)
Console.WriteLine(formatString, decValue)
Console.WriteLine(formatString, sngValue)
Console.WriteLine(formatString, dblValue)
' The example displays the following output:
' 01053240
' 00103932.52
' 01549230
' 9034521202.93
'
' 01053240
' 00103932.52
' 01549230
' 9034521202.93

Para rellenar un valor numérico con una determinada cantidad de ceros


a la izquierda
1. Determine cuántos ceros a la izquierda desea que tenga el valor numérico.
2. Determine el número de dígitos a la izquierda del separador decimal que tendrá la cadena numérica sin
rellenar:
a. Determine si la representación de cadena de un número incluye un símbolo de separador decimal.
b. Si incluye un símbolo de separador decimal, determine el número de caracteres a la izquierda del
separador decimal.
O bien
Si no incluye un símbolo de separador decimal, determine la longitud de la cadena.
3. Cree una cadena de formato personalizado que utilice:
El marcador de posición cero "0" para cada uno de los ceros a la izquierda que aparecen en la
cadena.
El marcador de posición cero o el marcador de posición de dígito "#" para representar cada dígito en
la cadena predeterminada.
4. Proporcione la cadena de formato personalizado como un parámetro bien al método ToString(String) del
número, bien a un método que admita el formato compuesto.
En el ejemplo siguiente se rellenan dos valores Double con cinco ceros a la izquierda.

double[] dblValues = { 9034521202.93217412, 9034521202 };


foreach (double dblValue in dblValues)
{
string decSeparator = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
string fmt, formatString;

if (dblValue.ToString().Contains(decSeparator))
{
int digits = dblValue.ToString().IndexOf(decSeparator);
fmt = new String('0', 5) + new String('#', digits) + ".##";
}
else
{
fmt = new String('0', dblValue.ToString().Length);
}
formatString = "{0,20:" + fmt + "}";

Console.WriteLine(dblValue.ToString(fmt));
Console.WriteLine(formatString, dblValue);
}
// The example displays the following output:
// 000009034521202.93
// 000009034521202.93
// 9034521202
// 9034521202
Dim dblValues() As Double = { 9034521202.93217412, 9034521202 }
For Each dblValue As Double In dblValues
Dim decSeparator As String = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator
Dim fmt, formatString As String

If dblValue.ToString.Contains(decSeparator) Then
Dim digits As Integer = dblValue.ToString().IndexOf(decSeparator)
fmt = New String("0"c, 5) + New String("#"c, digits) + ".##"
Else
fmt = New String("0"c, dblValue.ToString.Length)
End If
formatString = "{0,20:" + fmt + "}"

Console.WriteLine(dblValue.ToString(fmt))
Console.WriteLine(formatString, dblValue)
Next
' The example displays the following output:
' 000009034521202.93
' 000009034521202.93
' 9034521202
' 9034521202

Vea también
Custom Numeric Format Strings
Standard Numeric Format Strings
Formatos compuestos
Procedimiento para extraer el día de la semana de
una fecha concreta
04/11/2019 • 11 minutes to read • Edit Online

.NET Framework permite determinar fácilmente el número de día de la semana correspondiente a una fecha
concreta, así como mostrar el nombre localizado del día de la semana para una fecha en particular. Las
propiedades DayOfWeek o DayOfWeek proporcionan un valor enumerado que indica el día de la semana
correspondiente a una fecha concreta. Por el contrario, la recuperación del nombre del día de la semana es una
operación de formato que puede realizarse con una llamada a un método de formato como, por ejemplo, un
método ToString de un valor de fecha y hora o un método String.Format. En este tema se muestra cómo realizar
estas operaciones de formato.
Para obtener un número que indique el día de la semana a partir de una fecha específica
1. Cuando trabaje con la representación de cadena de una fecha, conviértala en un valor DateTime o
DateTimeOffset mediante el método estático DateTime.Parse o DateTimeOffset.Parse.
2. Use las propiedades DateTime.DayOfWeek o DateTimeOffset.DayOfWeek para recuperar un valor
DayOfWeek que indique el día de la semana.
3. En caso necesario, convierta (en C# o en Visual Basic) el valor DayOfWeek en un entero.
En el ejemplo siguiente se muestra un entero que representa el día de la semana de una fecha concreta.

using System;

public class Example


{
public static void Main()
{
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine((int) dateValue.DayOfWeek);
}
}
// The example displays the following output:
// 3

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#
Console.WriteLine(dateValue.DayOfWeek)
End Sub
End Module
' The example displays the following output:
' 3

Para obtener el nombre abreviado del día de la semana a partir de una fecha específica
1. Cuando trabaje con la representación de cadena de una fecha, conviértala en un valor DateTime o
DateTimeOffset mediante el método estático DateTime.Parse o DateTimeOffset.Parse.
2. Puede obtener el nombre abreviado de un día de la semana de la referencia cultural actual o de una
referencia cultural específica:
a. Para obtener el nombre abreviado del día de la semana de la referencia cultural actual, llame al
método de instancia DateTime.ToString(String) o DateTimeOffset.ToString(String) del valor de fecha
y hora, y pase la cadena "ddd" como parámetro format . En el ejemplo siguiente se muestra la
llamada al método ToString(String).

using System;

public class Example


{
public static void Main()
{
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine(dateValue.ToString("ddd"));
}
}
// The example displays the following output:
// Wed

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#
Console.WriteLine(dateValue.ToString("ddd"))
End Sub
End Module
' The example displays the following output:
' Wed

b. Para obtener el nombre abreviado del día de la semana de una referencia cultural específica, llame al
método de instancia DateTime.ToString(String, IFormatProvider) o DateTimeOffset.ToString(String,
IFormatProvider) del valor de fecha y hora. Pase la cadena "ddd" como parámetro format . Pase un
objeto CultureInfo o DateTimeFormatInfo que represente la referencia cultural cuyo nombre del día
de la semana desee recuperar como parámetro provider . En el código siguiente se muestra una
llamada al método ToString(String, IFormatProvider) con un objeto CultureInfo que representa la
referencia cultural fr-FR.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine(dateValue.ToString("ddd",
new CultureInfo("fr-FR")));
}
}
// The example displays the following output:
// mer.
Imports System.Globalization

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#
Console.WriteLine(dateValue.ToString("ddd",
New CultureInfo("fr-FR")))
End Sub
End Module
' The example displays the following output:
' mer.

Para obtener el nombre completo del día de la semana a partir de una fecha específica
1. Cuando trabaje con la representación de cadena de una fecha, conviértala en un valor DateTime o
DateTimeOffset mediante el método estático DateTime.Parse o DateTimeOffset.Parse.
2. Puede obtener el nombre completo de un día de la semana de la referencia cultural actual o de una
referencia cultural específica:
a. Para obtener el nombre del día de la semana de la referencia cultural actual, llame al método de
instancia DateTime.ToString(String) o DateTimeOffset.ToString(String) del valor de fecha y hora, y
pase la cadena "dddd" como parámetro format . En el ejemplo siguiente se muestra la llamada al
método ToString(String).

using System;

public class Example


{
public static void Main()
{
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine(dateValue.ToString("dddd"));
}
}
// The example displays the following output:
// Wednesday

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#
Console.WriteLine(dateValue.ToString("dddd"))
End Sub
End Module
' The example displays the following output:
' Wednesday

b. Para obtener el nombre del día de la semana de una referencia cultural específica, llame al método
de instancia DateTime.ToString(String, IFormatProvider) o DateTimeOffset.ToString(String,
IFormatProvider) del valor de fecha y hora. Pase la cadena "dddd" como parámetro format . Pase un
objeto CultureInfo o DateTimeFormatInfo que represente la referencia cultural cuyo nombre del día
de la semana desee recuperar como parámetro provider . En el código siguiente se muestra una
llamada al método ToString(String, IFormatProvider) con un objeto CultureInfo que representa la
referencia cultural es-ES.
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
DateTime dateValue = new DateTime(2008, 6, 11);
Console.WriteLine(dateValue.ToString("dddd",
new CultureInfo("es-ES")));
}
}
// The example displays the following output:
// miércoles.

Imports System.Globalization

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#
Console.WriteLine(dateValue.ToString("dddd", _
New CultureInfo("es-ES")))
End Sub
End Module
' The example displays the following output:
' miércoles.

Ejemplo
En el ejemplo se muestran llamadas a las propiedades DateTime.DayOfWeek y DateTimeOffset.DayOfWeek y los
métodos DateTime.ToString y DateTimeOffset.ToString para recuperar el número que representa el día de la
semana, el nombre abreviado del día de la semana y el nombre completo del día de la semana para una fecha en
particular.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
string dateString = "6/11/2007";
DateTime dateValue;
DateTimeOffset dateOffsetValue;

try
{
DateTimeFormatInfo dateTimeFormats;
// Convert date representation to a date value
dateValue = DateTime.Parse(dateString, CultureInfo.InvariantCulture);
dateOffsetValue = new DateTimeOffset(dateValue,
TimeZoneInfo.Local.GetUtcOffset(dateValue));

// Convert date representation to a number indicating the day of week


Console.WriteLine((int) dateValue.DayOfWeek);
Console.WriteLine((int) dateOffsetValue.DayOfWeek);

// Display abbreviated weekday name using current culture


Console.WriteLine(dateValue.ToString("ddd"));
Console.WriteLine(dateOffsetValue.ToString("ddd"));

// Display full weekday name using current culture


Console.WriteLine(dateValue.ToString("dddd"));
Console.WriteLine(dateValue.ToString("dddd"));
Console.WriteLine(dateOffsetValue.ToString("dddd"));

// Display abbreviated weekday name for de-DE culture


Console.WriteLine(dateValue.ToString("ddd", new CultureInfo("de-DE")));
Console.WriteLine(dateOffsetValue.ToString("ddd",
new CultureInfo("de-DE")));

// Display abbreviated weekday name with de-DE DateTimeFormatInfo object


dateTimeFormats = new CultureInfo("de-DE").DateTimeFormat;
Console.WriteLine(dateValue.ToString("ddd", dateTimeFormats));
Console.WriteLine(dateOffsetValue.ToString("ddd", dateTimeFormats));

// Display full weekday name for fr-FR culture


Console.WriteLine(dateValue.ToString("ddd", new CultureInfo("fr-FR")));
Console.WriteLine(dateOffsetValue.ToString("ddd",
new CultureInfo("fr-FR")));

// Display abbreviated weekday name with fr-FR DateTimeFormatInfo object


dateTimeFormats = new CultureInfo("fr-FR").DateTimeFormat;
Console.WriteLine(dateValue.ToString("dddd", dateTimeFormats));
Console.WriteLine(dateOffsetValue.ToString("dddd", dateTimeFormats));
}
catch (FormatException)
{
Console.WriteLine("Unable to convert {0} to a date.", dateString);
}
}
}
// The example displays the following output:
// 1
// 1
// Mon
// Mon
// Monday
// Monday
// Mo
// Mo
// Mo
// Mo
// lun.
// lun.
// lundi
// lundi
Imports System.Globalization

Module Example
Public Sub Main()
Dim dateString As String = "6/11/2007"
Dim dateValue As Date
Dim dateOffsetValue As DateTimeOffset

Try
Dim dateTimeFormats As DateTimeFormatInfo
' Convert date representation to a date value
dateValue = Date.Parse(dateString, CultureInfo.InvariantCulture)
dateOffsetValue = New DateTimeOffset(dateValue, _
TimeZoneInfo.Local.GetUtcOffset(dateValue))
' Convert date representation to a number indicating the day of week
Console.WriteLine(dateValue.DayOfWeek)
Console.WriteLine(dateOffsetValue.DayOfWeek)

' Display abbreviated weekday name using current culture


Console.WriteLine(dateValue.ToString("ddd"))
Console.WriteLine(dateOffsetValue.ToString("ddd"))

' Display full weekday name using current culture


Console.WriteLine(dateValue.ToString("dddd"))
Console.WriteLine(dateOffsetValue.ToString("dddd"))

' Display abbreviated weekday name for de-DE culture


Console.WriteLine(dateValue.ToString("ddd", New CultureInfo("de-DE")))
Console.WriteLine(dateOffsetValue.ToString("ddd", _
New CultureInfo("de-DE")))

' Display abbreviated weekday name with de-DE DateTimeFormatInfo object


dateTimeFormats = New CultureInfo("de-DE").DateTimeFormat
Console.WriteLine(dateValue.ToString("ddd", dateTimeFormats))
Console.WriteLine(dateOffsetValue.ToString("ddd", dateTimeFormats))

' Display full weekday name for fr-FR culture


Console.WriteLine(dateValue.ToString("ddd", New CultureInfo("fr-FR")))
Console.WriteLine(dateOffsetValue.ToString("ddd", _
New CultureInfo("fr-FR")))

' Display abbreviated weekday name with fr-FR DateTimeFormatInfo object


dateTimeFormats = New CultureInfo("fr-FR").DateTimeFormat
Console.WriteLine(dateValue.ToString("dddd", dateTimeFormats))
Console.WriteLine(dateOffsetValue.ToString("dddd", dateTimeFormats))
Catch e As FormatException
Console.WriteLine("Unable to convert {0} to a date.", dateString)
End Try
End Sub
End Module
' The example displays the following output to the console:
' 1
' 1
' Mon
' Mon
' Monday
' Monday
' Mo
' Mo
' Mo
' Mo
' lun.
' lun.
' lundi
' lundi
Puede haber lenguajes que ofrezcan una funcionalidad que duplique o complemente a la proporcionada por .NET
Framework. Por ejemplo, Visual Basic incluye dos funciones así:
Weekday , que devuelve un número que indica el día de la semana a partir de una fecha específica.
Considera que el valor ordinal del primer día de la semana es uno, mientras que la propiedad
DateTime.DayOfWeek considera que es cero.
WeekdayName , que devuelve el nombre de la semana en la referencia cultural actual que corresponde a un
número concreto del día de la semana.
En el ejemplo siguiente se demuestra el uso de las funciones Weekday y WeekdayName .

Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim dateValue As Date = #6/11/2008#

' Get weekday number using Visual Basic Weekday function


Console.WriteLine(Weekday(dateValue)) ' Displays 4
' Compare with .NET DateTime.DayOfWeek property
Console.WriteLine(dateValue.DayOfWeek) ' Displays 3

' Get weekday name using Weekday and WeekdayName functions


Console.WriteLine(WeekdayName(Weekday(dateValue))) ' Displays Wednesday

' Change culture to de-DE


Dim originalCulture As CultureInfo = Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture = New CultureInfo("de-DE")
' Get weekday name using Weekday and WeekdayName functions
Console.WriteLine(WeekdayName(Weekday(dateValue))) ' Displays Donnerstag

' Restore original culture


Thread.CurrentThread.CurrentCulture = originalCulture
End Sub
End Module

También se puede usar el valor devuelto por la propiedad DateTime.DayOfWeek para recuperar el nombre del día
de la semana de una fecha en particular. Para ello, solo se necesita hacer una llamada al método ToString en el
valor DayOfWeek devuelto por la propiedad. Sin embargo, esta técnica no produce el nombre localizado de un día
de la semana para la referencia cultural actual, tal como se muestra en el ejemplo siguiente.
using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
// Change current culture to fr-FR
CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");

DateTime dateValue = new DateTime(2008, 6, 11);


// Display the DayOfWeek string representation
Console.WriteLine(dateValue.DayOfWeek.ToString());
// Restore original current culture
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
// The example displays the following output:
// Wednesday

Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
' Change current culture to fr-FR
Dim originalCulture As CultureInfo = Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture = New CultureInfo("fr-FR")

Dim dateValue As Date = #6/11/2008#


' Display the DayOfWeek string representation
Console.WriteLine(dateValue.DayOfWeek.ToString())
' Restore original current culture
Thread.CurrentThread.CurrentCulture = originalCulture
End Sub
End Module
' The example displays the following output:
' Wednesday

Vea también
Efectuar operaciones de formato
Standard Date and Time Format Strings
Custom Date and Time Format Strings
Procedimiento para definir y usar proveedores de
formato numérico personalizado
04/11/2019 • 11 minutes to read • Edit Online

.NET Framework ofrece un amplio control sobre la representación de cadena de valores numéricos. Admite las
siguientes características para personalizar el formato de los valores numéricos:
Cadenas con formato numérico estándar, que proporcionan un conjunto predefinido de formatos para
convertir números en su representación de cadena. Se pueden usar con cualquier método de formato
numérico, como Decimal.ToString(String), que tiene un parámetro format . Para obtener detalles, vea
Cadenas con formato numérico estándar.
Cadenas con formato numérico personalizado, que proporcionan un conjunto de símbolos que pueden
combinarse para definir especificadores de formato numérico personalizado. Se pueden usar también con
cualquier método de formato numérico, como Decimal.ToString(String), que tiene un parámetro format .
Para obtener detalles, consulte Cadenas con formato numérico personalizado.
Objetos personalizados CultureInfo o NumberFormatInfo, que definen los símbolos y los modelos de
formato que se usan para mostrar las representaciones de cadena de valores numéricos. Se pueden usar
con cualquier método de formato numérico, como ToString, que tiene un parámetro provider .
Normalmente, el parámetro provider se usa para especificar el formato específico de la referencia cultural.
En algunos casos (por ejemplo, cuando una aplicación debe mostrar un número de cuenta con formato, un número
de identificación o un código postal) estas tres técnicas no resultan apropiadas. .NET Framework también permite
definir un objeto de formato que no es ni un objeto CultureInfo ni NumberFormatInfo para determinar cómo se
aplica formato a un valor numérico. En este tema se proporcionan instrucciones paso a paso para implementar
este tipo de objeto y se ofrece un ejemplo que da formato a números de teléfono.
Para definir un proveedor de formato personalizado
1. Defina una clase que implementa las interfaces IFormatProvider y ICustomFormatter.
2. Implemente el método IFormatProvider.GetFormat. GetFormat es un método de devolución de llamada
que el método de formato (como el método String.Format(IFormatProvider, String, Object[])) invoca para
recuperar el objeto realmente responsable del formato personalizado. Una implementación típica de
GetFormat hace lo siguiente:
a. Determina si el objeto Type pasado como un parámetro de método representa a una interfaz
ICustomFormatter.
b. Si el parámetro representa a la interfaz ICustomFormatter, GetFormat devuelve un objeto que
implementa la interfaz ICustomFormatter, que es responsable de proporcionar el formato
personalizado. Normalmente, el objeto de formato personalizado se devuelve a sí mismo.
c. Si el parámetro no representa la interfaz ICustomFormatter, GetFormat devuelve null .
3. Implemente el método Format. Este método es invocado por el método String.Format(IFormatProvider,
String, Object[]) y es responsable de devolver la representación de cadena de un número. La
implementación del método normalmente implica lo siguiente:
a. Opcionalmente, asegúrese de que el método se haya diseñado para proporcionar servicios de
formato al examinar el parámetro provider . En el caso de los objetos de formato que implementan
IFormatProvider y ICustomFormatter, esto implica probar la igualdad del parámetro provider y el
objeto de formato actual.
b. Determine si el objeto de formato debe admitir especificadores de formato personalizado. (Por
ejemplo, un especificador de formato "N" podría indicar que debe generarse un número de teléfono
de los Estados Unidos en formato NANP, mientras que una "I" podría indicar la salida en el formato
de la recomendación E.123 de ITU -T). Si se usan especificadores de formato, el método debe
controlar el especificador de formato específico. Se pasa al método en el parámetro format . Si no
hay ningún especificador, el valor del parámetro format es String.Empty.
c. Recupere el valor numérico pasado al método como parámetro arg . Realice todas las
manipulaciones necesarias para convertirlo en su representación de cadena.
d. Devuelva la representación de cadena del parámetro arg .
Para usar un objeto de formato numérico personalizado
1. Cree una nueva instancia de la clase de formato personalizado.
2. Llame al método de formato String.Format(IFormatProvider, String, Object[]) y pásele el objeto de formato
personalizado, el especificador de formato (o String.Empty si no se usa ninguno) y el valor numérico al que
se va a dar formato.

Ejemplo
En el ejemplo siguiente se define un proveedor de formato numérico personalizado denominado
TelephoneFormatter que convierte un número que representa un número de teléfono de los Estados Unidos en su
formato NANP o E.123. El método controla dos especificadores de formato, "N" (que genera el formato NANP ) e
"I" (que genera el formato E.123 internacional).

using System;
using System.Globalization;

public class TelephoneFormatter : IFormatProvider, ICustomFormatter


{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}

public string Format(string format, object arg, IFormatProvider formatProvider)


{
// Check whether this is an appropriate callback
if (! this.Equals(formatProvider))
return null;

// Set default format specifier


if (string.IsNullOrEmpty(format))
format = "N";

string numericString = arg.ToString();

if (format == "N")
{
if (numericString.Length <= 4)
return numericString;
else if (numericString.Length == 7)
return numericString.Substring(0, 3) + "-" + numericString.Substring(3, 4);
else if (numericString.Length == 10)
return "(" + numericString.Substring(0, 3) + ") " +
numericString.Substring(3, 3) + "-" + numericString.Substring(6);
else
else
throw new FormatException(
string.Format("'{0}' cannot be used to format {1}.",
format, arg.ToString()));
}
else if (format == "I")
{
if (numericString.Length < 10)
throw new FormatException(string.Format("{0} does not have 10 digits.", arg.ToString()));
else
numericString = "+1 " + numericString.Substring(0, 3) + " " + numericString.Substring(3, 3) + " "
+ numericString.Substring(6);
}
else
{
throw new FormatException(string.Format("The {0} format specifier is invalid.", format));
}
return numericString;
}
}

public class TestTelephoneFormatter


{
public static void Main()
{
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 0));
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 911));
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 8490216));
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 0));


Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 911));
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 8490216));
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:I}", 4257884748));


}
}
Public Class TelephoneFormatter : Implements IFormatProvider, ICustomFormatter
Public Function GetFormat(formatType As Type) As Object _
Implements IFormatProvider.GetFormat
If formatType Is GetType(ICustomFormatter) Then
Return Me
Else
Return Nothing
End If
End Function

Public Function Format(fmt As String, arg As Object, _


formatProvider As IFormatProvider) As String _
Implements ICustomFormatter.Format
' Check whether this is an appropriate callback
If Not Me.Equals(formatProvider) Then Return Nothing

' Set default format specifier


If String.IsNullOrEmpty(fmt) Then fmt = "N"

Dim numericString As String = arg.ToString

If fmt = "N" Then


Select Case numericString.Length
Case <= 4
Return numericString
Case 7
Return Left(numericString, 3) & "-" & Mid(numericString, 4)
Case 10
Return "(" & Left(numericString, 3) & ") " & _
Mid(numericString, 4, 3) & "-" & Mid(numericString, 7)
Case Else
Throw New FormatException( _
String.Format("'{0}' cannot be used to format {1}.", _
fmt, arg.ToString()))
End Select
ElseIf fmt = "I" Then
If numericString.Length < 10 Then
Throw New FormatException(String.Format("{0} does not have 10 digits.", arg.ToString()))
Else
numericString = "+1 " & Left(numericString, 3) & " " & Mid(numericString, 4, 3) & " " &
Mid(numericString, 7)
End If
Else
Throw New FormatException(String.Format("The {0} format specifier is invalid.", fmt))
End If
Return numericString
End Function
End Class

Public Module TestTelephoneFormatter


Public Sub Main
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 0))
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 911))
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 8490216))
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))

Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 0))


Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 911))
Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 8490216))
Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))

Console.WriteLine(String.Format(New TelephoneFormatter, "{0:I}", 4257884748))


End Sub
End Module

El proveedor de formato numérico personalizado puede utilizarse solo con el método


String.Format(IFormatProvider, String, Object[]). Las demás sobrecargas de métodos de formato numérico (como
ToString ) que tienen un parámetro de tipo IFormatProvider pasan a la implementación de
IFormatProvider.GetFormat un objeto Type que representa al tipo NumberFormatInfo. A cambio, esperan que el
método devuelva un objeto NumberFormatInfo. Si no es así, se omite el proveedor de formato numérico
personalizado y se usa el objeto NumberFormatInfo de la referencia cultural actual en su lugar. En el ejemplo, el
método TelephoneFormatter.GetFormat controla la posibilidad de que se pueda pasar incorrectamente a un método
de formato numérico al examinar el parámetro de método y devolver null si representa a un tipo distinto de
ICustomFormatter.
Si un proveedor de formato numérico personalizado admite un conjunto de especificadores de formato, asegúrese
de proporcionar un comportamiento predeterminado si no se proporciona ningún especificador de formato en el
elemento de formato usado en la llamada al método String.Format(IFormatProvider, String, Object[]). En el
ejemplo, "N" es el especificador de formato predeterminado. Esto permite convertir un número en un número de
teléfono con formato al proporcionar un especificador de formato explícito. En el ejemplo siguiente se muestra una
llamada al método así.

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));

Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))

Pero también permite que se produzca la conversión si no hay ningún especificador de formato. En el ejemplo
siguiente se muestra una llamada al método así.

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));

Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))

Si no se ha definido ningún especificador de formato predeterminado, la implementación del método


ICustomFormatter.Format debe incluir código como el siguiente para que .NET pueda proporcionar formato no
admitido por el código.

if (arg is IFormattable)
s = ((IFormattable)arg).ToString(format, formatProvider);
else if (arg != null)
s = arg.ToString();

If TypeOf(arg) Is IFormattable Then


s = DirectCast(arg, IFormattable).ToString(fmt, formatProvider)
ElseIf arg IsNot Nothing Then
s = arg.ToString()
End If

En el caso de este ejemplo, el método que implementa ICustomFormatter.Format está diseñado para que actúe
como un método de devolución de llamada para el método String.Format(IFormatProvider, String, Object[]). Por lo
tanto, examina el parámetro formatProvider para determinar si contiene una referencia al objeto
TelephoneFormatter actual. Pero también se puede llamar al método directamente desde el código. En ese caso,
puede usar el parámetro formatProvider para proporcionar un objeto CultureInfo o NumberFormatInfo que
aporte información de formato específica de la referencia cultural.

Vea también
Efectuar operaciones de formato
Procedimiento para valores de fecha y hora de ida y
vuelta
04/11/2019 • 11 minutes to read • Edit Online

En muchas aplicaciones, un valor de fecha y hora sirve para identificar inequívocamente un único punto en el
tiempo. Este tema muestra cómo guardar y restaurar un valor DateTime, un valor DateTimeOffset y un valor de
fecha y hora con información sobre la zona horaria, de manera que el valor restaurado identifique la misma hora
que el valor guardado.
Para un valor DateTime de ida y vuelta
1. Convierta el valor DateTime en su representación de cadena mediante una llamada al método
DateTime.ToString(String) con el especificador de formato "o".
2. Guarde la representación de cadena del valor DateTime en un archivo o pásela a través de un límite de
proceso, dominio de aplicación o máquina.
3. Recupere la cadena que representa el valor DateTime.
4. Llame al método DateTime.Parse(String, IFormatProvider, DateTimeStyles) y pase
DateTimeStyles.RoundtripKind como el valor del parámetro styles .
En el ejemplo siguiente se muestra cómo usar un valor DateTime de ida y vuelta.

const string fileName = @".\DateFile.txt";

StreamWriter outFile = new StreamWriter(fileName);

// Save DateTime value.


DateTime dateToSave = DateTime.SpecifyKind(new DateTime(2008, 6, 12, 18, 45, 15),
DateTimeKind.Local);
string dateString = dateToSave.ToString("o");
Console.WriteLine("Converted {0} ({1}) to {2}.",
dateToSave.ToString(),
dateToSave.Kind.ToString(),
dateString);
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();

// Restore DateTime value.


DateTime restoredDate;

StreamReader inFile = new StreamReader(fileName);


dateString = inFile.ReadLine();
inFile.Close();
restoredDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(),
fileName,
restoredDate.Kind.ToString());
// The example displays the following output:
// Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
// Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
// Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.
Const fileName As String = ".\DateFile.txt"

Dim outFile As New StreamWriter(fileName)

' Save DateTime value.


Dim dateToSave As Date = DateTime.SpecifyKind(#06/12/2008 6:45:15 PM#, _
DateTimeKind.Local)
Dim dateString As String = dateToSave.ToString("o")
Console.WriteLine("Converted {0} ({1}) to {2}.", dateToSave.ToString(), _
dateToSave.Kind.ToString(), dateString)
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()

' Restore DateTime value.


Dim restoredDate As Date

Dim inFile As New StreamReader(fileName)


dateString = inFile.ReadLine()
inFile.Close()
restoredDate = DateTime.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(), _
fileName, restoredDAte.Kind.ToString())
' The example displays the following output:
' Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
' Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
' Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.

Cuando se usa un valor DateTime de ida y vuelta, esta técnica mantiene correctamente la hora para todas las horas
locales y universales. Por ejemplo, si un valor local DateTime se guarda en un sistema de la zona horaria estándar
del Pacífico de Estados Unidos y se restaura en un sistema de la zona horaria estándar central de Estados Unidos,
la fecha y hora restauradas serán dos horas posteriores a la hora original, lo que refleja la diferencia horaria entre
las dos zonas. Pero esta técnica no es necesariamente precisa para horas no especificadas. Todos los valores
DateTime cuya propiedad Kind es Unspecified se tratan como si fueran horas locales. Si no es el caso, DateTime no
identificará correctamente el punto en el tiempo. La solución alternativa para esta limitación es acoplar
estrechamente un valor de fecha y hora con su zona horaria para la operación de guardado y restauración.
Para un valor DateTimeOffset de ida y vuelta
1. Convierta el valor DateTimeOffset en su representación de cadena mediante una llamada al método
DateTimeOffset.ToString(String) con el especificador de formato "o".
2. Guarde la representación de cadena del valor DateTimeOffset en un archivo o pásela a través de un límite
de proceso, dominio de aplicación o máquina.
3. Recupere la cadena que representa el valor DateTimeOffset.
4. Llame al método DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) y pase
DateTimeStyles.RoundtripKind como el valor del parámetro styles .

En el ejemplo siguiente se muestra cómo usar un valor DateTimeOffset de ida y vuelta.


const string fileName = @".\DateOff.txt";

StreamWriter outFile = new StreamWriter(fileName);

// Save DateTime value.


DateTimeOffset dateToSave = new DateTimeOffset(2008, 6, 12, 18, 45, 15,
new TimeSpan(7, 0, 0));
string dateString = dateToSave.ToString("o");
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(),
dateString);
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();

// Restore DateTime value.


DateTimeOffset restoredDateOff;

StreamReader inFile = new StreamReader(fileName);


dateString = inFile.ReadLine();
inFile.Close();
restoredDateOff = DateTimeOffset.Parse(dateString, null,
DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(),
fileName);
// The example displays the following output:
// Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
// Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
// Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.

Const fileName As String = ".\DateOff.txt"

Dim outFile As New StreamWriter(fileName)

' Save DateTime value.


Dim dateToSave As New DateTimeOffset(2008, 6, 12, 18, 45, 15, _
New TimeSpan(7, 0, 0))
Dim dateString As String = dateToSave.ToString("o")
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(), dateString)
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()

' Restore DateTime value.


Dim restoredDateOff As DateTimeOffset

Dim inFile As New StreamReader(fileName)


dateString = inFile.ReadLine()
inFile.Close()
restoredDateOff = DateTimeOffset.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(), fileName)
' The example displays the following output:
' Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
' Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
' Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.

Esta técnica identifica siempre de forma inequívoca un valor DateTimeOffset como un único punto en el tiempo. El
valor puede convertirse entonces en la hora universal coordinada (UTC ) al llamar al método
DateTimeOffset.ToUniversalTime, o bien puede convertirse en la hora de una zona horaria concreta al llamar a los
métodos DateTimeOffset.ToOffset o TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo). La limitación
principal de esta técnica está en que las operaciones aritméticas de fecha y hora, cuando se realizan en un valor
DateTimeOffset que representa la hora en una zona horaria determinada, podrían no generar resultados precisos
para esa zona horaria. Esto se debe a que, cuando se crea una instancia de un valor DateTimeOffset, se desasocia
de su zona horaria. Por lo tanto, ya no se pueden aplicar las reglas de ajuste de esa zona de horaria al realizar
cálculos de fecha y hora. Para evitar este problema, puede definir un tipo personalizado que incluya tanto el valor
de fecha y hora como la zona horaria correspondiente.
Para un valor de fecha y hora de ida y vuelta con su zona horaria
1. Defina una clase o una estructura con dos campos. El primer campo es un objeto DateTime o
DateTimeOffset y el segundo es un objeto TimeZoneInfo. El ejemplo siguiente es una versión sencilla de
ese tipo.

[Serializable] public class DateInTimeZone


{
private TimeZoneInfo tz;
private DateTimeOffset thisDate;

public DateInTimeZone() {}

public DateInTimeZone(DateTimeOffset date, TimeZoneInfo timeZone)


{
if (timeZone == null)
throw new ArgumentNullException("The time zone cannot be null.");

this.thisDate = date;
this.tz = timeZone;
}

public DateTimeOffset DateAndTime


{
get {
return this.thisDate;
}
set {
if (value.Offset != this.tz.GetUtcOffset(value))
this.thisDate = TimeZoneInfo.ConvertTime(value, tz);
else
this.thisDate = value;
}
}

public TimeZoneInfo TimeZone


{
get {
return this.tz;
}
}
}
<Serializable> Public Class DateInTimeZone
Private tz As TimeZoneInfo
Private thisDate As DateTimeOffset

Public Sub New()


End Sub

Public Sub New(date1 As DateTimeOffset, timeZone As TimeZoneInfo)


If timeZone Is Nothing Then
Throw New ArgumentNullException("The time zone cannot be null.")
End If
Me.thisDate = date1
Me.tz = timeZone
End Sub

Public Property DateAndTime As DateTimeOffset


Get
Return Me.thisDate
End Get
Set
If Value.Offset <> Me.tz.GetUtcOffset(Value) Then
Me.thisDate = TimeZoneInfo.ConvertTime(Value, tz)
Else
Me.thisDate = Value
End If
End Set
End Property

Public ReadOnly Property TimeZone As TimeZoneInfo


Get
Return tz
End Get
End Property
End Class

2. Marque la clase con el atributo SerializableAttribute.


3. Serialice el objeto con el método BinaryFormatter.Serialize.
4. Restaure el objeto con el método Deserialize.
5. Convierta (en C# o en Visual Basic) el objeto deserializado en un objeto del tipo adecuado.
En el ejemplo siguiente se muestra cómo realizar un recorrido de ida y vuelta de un objeto que almacena la
información de fecha y hora y de zona horaria.
const string fileName = @".\DateWithTz.dat";

DateTime tempDate = new DateTime(2008, 9, 3, 19, 0, 0);


TimeZoneInfo tempTz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateInTimeZone dateWithTz = new DateInTimeZone(new DateTimeOffset(tempDate,
tempTz.GetUtcOffset(tempDate)),
tempTz);

// Store DateInTimeZone value to a file


FileStream outFile = new FileStream(fileName, FileMode.Create);
try
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(outFile, dateWithTz);
Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime,
dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime) ?
dateWithTz.TimeZone.DaylightName : dateWithTz.TimeZone.DaylightName,
fileName);
}
catch (SerializationException)
{
Console.WriteLine("Unable to serialize time data to {0}.", fileName);
}
finally
{
outFile.Close();
}

// Retrieve DateInTimeZone value


if (File.Exists(fileName))
{
FileStream inFile = new FileStream(fileName, FileMode.Open);
DateInTimeZone dateWithTz2 = new DateInTimeZone();
try
{
BinaryFormatter formatter = new BinaryFormatter();
dateWithTz2 = formatter.Deserialize(inFile) as DateInTimeZone;
Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime,
dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime) ?
dateWithTz2.TimeZone.DaylightName : dateWithTz2.TimeZone.DaylightName,
fileName);
}
catch (SerializationException)
{
Console.WriteLine("Unable to retrieve date and time information from {0}",
fileName);
}
finally
{
inFile.Close();
}
}
// This example displays the following output to the console:
// Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
// Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat
Const fileName As String = ".\DateWithTz.dat"

Dim tempDate As Date = #9/3/2008 7:00:00 PM#


Dim tempTz As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
Dim dateWithTz As New DateInTimeZone(New DateTimeOffset(tempDate, _
tempTz.GetUtcOffset(tempDate)), _
tempTz)

' Store DateInTimeZone value to a file


Dim outFile As New FileStream(fileName, FileMode.Create)
Try
Dim formatter As New BinaryFormatter()
formatter.Serialize(outFile, dateWithTz)
Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime, _
IIf(dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime), _
dateWithTz.TimeZone.DaylightName, dateWithTz.TimeZone.DaylightName), _
fileName)
Catch e As SerializationException
Console.WriteLine("Unable to serialize time data to {0}.", fileName)
Finally
outFile.Close()
End Try

' Retrieve DateInTimeZone value


If File.Exists(fileName) Then
Dim inFile As New FileStream(fileName, FileMode.Open)
Dim dateWithTz2 As New DateInTimeZone()
Try
Dim formatter As New BinaryFormatter()
dateWithTz2 = DirectCast(formatter.Deserialize(inFile), DateInTimeZone)
Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime, _
IIf(dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime), _
dateWithTz2.TimeZone.DaylightName, dateWithTz2.TimeZone.DaylightName), _
fileName)
Catch e As SerializationException
Console.WriteLine("Unable to retrieve date and time information from {0}", _
fileName)
Finally
inFile.Close
End Try
End If
' This example displays the following output to the console:
' Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
' Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat

Esta técnica debe reflejar siempre de forma inequívoca el punto correcto de tiempo antes y después de guardar y
restaurar, siempre que la implementación del objeto combinado de fecha y hora y de zona horaria no permita que
el valor de fecha quede fuera de la sincronización con el valor de zona horaria.

Compilar el código
Para estos ejemplos se necesita:
Que los espacios de nombres siguientes se importen con instrucciones using de C# o con instrucciones
Imports de Visual Basic:

System (solo C#).


System.Globalization.
System.IO.
System.Runtime.Serialization.
System.Runtime.Serialization.Formatters.Binary.
Cada ejemplo de código, excepto la clase DateInTimeZone , debe incluirse en una clase o en módulo de Visual
Basic, ajustado en métodos y con una llamada al método Main .

Vea también
Efectuar operaciones de formato
Elección entre DateTime, DateTimeOffset, TimeSpan y TimeZoneInfo
Standard Date and Time Format Strings
Procedimiento para mostrar milisegundos en los
valores de fecha y hora
18/12/2019 • 7 minutes to read • Edit Online

Los métodos de formato de fecha y hora predeterminados, como DateTime.ToString(), incluyen las horas, minutos
y segundos de un valor de tiempo, pero excluyen el componente correspondiente a los milisegundos. En este tema
se muestra cómo se incluye un componente de milisegundos de un valor de fecha y hora en cadenas de fecha y
hora con formato.
Para mostrar el componente de milisegundos de un valor DateTime
1. Cuando trabaje con la representación de cadena de una fecha, conviértala en un valor DateTime o
DateTimeOffset mediante el método estático DateTime.Parse(String) o DateTimeOffset.Parse(String).
2. Para extraer la representación de cadena del componente de milisegundos de una hora, llame al método
DateTime.ToString(String) o ToString del valor de fecha y hora y pase el modelo de formato personalizado
fff o FFF en solitario o junto a otros especificadores de formato personalizado como el parámetro
format .

Ejemplo
En el ejemplo se muestra el componente de milisegundos de un valor DateTime y DateTimeOffset en la consola en
su presentación en solitario e incluido en una cadena de fecha y hora más larga.
using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class MillisecondDisplay


{
public static void Main()
{
string dateString = "7/16/2008 8:32:45.126 AM";

try
{
DateTime dateValue = DateTime.Parse(dateString);
DateTimeOffset dateOffsetValue = DateTimeOffset.Parse(dateString);

// Display Millisecond component alone.


Console.WriteLine("Millisecond component only: {0}",
dateValue.ToString("fff"));
Console.WriteLine("Millisecond component only: {0}",
dateOffsetValue.ToString("fff"));

// Display Millisecond component with full date and time.


Console.WriteLine("Date and Time with Milliseconds: {0}",
dateValue.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));
Console.WriteLine("Date and Time with Milliseconds: {0}",
dateOffsetValue.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));

// Append millisecond pattern to current culture's full date time pattern


string fullPattern = DateTimeFormatInfo.CurrentInfo.FullDateTimePattern;
fullPattern = Regex.Replace(fullPattern, "(:ss|:s)", "$1.fff");

// Display Millisecond component with modified full date and time pattern.
Console.WriteLine("Modified full date time pattern: {0}",
dateValue.ToString(fullPattern));
Console.WriteLine("Modified full date time pattern: {0}",
dateOffsetValue.ToString(fullPattern));
}
catch (FormatException)
{
Console.WriteLine("Unable to convert {0} to a date.", dateString);
}
}
}
// The example displays the following output if the current culture is en-US:
// Millisecond component only: 126
// Millisecond component only: 126
// Date and Time with Milliseconds: 07/16/2008 08:32:45.126 AM
// Date and Time with Milliseconds: 07/16/2008 08:32:45.126 AM
// Modified full date time pattern: Wednesday, July 16, 2008 8:32:45.126 AM
// Modified full date time pattern: Wednesday, July 16, 2008 8:32:45.126 AM
Imports System.Globalization
Imports System.Text.REgularExpressions

Module MillisecondDisplay
Public Sub Main()

Dim dateString As String = "7/16/2008 8:32:45.126 AM"

Try
Dim dateValue As Date = Date.Parse(dateString)
Dim dateOffsetValue As DateTimeOffset = DateTimeOffset.Parse(dateString)

' Display Millisecond component alone.


Console.WriteLine("Millisecond component only: {0}", _
dateValue.ToString("fff"))
Console.WriteLine("Millisecond component only: {0}", _
dateOffsetValue.ToString("fff"))

' Display Millisecond component with full date and time.


Console.WriteLine("Date and Time with Milliseconds: {0}", _
dateValue.ToString("MM/dd/yyyy hh:mm:ss.fff tt"))
Console.WriteLine("Date and Time with Milliseconds: {0}", _
dateOffsetValue.ToString("MM/dd/yyyy hh:mm:ss.fff tt"))

' Append millisecond pattern to current culture's full date time pattern
Dim fullPattern As String = DateTimeFormatInfo.CurrentInfo.FullDateTimePattern
fullPattern = Regex.Replace(fullPattern, "(:ss|:s)", "$1.fff")

' Display Millisecond component with modified full date and time pattern.
Console.WriteLine("Modified full date time pattern: {0}", _
dateValue.ToString(fullPattern))
Console.WriteLine("Modified full date time pattern: {0}", _
dateOffsetValue.ToString(fullPattern))
Catch e As FormatException
Console.WriteLine("Unable to convert {0} to a date.", dateString)
End Try
End Sub
End Module
' The example displays the following output if the current culture is en-US:
' Millisecond component only: 126
' Millisecond component only: 126
' Date and Time with Milliseconds: 07/16/2008 08:32:45.126 AM
' Date and Time with Milliseconds: 07/16/2008 08:32:45.126 AM
' Modified full date time pattern: Wednesday, July 16, 2008 8:32:45.126 AM
' Modified full date time pattern: Wednesday, July 16, 2008 8:32:45.126 AM

El modelo de formato fff incluye todos los ceros finales en el valor de milisegundos. El modelo de formato FFF
suprime todos estos ceros. En el siguiente ejemplo se ilustra la diferencia.

DateTime dateValue = new DateTime(2008, 7, 16, 8, 32, 45, 180);


Console.WriteLine(dateValue.ToString("fff"));
Console.WriteLine(dateValue.ToString("FFF"));
// The example displays the following output to the console:
// 180
// 18

Dim dateValue As New Date(2008, 7, 16, 8, 32, 45, 180)


Console.WriteLIne(dateValue.ToString("fff"))
Console.WriteLine(dateValue.ToString("FFF"))
' The example displays the following output to the console:
' 180
' 18
Un problema que surge al definir un especificador de formato personalizado completo que incluya el componente
de milisegundos de un valor de fecha y hora es que éste establece un formato codificado de forma rígida que es
posible que no se corresponda con la organización de elementos horarios de la referencia cultural actual de la
aplicación. Una alternativa más conveniente consiste en recuperar uno de los modelos de presentación de fecha y
hora definidos por el objeto DateTimeFormatInfo de la referencia cultural actual y modificarlo para incluir los
milisegundos. En el ejemplo se muestra también este enfoque. En este ejemplo, se recupera el modelo completo de
fecha y hora de la referencia cultural actual de la propiedad DateTimeFormatInfo.FullDateTimePattern y, a
continuación, se inserta el modelo personalizado .ffff tras el segundo modelo. Observe que en el ejemplo se
utiliza una expresión regular para realizar esta operación en una única llamada al método.
También puede utilizar un especificador de formato personalizado para mostrar una fracción de segundo distinta
de los milisegundos. Por ejemplo, el especificador de formato personalizado f o F muestra las décimas de
segundo, el especificador de formato personalizado ff o FF muestra las centésimas de segundo y el
especificador de formato personalizado ffff o FFFF muestra las diezmilésimas de segundo. Las fracciones de
milisegundo se truncan en lugar de redondearse en la cadena devuelta. Estos especificadores de formato se
utilizan en el ejemplo siguiente.

DateTime dateValue = new DateTime(2008, 7, 16, 8, 32, 45, 180);


Console.WriteLine("{0} seconds", dateValue.ToString("s.f"));
Console.WriteLine("{0} seconds", dateValue.ToString("s.ff"));
Console.WriteLine("{0} seconds", dateValue.ToString("s.ffff"));
// The example displays the following output to the console:
// 45.1 seconds
// 45.18 seconds
// 45.1800 seconds

Dim dateValue As New DateTime(2008, 7, 16, 8, 32, 45, 180)


Console.WriteLine("{0} seconds", dateValue.ToString("s.f"))
Console.WriteLine("{0} seconds", dateValue.ToString("s.ff"))
Console.WriteLine("{0} seconds", dateValue.ToString("s.ffff"))
' The example displays the following output to the console:
' 45.1 seconds
' 45.18 seconds
' 45.1800 seconds

NOTE
Es posible mostrar unidades fraccionarias de segundo muy pequeñas, como diezmilésimas o cienmilésimas de segundo. Sin
embargo, estos valores no suelen ser significativos. La precisión de los valores de fecha y hora depende de la resolución del
reloj del sistema. En los sistemas operativos Windows NT 3.5 (y versiones posteriores) y Windows Vista, la resolución del reloj
es aproximadamente de 10 a 15 milisegundos.

Vea también
DateTimeFormatInfo
Custom Date and Time Format Strings
Procedimiento para mostrar fechas en calendarios no
gregorianos
04/11/2019 • 12 minutes to read • Edit Online

Los tipos DateTime y DateTimeOffset usan el calendario gregoriano como calendario predeterminado. Esto
significa que al llamar al método ToString de un valor de fecha y hora se muestra la representación de cadena de
esa fecha y hora en el calendario gregoriano, aunque se creara con otro calendario. Esto se muestra en el ejemplo
siguiente, que usa dos maneras diferentes de crear un valor de fecha y hora con el calendario persa, pero muestra
esos valores de fecha y hora en el calendario gregoriano cuando llama al método ToString. En este ejemplo se
reflejan dos técnicas usadas habitualmente, aunque incorrectas, para mostrar la fecha en un calendario
determinado.

PersianCalendar persianCal = new PersianCalendar();

DateTime persianDate = persianCal.ToDateTime(1387, 3, 18, 12, 0, 0, 0);


Console.WriteLine(persianDate.ToString());

persianDate = new DateTime(1387, 3, 18, persianCal);


Console.WriteLine(persianDate.ToString());
// The example displays the following output to the console:
// 6/7/2008 12:00:00 PM
// 6/7/2008 12:00:00 AM

Dim persianCal As New PersianCalendar()

Dim persianDate As Date = persianCal.ToDateTime(1387, 3, 18, _


12, 0, 0, 0)
Console.WriteLine(persianDate.ToString())

persianDate = New DateTime(1387, 3, 18, persianCal)


Console.WriteLine(persianDate.ToString())
' The example displays the following output to the console:
' 6/7/2008 12:00:00 PM
' 6/7/2008 12:00:00 AM

Se pueden usar dos técnicas distintas para mostrar la fecha en un calendario determinado. La primera exige que el
calendario sea el predeterminado de una referencia cultural determinada. La segunda se puede usar con cualquier
calendario.
Para mostrar la fecha del calendario predeterminado de una referencia cultural
1. Cree una instancia de un objeto de calendario derivado de la clase Calendar que representa al calendario
que se va a usar.
2. Cree una instancia de un objeto CultureInfo que representa la referencia cultural cuyo formato se va a usar
para mostrar la fecha.
3. Llame al método Array.Exists para determinar si el objeto de calendario es miembro de la matriz devuelta
por la propiedad CultureInfo.OptionalCalendars. Esto indica que el calendario puede actuar como
calendario predeterminado del objeto CultureInfo. Si no es miembro de la matriz, siga las instrucciones de
la sección "Para mostrar la fecha en cualquier calendario".
4. Asigne el objeto de calendario a la propiedad Calendar del objeto DateTimeFormatInfo devuelto por la
propiedad CultureInfo.DateTimeFormat.

NOTE
La clase CultureInfo también tiene una propiedad Calendar. Pero es de solo lectura y constante; no cambia para
reflejar el nuevo calendario predeterminado asignado a la propiedad DateTimeFormatInfo.Calendar.

5. Llame al método ToString o ToString y pásele el objeto CultureInfo cuyo calendario predeterminado se
modificó en el paso anterior.
Para mostrar la fecha en cualquier calendario
1. Cree una instancia de un objeto de calendario derivado de la clase Calendar que representa al calendario
que se va a usar.
2. Determine qué elementos de fecha y hora deben aparecer en la representación de cadena del valor de fecha
y hora.
3. Para cada elemento de fecha y hora que quiera mostrar, llame al método Get del objeto de calendario... .
Están disponibles los siguientes métodos:
GetYear, para mostrar el año en el calendario adecuado.
GetMonth, para mostrar el mes en el calendario adecuado.
GetDayOfMonth, para mostrar el número del día del mes en el calendario adecuado.
GetHour, para mostrar la hora del día en el calendario adecuado.
GetMinute, para mostrar los minutos de la hora en el calendario adecuado.
GetSecond, para mostrar los segundos del minuto en el calendario adecuado.
GetMilliseconds, para mostrar los milisegundos del segundo en el calendario adecuado.

Ejemplo
En el ejemplo se muestra una fecha con dos calendarios diferentes. Se muestra la fecha después de definir el
calendario Hijri como calendario predeterminado de la referencia cultural ar-JO y se muestra la fecha con el
calendario persa, que no se admite como calendario opcional de la referencia cultural fa-IR.

using System;
using System.Globalization;

public class CalendarDates


{
public static void Main()
{
HijriCalendar hijriCal = new HijriCalendar();
CalendarUtility hijriUtil = new CalendarUtility(hijriCal);
DateTime dateValue1 = new DateTime(1429, 6, 29, hijriCal);
DateTimeOffset dateValue2 = new DateTimeOffset(dateValue1,
TimeZoneInfo.Local.GetUtcOffset(dateValue1));
CultureInfo jc = CultureInfo.CreateSpecificCulture("ar-JO");

// Display the date using the Gregorian calendar.


Console.WriteLine("Using the system default culture: {0}",
dateValue1.ToString("d"));
// Display the date using the ar-JO culture's original default calendar.
Console.WriteLine("Using the ar-JO culture's original default calendar: {0}",
dateValue1.ToString("d", jc));
// Display the date using the Hijri calendar.
Console.WriteLine("Using the ar-JO culture with Hijri as the default calendar:");
Console.WriteLine("Using the ar-JO culture with Hijri as the default calendar:");
// Display a Date value.
Console.WriteLine(hijriUtil.DisplayDate(dateValue1, jc));
// Display a DateTimeOffset value.
Console.WriteLine(hijriUtil.DisplayDate(dateValue2, jc));

Console.WriteLine();

PersianCalendar persianCal = new PersianCalendar();


CalendarUtility persianUtil = new CalendarUtility(persianCal);
CultureInfo ic = CultureInfo.CreateSpecificCulture("fa-IR");

// Display the date using the ir-FA culture's default calendar.


Console.WriteLine("Using the ir-FA culture's default calendar: {0}",
dateValue1.ToString("d", ic));
// Display a Date value.
Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic));
// Display a DateTimeOffset value.
Console.WriteLine(persianUtil.DisplayDate(dateValue2, ic));
}
}

public class CalendarUtility


{
private Calendar thisCalendar;
private CultureInfo targetCulture;

public CalendarUtility(Calendar cal)


{
this.thisCalendar = cal;
}

private bool CalendarExists(CultureInfo culture)


{
this.targetCulture = culture;
return Array.Exists(this.targetCulture.OptionalCalendars,
this.HasSameName);
}

private bool HasSameName(Calendar cal)


{
if (cal.ToString() == thisCalendar.ToString())
return true;
else
return false;
}

public string DisplayDate(DateTime dateToDisplay, CultureInfo culture)


{
DateTimeOffset displayOffsetDate = dateToDisplay;
return DisplayDate(displayOffsetDate, culture);
}

public string DisplayDate(DateTimeOffset dateToDisplay,


CultureInfo culture)
{
string specifier = "yyyy/MM/dd";

if (this.CalendarExists(culture))
{
Console.WriteLine("Displaying date in supported {0} calendar...",
this.thisCalendar.GetType().Name);
culture.DateTimeFormat.Calendar = this.thisCalendar;
return dateToDisplay.ToString(specifier, culture);
}
else
{
Console.WriteLine("Displaying date in unsupported {0} calendar...",
thisCalendar.GetType().Name);
string separator = targetCulture.DateTimeFormat.DateSeparator;

return thisCalendar.GetYear(dateToDisplay.DateTime).ToString("0000") +
separator +
thisCalendar.GetMonth(dateToDisplay.DateTime).ToString("00") +
separator +
thisCalendar.GetDayOfMonth(dateToDisplay.DateTime).ToString("00");
}
}
}
// The example displays the following output to the console:
// Using the system default culture: 7/3/2008
// Using the ar-JO culture's original default calendar: 03/07/2008
// Using the ar-JO culture with Hijri as the default calendar:
// Displaying date in supported HijriCalendar calendar...
// 1429/06/29
// Displaying date in supported HijriCalendar calendar...
// 1429/06/29
//
// Using the ir-FA culture's default calendar: 7/3/2008
// Displaying date in unsupported PersianCalendar calendar...
// 1387/04/13
// Displaying date in unsupported PersianCalendar calendar...
// 1387/04/13

Imports System.Globalization

Public Class CalendarDates


Public Shared Sub Main()
Dim hijriCal As New HijriCalendar()
Dim hijriUtil As New CalendarUtility(hijriCal)
Dim dateValue1 As Date = New Date(1429, 6, 29, hijriCal)
Dim dateValue2 As DateTimeOffset = New DateTimeOffset(dateValue1, _
TimeZoneInfo.Local.GetUtcOffset(dateValue1))
Dim jc As CultureInfo = CultureInfo.CreateSpecificCulture("ar-JO")

' Display the date using the Gregorian calendar.


Console.WriteLine("Using the system default culture: {0}", _
dateValue1.ToString("d"))
' Display the date using the ar-JO culture's original default calendar.
Console.WriteLine("Using the ar-JO culture's original default calendar: {0}", _
dateValue1.ToString("d", jc))
' Display the date using the Hijri calendar.
Console.WriteLine("Using the ar-JO culture with Hijri as the default calendar:")
' Display a Date value.
Console.WriteLine(hijriUtil.DisplayDate(dateValue1, jc))
' Display a DateTimeOffset value.
Console.WriteLine(hijriUtil.DisplayDate(dateValue2, jc))

Console.WriteLine()

Dim persianCal As New PersianCalendar()


Dim persianUtil As New CalendarUtility(persianCal)
Dim ic As CultureInfo = CultureInfo.CreateSpecificCulture("fa-IR")

' Display the date using the ir-FA culture's default calendar.
Console.WriteLine("Using the ir-FA culture's default calendar: {0}", _
dateValue1.ToString("d", ic))
' Display a Date value.
Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic))
' Display a DateTimeOffset value.
Console.WriteLine(persianUtil.DisplayDate(dateValue2, ic))
End Sub
End Class

Public Class CalendarUtility


Private thisCalendar As Calendar
Private thisCalendar As Calendar
Private targetCulture As CultureInfo

Public Sub New(cal As Calendar)


Me.thisCalendar = cal
End Sub

Private Function CalendarExists(culture As CultureInfo) As Boolean


Me.targetCulture = culture
Return Array.Exists(Me.targetCulture.OptionalCalendars, _
AddressOf Me.HasSameName)
End Function

Private Function HasSameName(cal As Calendar) As Boolean


If cal.ToString() = thisCalendar.ToString() Then
Return True
Else
Return False
End If
End Function

Public Function DisplayDate(dateToDisplay As Date, _


culture As CultureInfo) As String
Dim displayOffsetDate As DateTimeOffset = dateToDisplay
Return DisplayDate(displayOffsetDate, culture)
End Function

Public Function DisplayDate(dateToDisplay As DateTimeOffset, _


culture As CultureInfo) As String
Dim specifier As String = "yyyy/MM/dd"

If Me.CalendarExists(culture) Then
Console.WriteLine("Displaying date in supported {0} calendar...", _
thisCalendar.GetType().Name)
culture.DateTimeFormat.Calendar = Me.thisCalendar
Return dateToDisplay.ToString(specifier, culture)
Else
Console.WriteLine("Displaying date in unsupported {0} calendar...", _
thisCalendar.GetType().Name)

Dim separator As String = targetCulture.DateTimeFormat.DateSeparator

Return thisCalendar.GetYear(dateToDisplay.DateTime).ToString("0000") & separator & _


thisCalendar.GetMonth(dateToDisplay.DateTime).ToString("00") & separator & _
thisCalendar.GetDayOfMonth(dateToDisplay.DateTime).ToString("00")
End If
End Function
End Class
' The example displays the following output to the console:
' Using the system default culture: 7/3/2008
' Using the ar-JO culture's original default calendar: 03/07/2008
' Using the ar-JO culture with Hijri as the default calendar:
' Displaying date in supported HijriCalendar calendar...
' 1429/06/29
' Displaying date in supported HijriCalendar calendar...
' 1429/06/29
'
' Using the ir-FA culture's default calendar: 7/3/2008
' Displaying date in unsupported PersianCalendar calendar...
' 1387/04/13
' Displaying date in unsupported PersianCalendar calendar...
' 1387/04/13

Cada objeto CultureInfo puede admitir uno o varios calendarios, que se indican mediante la propiedad
OptionalCalendars. Uno de ellos se designa como calendario predeterminado de la referencia cultural y es
devuelto por la propiedad de solo lectura CultureInfo.Calendar. Otro de los calendarios opcionales se puede
designar como valor predeterminado si se asigna un objeto Calendar que represente ese calendario a la propiedad
DateTimeFormatInfo.Calendar devuelta por la propiedad CultureInfo.DateTimeFormat. Pero algunos calendarios,
como el persa representado por la clase PersianCalendar, no actúan como calendarios opcionales de ninguna
referencia cultural.
En el ejemplo se define una clase de utilidad de calendario reutilizable, CalendarUtility , para controlar muchos de
los detalles de generación de la representación de cadena de una fecha mediante un calendario determinado. La
clase CalendarUtility tiene los siguientes miembros:
Un constructor parametrizado cuyo único parámetro es un objeto Calendar en el que se va a representar
una fecha. Se asigna a un campo privado de la clase.
CalendarExists, un método privado que devuelve un valor booleano que indica si el calendario
representado por el objeto CalendarUtility es compatible con el objeto CultureInfo pasado al método
como parámetro. El método encapsula una llamada al método Array.Exists, al que pasa la matriz
CultureInfo.OptionalCalendars.
HasSameName, un método privado asignado al delegado Predicate<T> que se pasa como parámetro al
método Array.Exists. Cada miembro de la matriz se pasa al método hasta que este devuelve true . El
método determina si el nombre de un calendario opcional es igual que el calendario representado por el
objeto CalendarUtility .
DisplayDate , un método público sobrecargado al que se pasan dos parámetros: un valor DateTime o
DateTimeOffset para expresar en el calendario representado por el objeto CalendarUtility ; y la referencia
cultural cuyas reglas de formato se van a usar. Su comportamiento a la hora de devolver la representación
de cadena de una fecha depende de si la referencia cultural cuyas reglas de formato se van a usar admite el
calendario de destino.
Independientemente del calendario usado para crear un valor DateTime o DateTimeOffset en este ejemplo, ese
valor normalmente se expresa como una fecha gregoriana. Esto se debe a que los tipos DateTime y
DateTimeOffset no conservan ninguna información del calendario. Internamente, se representan como el número
de tics transcurridos desde la medianoche del 1 de enero de 0001. La interpretación de ese número depende del
calendario. En la mayoría de las referencias culturales, el calendario predeterminado es el gregoriano.

Vea también
Efectuar operaciones de formato
Manipular cadenas en .NET
04/11/2019 • 2 minutes to read • Edit Online

.NET proporciona un amplio conjunto de rutinas que permiten crear, comparar y modificar cadenas de forma
eficaz, así como analizar rápidamente grandes cantidades de texto y datos para buscar, quitar y reemplazar
patrones de texto.

En esta sección
Procedimientos recomendados para el uso de cadenas
Se examinan los métodos de ordenación, comparación y uso de mayúsculas y minúsculas de cadenas de .NET y se
proporcionan recomendaciones para seleccionar un método de control de cadenas.
Expresiones regulares de .NET
Se proporciona información sobre expresiones regulares de .NET, incluidos elementos de lenguaje,
comportamiento de expresiones regulares y ejemplos.
Operaciones básicas de cadenas
Se describen las operaciones de cadenas que proporcionan las clases System.String y System.Text.StringBuilder,
incluida la creación de cadenas a partir de matrices de bytes, la comparación de valores de cadena y la
modificación de cadenas existentes.

Secciones relacionadas
Conversión de tipos en .NET
Se explican las técnicas y reglas utilizadas para convertir tipos con .NET.
Aplicación de formato a tipos
Se explica cómo usar la biblioteca de clases base para implementar el formato, cómo dar formato a tipos
numéricos, cómo dar formato a tipos de cadena y cómo dar formato a una referencia cultural concreta.
Parsing Strings
Describe cómo inicializar objetos en los valores descritos por representaciones de cadena de dichos objetos. El
análisis es la operación inversa de la aplicación de formato.
Procedimientos recomendados para el uso de
cadenas en .NET
13/01/2020 • 58 minutes to read • Edit Online

.NET proporciona una gran compatibilidad para desarrollar aplicaciones localizadas y globalizadas, y simplifica la
aplicación de las convenciones de la referencia cultural actual o de una referencia cultural concreta al realizar
operaciones comunes como ordenar y mostrar cadenas. Pero ordenar o comparar cadenas no es siempre una
operación dependiente de la referencia cultural. Por ejemplo, las cadenas usadas internamente por una aplicación
normalmente se deben administrar de forma idéntica en todas las referencias culturales. Cuando los datos de
cadenas independientes de la referencia cultural (como etiquetas XML, etiquetas HTML, nombres de usuario,
rutas de acceso de archivos y nombres de objetos del sistema) se interpretan como si fueran dependientes de la
referencia cultural, el código de aplicación puede estar sujeto a errores imperceptibles, un rendimiento inadecuado
y, en algunos casos, a problemas de seguridad.
En este tema, se examinan los métodos de ordenación, comparación y uso de mayúsculas y minúsculas de
cadenas de .NET, se presentan recomendaciones para seleccionar un método adecuado de control de cadenas y se
proporciona información adicional sobre los métodos de control de cadenas. También se examina cómo se usan
para la presentación y el almacenamiento los datos con formato, como los datos numéricos y los datos de fecha y
hora.

Recomendaciones sobre el uso de cadenas


Cuando desarrolle con .NET, siga estas recomendaciones sencillas a la hora de usar cadenas:
Use sobrecargas que especifiquen explícitamente las reglas de comparación de cadenas para las operaciones
de cadenas. Normalmente, esto implica llamar a una sobrecarga de método que tiene un parámetro de tipo
StringComparison.
Use StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase para las comparaciones como su valor
predeterminado seguro para la coincidencia de cadenas válidas para la referencia cultural.
Use comparaciones con StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase para lograr un
rendimiento mejor.
Use operaciones de cadena basadas en StringComparison.CurrentCulture al mostrar la salida al usuario.
Use los valores StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase no lingüísticos en lugar de
operaciones de cadena basadas en CultureInfo.InvariantCulture cuando la comparación sea lingüísticamente
no pertinente (por ejemplo, nombre simbólico).
Emplee el método String.ToUpperInvariant en lugar del método String.ToLowerInvariant al normalizar cadenas
para la comparación.
Use una sobrecarga del método String.Equals para probar si dos cadenas son iguales.
Use los métodos String.Compare y String.CompareTo para ordenar cadenas, no para comprobar la igualdad.
Use el formato dependiente de la referencia cultural para mostrar datos que no son de cadena, como números
y fechas, en una interfaz de usuario. Use el formato con la referencia cultural invariable para conservar datos
que no son de cadena en forma de cadena.
Evite lo siguiente cuando use cadenas:
No emplee sobrecargas que no especifiquen explícita o implícitamente las reglas de comparación de cadenas
para las operaciones de cadena.
No use operaciones de cadena basadas en StringComparison.InvariantCulture en la mayoría de los casos. Una
de las pocas excepciones es cuando vaya a conservar datos lingüísticamente significativos pero válidos
culturalmente.
No emplee ninguna sobrecarga del método String.Compare o CompareTo y pruebe si se devuelve un valor
cero para determinar si dos cadenas son iguales.
No use el formato dependiente de la referencia cultural para conservar datos numéricos o datos de fecha y
hora en formato de cadena.

Especificar comparaciones de cadenas explícitamente


La mayoría de los métodos de manipulación de cadenas de .NET están sobrecargados. Normalmente, una o más
sobrecargas aceptan la configuración predeterminada, mientras que otras no aceptan ningún valor
predeterminado y en su lugar definen la manera precisa en la que se van a comparar o manipular las cadenas. La
mayoría de los métodos que no confían en los valores predeterminados incluye un parámetro de tipo
StringComparison, que es una enumeración que especifica explícitamente reglas para la comparación de cadenas
por referencia cultural y uso de mayúsculas y minúsculas. En la tabla siguiente se describen los miembros de la
enumeración StringComparison .

MIEMBRO DE STRINGCOMPARISON DESCRIPCIÓN

CurrentCulture Realiza una comparación con distinción entre mayúsculas y


minúsculas usando la referencia cultural actual.

CurrentCultureIgnoreCase Realiza una comparación sin distinción entre mayúsculas y


minúsculas usando la referencia cultural actual.

InvariantCulture Realiza una comparación con distinción entre mayúsculas y


minúsculas usando la referencia cultural de todos los idiomas.

InvariantCultureIgnoreCase Realiza una comparación sin distinción entre mayúsculas y


minúsculas usando la referencia cultural de todos los idiomas.

Ordinal Realiza una comparación ordinal.

OrdinalIgnoreCase Realiza una comparación ordinal sin distinción entre


mayúsculas y minúsculas.

Por ejemplo, el método IndexOf , que devuelve el índice de una subcadena en un objeto String que coincide con
un carácter o una cadena, tiene nueve sobrecargas:
IndexOf(Char), IndexOf(Char, Int32)y IndexOf(Char, Int32, Int32), que de forma predeterminada realizan una
búsqueda ordinal (con distinción entre mayúsculas y minúsculas e independiente de la referencia cultural) de
un carácter de la cadena.
IndexOf(String), IndexOf(String, Int32)y IndexOf(String, Int32, Int32), que de forma predeterminada realizan
una búsqueda con distinción entre mayúsculas y minúsculas y dependiente de la referencia cultural de una
subcadena de la cadena.
IndexOf(String, StringComparison), IndexOf(String, Int32, StringComparison)y IndexOf(String, Int32, Int32,
StringComparison), que incluyen un parámetro de tipo StringComparison que permite especificar el formato
de la comparación.
Se recomienda seleccionar una sobrecarga que no use valores predeterminados, por las razones siguientes:
Algunas sobrecargas con parámetros predeterminados (las que buscan un valor Char en la instancia de la
cadena) realizan una comparación ordinal, mientras que otras (las que buscan una cadena en la instancia de
la cadena) son dependientes de la referencia cultural. Es difícil recordar qué método usa cada valor
predeterminado y resulta fácil confundir las sobrecargas.
La intención del código que usa valores predeterminados para las llamadas al método no está clara. En el
ejemplo siguiente, en el cual se usan valores predeterminados, es difícil saber si el desarrollador pretendía
realizar una comparación ordinal o lingüística de dos cadenas, o si había alguna diferencia al usar
mayúsculas y minúsculas entre protocol y "http" que pudiera hacer que la prueba de igualdad devolviera
el valor false .

string protocol = GetProtocol(url);


if (String.Equals(protocol, "http")) {
// ...Code to handle HTTP protocol.
}
else {
throw new InvalidOperationException();
}

Dim protocol As String = GetProtocol(url)


If String.Equals(protocol, "http") Then
' ...Code to handle HTTP protocol.
Else
Throw New InvalidOperationException()
End If

En general, se recomienda llamar a un método que no use los valores predeterminados, ya que hace que la
intención del código no sea ambigua. Esto, a su vez, hace el código más legible y más fácil de depurar y mantener.
En el ejemplo siguiente se abordan las cuestiones que se derivan del ejemplo anterior. Indica claramente que se
usa la comparación ordinal y que se omiten las diferencias en cuanto al uso de mayúsculas y minúsculas.

string protocol = GetProtocol(url);


if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
// ...Code to handle HTTP protocol.
}
else {
throw new InvalidOperationException();
}

Dim protocol As String = GetProtocol(url)


If String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase) Then
' ...Code to handle HTTP protocol.
Else
Throw New InvalidOperationException()
End If

Detalles de la comparación de cadenas


La comparación de cadenas es el corazón de muchas operaciones relacionadas con cadenas, especialmente la
ordenación y la comprobación de igualdad. Las cadenas se ordenan en un orden determinado: si "mi" aparece
antes que "cadena" en una lista ordenada de cadenas, "mi" debe compararse como menor o igual que "cadena".
Además, la comparación define la igualdad implícitamente. La operación de comparación devuelve cero para las
cadenas que considera iguales. Una buena interpretación es que ninguna cadena es menor que otra. La mayoría
de las operaciones significativas que implican cadenas incluyen uno o ambos de estos procedimientos: comparar
con otra cadena y ejecutar una operación de ordenación bien definida.
NOTE
Puede descargar las tablas de pesos de ordenación, un conjunto de archivos de texto que contienen información sobre los
pesos de caracteres que se usan en las operaciones de ordenación y comparación para los sistemas operativos Windows,
además de la tabla de elementos de intercalación Unicode predeterminada, que es la última versión de la tabla de pesos de
ordenación para Linux y macOS. La versión específica de la tabla de pesos de ordenación en Linux y macOS depende de la
versión de las bibliotecas de componentes internacionales de Unicode instaladas en el sistema. Para más información sobre
las versiones de los componentes internacionales de Unicode y las versiones de Unicode que implementan, vea la
información sobre la descarga de componentes internacionales de Unicode.

Sin embargo, la evaluación de dos cadenas para comprobar su igualdad o su criterio de ordenación no produce
ningún resultado correcto único; el resultado depende de los criterios empleados para comparar las cadenas. En
especial, las comparaciones de cadenas que son ordinales o que se basan en las convenciones de ordenación y uso
de mayúsculas y minúsculas de la referencia cultural actual o de la referencia cultural invariable (una referencia
cultural válida para la configuración regional basada en el idioma inglés) pueden producir resultados diferentes.
Además, las comparaciones de cadenas mediante las diferentes versiones de .NET o con .NET en distintos
sistemas operativos o versiones de sistema operativo pueden devolver resultados diferentes. Para más
información, vea Las cadenas y el estándar Unicode.
Comparaciones de cadenas que usan la referencia cultural actual
Un criterio implica usar las convenciones de la referencia cultural actual a la hora de comparar cadenas. Las
comparaciones que se basan en la referencia cultural actual usan la referencia cultural o la configuración regional
actual del subproceso. Si el usuario no establece la referencia cultural, se usa como valor predeterminado la
configuración de la ventana Opciones regionales del Panel de control. Siempre debe usar comparaciones
basadas en la referencia cultural actual cuando los datos sean lingüísticamente pertinentes y cuando refleje una
interacción con el usuario dependiente de la referencia cultural.
En cambio, el comportamiento de comparación y uso de mayúsculas y minúsculas de .NET cambia cuando la
referencia cultural cambia. Esto ocurre cuando una aplicación se ejecuta en un equipo que tiene una referencia
cultural diferente que el equipo en el que se desarrolló la aplicación o cuando el subproceso en ejecución cambia
su referencia cultural. Este comportamiento es deliberado, pero sigue resultando no obvio para muchos
desarrolladores. En el ejemplo siguiente, se muestran las diferencias en el criterio de ordenación entre las
referencias culturales de inglés de EE. UU. ("en-US") y sueco ("sv-SE"). Tenga en cuenta que las palabras
"ångström", "Windows" y "Visual Studio" aparecen en distintas posiciones en las matrices de cadenas ordenadas.
using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
string[] values= { "able", "ångström", "apple", "Æble",
"Windows", "Visual Studio" };
Array.Sort(values);
DisplayArray(values);

// Change culture to Swedish (Sweden).


string originalCulture = CultureInfo.CurrentCulture.Name;
Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
Array.Sort(values);
DisplayArray(values);

// Restore the original culture.


Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
}

private static void DisplayArray(string[] values)


{
Console.WriteLine("Sorting using the {0} culture:",
CultureInfo.CurrentCulture.Name);
foreach (string value in values)
Console.WriteLine(" {0}", value);

Console.WriteLine();
}
}
// The example displays the following output:
// Sorting using the en-US culture:
// able
// Æble
// ångström
// apple
// Visual Studio
// Windows
//
// Sorting using the sv-SE culture:
// able
// Æble
// apple
// Windows
// Visual Studio
// ångström
Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim values() As String = { "able", "ångström", "apple", _
"Æble", "Windows", "Visual Studio" }
Array.Sort(values)
DisplayArray(values)

' Change culture to Swedish (Sweden).


Dim originalCulture As String = CultureInfo.CurrentCulture.Name
Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
Array.Sort(values)
DisplayArray(values)

' Restore the original culture.


Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
End Sub

Private Sub DisplayArray(values() As String)


Console.WRiteLine("Sorting using the {0} culture:", _
CultureInfo.CurrentCulture.Name)
For Each value As String In values
Console.WriteLine(" {0}", value)
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' Sorting using the en-US culture:
' able
' Æble
' ångström
' apple
' Visual Studio
' Windows
'
' Sorting using the sv-SE culture:
' able
' Æble
' apple
' Windows
' Visual Studio
' ångström

Las comparaciones sin distinción entre mayúsculas y minúsculas que usan la referencia cultural actual son iguales
que las comparaciones dependientes de la referencia cultural, excepto que omiten el uso de mayúsculas y
minúsculas según indica la referencia cultural actual del subproceso. Este comportamiento también se puede
manifestar en los criterios de ordenación.
Las comparaciones que usan semántica de la referencia cultural actual son el valor predeterminado para los
métodos siguientes:
Sobrecargas deString.Compare que no incluyen un parámetro StringComparison .
Sobrecargas deString.CompareTo .
El método predeterminado String.StartsWith(String) y el método String.StartsWith(String, Boolean,
CultureInfo) con un parámetro null CultureInfo .
El método predeterminado String.EndsWith(String) y el método String.EndsWith(String, Boolean, CultureInfo)
con un parámetro null CultureInfo.
Sobrecargas deString.IndexOf que aceptan String como un parámetro de búsqueda y que no tienen un
parámetro StringComparison .
Sobrecargas deString.LastIndexOf que aceptan String como un parámetro de búsqueda y que no tienen un
parámetro StringComparison .
En cualquier caso, se recomienda llamar a una sobrecarga que tenga un parámetro StringComparison para aclarar
la intención de la llamada al método.
Pueden surgir errores imperceptibles y no tan imperceptibles cuando los datos de cadenas no lingüísticos se
interpretan lingüísticamente, o cuando los datos de cadenas de una referencia cultural determinada se interpretan
usando las convenciones de otra referencia cultural. El ejemplo canónico es el problema con I en turco.
Para casi todos los alfabetos latinos, incluso en inglés de EE. UU., el carácter "i" (\u0069) es la versión en
minúsculas del carácter "I" (\u0049). Esta regla de mayúsculas y minúsculas se convierte rápidamente en el valor
predeterminado para alguien que programe en esa referencia cultural. En cambio, el alfabeto turco ("tr-TR")
incluye un carácter "I con punto" "İ" (\u0130), que es la versión en mayúsculas de "i". El turco también incluye un
carácter "i sin punto" en minúscula, "ı" (\u0131), que en mayúsculas es "I". Este comportamiento también se
produce en la referencia cultural de azerbaiyano ("az").
Por tanto, los supuestos sobre poner en mayúsculas "i" o escribir "I" en minúsculas no son válidas en todas las
referencias culturales. Si usa las sobrecargas predeterminadas para las rutinas de comparación de cadenas,
estarán sujetas a variaciones entre distintas referencias culturales. Si los datos que se van a comparar son no
lingüísticos, el uso de las sobrecargas predeterminadas puede generar resultados no deseables, como ilustra el
siguiente intento de realizar una comparación sin distinción entre mayúsculas y minúsculas de las cadenas "file" y
"FILE".

using System;
using System.Globalization;
using System.Threading;

public class Example


{
public static void Main()
{
string fileUrl = "file";
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine("Culture = {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}",
fileUrl.StartsWith("FILE", true, null));
Console.WriteLine();

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");


Console.WriteLine("Culture = {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}",
fileUrl.StartsWith("FILE", true, null));
}
}
// The example displays the following output:
// Culture = English (United States)
// (file == FILE) = True
//
// Culture = Turkish (Turkey)
// (file == FILE) = False
Imports System.Globalization
Imports System.Threading

Module Example
Public Sub Main()
Dim fileUrl = "file"
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
Console.WriteLine("Culture = {0}", _
Thread.CurrentThread.CurrentCulture.DisplayName)
Console.WriteLine("(file == FILE) = {0}", _
fileUrl.StartsWith("FILE", True, Nothing))
Console.WriteLine()

Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")


Console.WriteLine("Culture = {0}", _
Thread.CurrentThread.CurrentCulture.DisplayName)
Console.WriteLine("(file == FILE) = {0}", _
fileUrl.StartsWith("FILE", True, Nothing))
End Sub
End Module
' The example displays the following output:
' Culture = English (United States)
' (file == FILE) = True
'
' Culture = Turkish (Turkey)
' (file == FILE) = False

Esta comparación podría producir problemas importantes si la referencia cultural se usa involuntariamente en
configuraciones que afectan a la seguridad, como en el ejemplo siguiente. Una llamada al método como
IsFileURI("file:") devuelve true si la referencia cultural actual es inglés de EE. U.U., pero false si la referencia
cultural actual es el turco. Así, en los sistemas turcos, alguien podría sortear las medidas de seguridad que
bloquean el acceso a los URI sin distinción entre mayúsculas y minúsculas que comienzan con "FILE":.

public static bool IsFileURI(String path)


{
return path.StartsWith("FILE:", true, null);
}

Public Shared Function IsFileURI(path As String) As Boolean


Return path.StartsWith("FILE:", True, Nothing)
End Function

En este caso, como "file:" se debe interpretar como un identificador no lingüístico e independiente de la referencia
cultural, el código se debe escribir como se muestra en el ejemplo siguiente:

public static bool IsFileURI(string path)


{
return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}

Public Shared Function IsFileURI(path As String) As Boolean


Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function

Operaciones de cadenas ordinales


Al especificar el valor StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase en una llamada al
método, se indica una comparación no lingüística en la que se omiten las características de los lenguajes naturales.
Los métodos que se invocan con estos valores StringComparison basan las decisiones sobre las operaciones con
cadenas en simples comparaciones de bytes en lugar de usos de mayúsculas y minúsculas o tablas de
equivalencia parametrizadas por referencia cultural. En la mayoría de los casos, este enfoque se adapta mejor a la
interpretación prevista de cadenas, y el código es más rápido y más confiable.
Las comparaciones ordinales son comparaciones de cadenas en las que cada byte de cada cadena se compara sin
ninguna interpretación lingüística; por ejemplo, "windows" no coincide con "Windows". Esta es, esencialmente,
una llamada a la función strcmp en tiempo de ejecución de C. Use esta comparación cuando el contexto indique
que las cadenas deben coincidir exactamente o exija una directiva de coincidencia conservadora. Además, la
comparación ordinal es la operación de comparación más rápida porque no aplica ninguna regla lingüística al
determinar un resultado.
En .NET, las cadenas pueden contener caracteres nulos incrustados. Una de las diferencias más claras entre la
comparación ordinal y dependiente de la referencia cultural (incluyendo las comparaciones que usan la referencia
cultural de todos los idiomas) tiene que ver con el control de caracteres nulos incrustados en una cadena. Estos
caracteres se omiten cuando usa métodos String.Compare y String.Equals para realizar comparaciones
dependientes de la referencia cultural (incluyendo las comparaciones que usan la referencia cultural de todos los
idiomas). Por tanto, en las comparaciones dependientes de la referencia cultural, las cadenas que contienen
caracteres nulos incrustados pueden considerarse iguales que las cadenas que no los contienen.

IMPORTANT
Aunque los métodos de comparación de cadenas hacen caso omiso de los caracteres nulos incrustados, los métodos de
búsqueda de cadenas como String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOfy String.StartsWith sí los
tienen en cuenta.

En el ejemplo siguiente se realiza una comparación dependiente de la referencia cultural de la cadena "Aa" con
una cadena similar que contiene varios caracteres nulos insertados entre "A" y "a", y se muestra cómo las dos
cadenas se consideran iguales:
using System;

public class Example


{
public static void Main()
{
string str1 = "Aa";
string str2 = "A" + new String('\u0000', 3) + "a";
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):",
str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine(" With String.Compare:");
Console.WriteLine(" Current Culture: {0}",
String.Compare(str1, str2, StringComparison.CurrentCulture));
Console.WriteLine(" Invariant Culture: {0}",
String.Compare(str1, str2, StringComparison.InvariantCulture));

Console.WriteLine(" With String.Equals:");


Console.WriteLine(" Current Culture: {0}",
String.Equals(str1, str2, StringComparison.CurrentCulture));
Console.WriteLine(" Invariant Culture: {0}",
String.Equals(str1, str2, StringComparison.InvariantCulture));
}

private static string ShowBytes(string str)


{
string hexString = String.Empty;
for (int ctr = 0; ctr < str.Length; ctr++)
{
string result = String.Empty;
result = Convert.ToInt32(str[ctr]).ToString("X4");
result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
hexString += result;
}
return hexString.Trim();
}
}
// The example displays the following output:
// Comparing 'Aa' (00 41 00 61) and 'A a' (00 41 00 00 00 00 00 00 00 61):
// With String.Compare:
// Current Culture: 0
// Invariant Culture: 0
// With String.Equals:
// Current Culture: True
// Invariant Culture: True
Module Example
Public Sub Main()
Dim str1 As String = "Aa"
Dim str2 As String = "A" + New String(Convert.ToChar(0), 3) + "a"
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine(" With String.Compare:")
Console.WriteLine(" Current Culture: {0}", _
String.Compare(str1, str2, StringComparison.CurrentCulture))
Console.WriteLine(" Invariant Culture: {0}", _
String.Compare(str1, str2, StringComparison.InvariantCulture))

Console.WriteLine(" With String.Equals:")


Console.WriteLine(" Current Culture: {0}", _
String.Equals(str1, str2, StringComparison.CurrentCulture))
Console.WriteLine(" Invariant Culture: {0}", _
String.Equals(str1, str2, StringComparison.InvariantCulture))
End Sub

Private Function ShowBytes(str As String) As String


Dim hexString As String = String.Empty
For ctr As Integer = 0 To str.Length - 1
Dim result As String = String.Empty
result = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
result = " " + result.Substring(0,2) + " " + result.Substring(2, 2)
hexString += result
Next
Return hexString.Trim()
End Function
End Module

Pero las cadenas no se consideran iguales cuando se usa la comparación ordinal, como se muestra en el ejemplo
siguiente:

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):",


str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine(" With String.Compare:");
Console.WriteLine(" Ordinal: {0}",
String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine(" With String.Equals:");


Console.WriteLine(" Ordinal: {0}",
String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
// Comparing 'Aa' (00 41 00 61) and 'A a' (00 41 00 00 00 00 00 00 00 61):
// With String.Compare:
// Ordinal: 97
// With String.Equals:
// Ordinal: False
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine(" With String.Compare:")
Console.WriteLine(" Ordinal: {0}", _
String.Compare(str1, str2, StringComparison.Ordinal))

Console.WriteLine(" With String.Equals:")


Console.WriteLine(" Ordinal: {0}", _
String.Equals(str1, str2, StringComparison.Ordinal))
' The example displays the following output:
' Comparing 'Aa' (00 41 00 61) and 'A a' (00 41 00 00 00 00 00 00 00 61):
' With String.Compare:
' Ordinal: 97
' With String.Equals:
' Ordinal: False

Las comparaciones ordinales sin distinción entre mayúsculas y minúsculas son el siguiente enfoque más
conservador. Estas comparaciones omiten la mayor parte del uso de mayúsculas y minúsculas; por ejemplo,
"windows" coincide con "Windows". A la hora de tratar con caracteres ASCII, esta directiva es equivalente a
StringComparison.Ordinal, salvo que omite el uso de mayúsculas y minúsculas habitual de ASCII. Por tanto,
cualquier carácter de [A, Z ] (\u0041-\u005A) coincide con el carácter correspondiente de [a, z] (\u0061-\007A). El
uso de mayúsculas y minúsculas fuera del intervalo ASCII emplea las tablas de la referencia cultural de todos los
idiomas. Por tanto, la siguiente comparación:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)

es equivalente a esta comparación (pero más rápida):

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(),
StringComparison.Ordinal);

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(),
StringComparison.Ordinal)

Estas comparaciones siguen siendo muy rápidas.

NOTE
El comportamiento de las cadenas del sistema de archivos, claves del Registro y valores, y variables de entorno se representa
mejor mediante StringComparison.OrdinalIgnoreCase.

Tanto StringComparison.Ordinal como StringComparison.OrdinalIgnoreCase usan los valores binarios


directamente y son más adecuados para la búsqueda de coincidencias. Si no sabe con seguridad qué
configuración de comparación debe emplear, use uno de estos dos valores. Sin embargo, puesto que realizan una
comparación byte a byte, no ordenan según un criterio de ordenación lingüístico (como un diccionario de inglés)
sino según un criterio de ordenación binario. Los resultados pueden parecer extraños en la mayoría de los
contextos si se muestran a los usuarios.
La semántica ordinal es el valor predeterminado para las sobrecargas de String.Equals que no incluyen un
argumento StringComparison (incluyendo el operador de igualdad). En cualquier caso, se recomienda llamar a
una sobrecarga que tenga un parámetro StringComparison .
Operaciones de cadenas que usan la referencia cultural invariable
Las comparaciones con la referencia cultural de todos los idiomas usan la propiedad CompareInfo devuelta por la
propiedad estática CultureInfo.InvariantCulture . Este comportamiento es igual en todos los sistemas; traduce
cualquier carácter que esté fuera de su intervalo en lo que cree que son caracteres invariables equivalentes. Esta
directiva puede ser útil para mantener un conjunto de comportamientos de las cadenas en distintas referencias
culturales, pero a menudo proporciona resultados inesperados.
Las comparaciones sin distinción entre mayúsculas y minúsculas con la referencia cultural de todos los idiomas
usan también la propiedad estática CompareInfo devuelta por la propiedad estática CultureInfo.InvariantCulture
para obtener información de comparación. Cualquier diferencia en el uso de mayúsculas y minúsculas entre estos
caracteres traducidos se pasa por alto.
Las comparaciones que usan StringComparison.InvariantCulture y StringComparison.Ordinal funcionan de
manera idéntica en cadenas ASCII. Sin embargo, StringComparison.InvariantCulture toma decisiones lingüísticas
que podrían no ser adecuadas para las cadenas que tienen que interpretarse como un conjunto de bytes. El objeto
CultureInfo.InvariantCulture.CompareInfo hace que el método Compare interprete ciertos conjuntos de caracteres
como equivalentes. Por ejemplo, la siguiente equivalencia es válida en la referencia cultural de todos los idiomas:
InvariantCulture: a + ̊ = å
El carácter LETRA LATINA A MINÚSCULA "a" (\u0061), cuando está junto al carácter ANILLO SUPERIOR
COMBINABLE "+ " ̊" (\u030a), se interpreta como el carácter LETRA LATINA MINÚSCULA A CON ANILLO
SUPERIOR "å" (\u00e5). Como se muestra en el ejemplo siguiente, este comportamiento difiere de la
comparación ordinal.

string separated = "\u0061\u030a";


string combined = "\u00e5";

Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",


separated, combined,
String.Compare(separated, combined,
StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",


separated, combined,
String.Compare(separated, combined,
StringComparison.Ordinal) == 0);
// The example displays the following output:
// Equal sort weight of a° and å using InvariantCulture: True
// Equal sort weight of a° and å using Ordinal: False

Dim separated As String = ChrW(&h61) + ChrW(&h30a)


Dim combined As String = ChrW(&he5)

Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}", _


separated, combined, _
String.Compare(separated, combined, _
StringComparison.InvariantCulture) = 0)

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}", _


separated, combined, _
String.Compare(separated, combined, _
StringComparison.Ordinal) = 0)
' The example displays the following output:
' Equal sort weight of a° and å using InvariantCulture: True
' Equal sort weight of a° and å using Ordinal: False

A la hora de interpretar nombres de archivo, cookies u otros elementos donde pueda aparecer una combinación
como "å", las comparaciones ordinales siguen ofreciendo el comportamiento más transparente y adecuado.
En conjunto, la referencia cultural de todos los idiomas tiene muy pocas propiedades que la hagan útil para la
comparación. Realiza la comparación de manera lingüísticamente pertinente, lo que le impide garantizar una
equivalencia simbólica completa, pero no es la opción ideal para la presentación en cualquier referencia cultural.
Una de las pocas razones para usar StringComparison.InvariantCulture con el fin de realizar una comparación es
para conservar datos ordenados cuando se desea realizar una presentación idéntica transculturalmente. Por
ejemplo, si un archivo de datos grande que contiene una lista de identificadores ordenados para su presentación
acompaña una aplicación, al agregar datos a esta lista se necesitaría realizar una inserción con ordenación de
estilo invariable.

Elegir un miembro StringComparison para la llamada al método


En la tabla siguiente se describe la asignación del contexto de cadena semántico a un miembro de la enumeración
StringComparison:

VALOR DE SYSTEM.STRINGCOMPARISON

DATOS COMPORTAMIENTO VALUE

Identificadores internos con distinción Identificador no lingüístico, donde los Ordinal


entre mayúsculas y minúsculas. bytes coinciden exactamente.

Identificadores con distinción entre


mayúsculas y minúsculas en estándares
como XML y HTTP.

Configuraciones relacionadas con la


seguridad con distinción entre
mayúsculas y minúsculas.

Identificadores internos sin distinción Identificador no lingüístico, donde el OrdinalIgnoreCase


entre mayúsculas y minúsculas. uso de mayúsculas y minúsculas no es
pertinente; especialmente datos
Identificadores sin distinción entre almacenados en la mayoría de los
mayúsculas y minúsculas en estándares servicios del sistema de Windows.
como XML y HTTP.

Rutas de acceso a archivos.

Claves del Registro y valores.

Variables de entorno.

Identificadores de recursos (por


ejemplo, nombres de identificadores).

Configuraciones relacionadas con la


seguridad sin distinción entre
mayúsculas y minúsculas.

Algunos datos almacenados Datos válidos culturalmente que siguen InvariantCulture


lingüísticamente pertinentes. siendo lingüísticamente pertinentes.
o bien
Presentación de datos lingüísticos que
necesitan un criterio de ordenación fijo. InvariantCultureIgnoreCase

Datos mostrados al usuario. Datos que necesitan personalizaciones CurrentCulture


lingüísticas locales.
La mayoría de los datos o bien
proporcionados por el usuario.
CurrentCultureIgnoreCase
Métodos comunes de comparación de cadenas en .NET
En las secciones siguientes se describen los métodos que se usan con más frecuencia para la comparación de
cadenas.
String.Compare
Interpretación predeterminada: StringComparison.CurrentCulture.
Al ser la operación fundamental para la interpretación de cadenas, todas las instancias de estas llamadas al
método se deben examinar para determinar si las cadenas se deben interpretar según la referencia cultural actual
o se deben separar de la referencia cultural (simbólicamente). Normalmente, se trata del último caso y se debe
usar en su lugar una comparación StringComparison.Ordinal .
La clase System.Globalization.CompareInfo , devuelta por la propiedad CultureInfo.CompareInfo , también incluye
un método Compare que proporciona un gran número de opciones de coincidencia (ordinal, omitir el espacio en
blanco, omitir el tipo de kana, etc.) por medio de la enumeración de marca CompareOptions .
String.CompareTo
Interpretación predeterminada: StringComparison.CurrentCulture.
Este método no ofrece actualmente una sobrecarga que especifique un tipo StringComparison . Normalmente es
posible convertir este método en el formato recomendado del método String.Compare(String, String,
StringComparison) .
Los tipos que implementan interfaces IComparable y IComparable<T> implementan este método. Puesto que no
ofrece la opción de un parámetro StringComparison , la implementación de tipos suele permitir al usuario
especificar StringComparer en su constructor. En el ejemplo siguiente se define una clase FileName cuyo
constructor de clase incluye un parámetro StringComparer . Este objeto StringComparer se usa entonces en el
método FileName.CompareTo .
using System;

public class FileName : IComparable


{
string fname;
StringComparer comparer;

public FileName(string name, StringComparer comparer)


{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");

this.fname = name;

if (comparer != null)
this.comparer = comparer;
else
this.comparer = StringComparer.OrdinalIgnoreCase;
}

public string Name


{
get { return fname; }
}

public int CompareTo(object obj)


{
if (obj == null) return 1;

if (! (obj is FileName))
return comparer.Compare(this.fname, obj.ToString());
else
return comparer.Compare(this.fname, ((FileName) obj).Name);
}
}
Public Class FileName : Implements IComparable
Dim fname As String
Dim comparer As StringComparer

Public Sub New(name As String, comparer As StringComparer)


If String.IsNullOrEmpty(name) Then
Throw New ArgumentNullException("name")
End If

Me.fname = name

If comparer IsNot Nothing Then


Me.comparer = comparer
Else
Me.comparer = StringComparer.OrdinalIgnoreCase
End If
End Sub

Public ReadOnly Property Name As String


Get
Return fname
End Get
End Property

Public Function CompareTo(obj As Object) As Integer _


Implements IComparable.CompareTo
If obj Is Nothing Then Return 1

If Not TypeOf obj Is FileName Then


obj = obj.ToString()
Else
obj = CType(obj, FileName).Name
End If
Return comparer.Compare(Me.fname, obj)
End Function
End Class

String.Equals
Interpretación predeterminada: StringComparison.Ordinal.
La clase String le permite comprobar la igualdad llamando a las sobrecargas de método estático o de instancia
Equals , o usando el operador de igualdad estático. Las sobrecargas y el operador usan la comparación ordinal de
forma predeterminada. Sin embargo, todavía sigue siendo recomendable llamar a una sobrecarga que especifique
explícitamente el tipo StringComparison aunque desee realizar una comparación ordinal; esto facilita la búsqueda
de cierta interpretación de la cadena en el código.
String.ToUpper y String.ToLower
Interpretación predeterminada: StringComparison.CurrentCulture.
Debe tener cuidado al usar estos métodos, ya que forzar que una cadena esté en mayúsculas o en minúsculas se
usa a menudo como una pequeña normalización para comparar cadenas independientemente del uso de
mayúsculas y minúsculas. En tal caso, considere la posibilidad de emplear una comparación sin distinción entre
mayúsculas y minúsculas.
También están disponibles los métodos String.ToUpperInvariant y String.ToLowerInvariant . ToUpperInvariant es
la manera estándar de normalizar el uso de mayúsculas y minúsculas. Las comparaciones realizadas mediante
StringComparison.OrdinalIgnoreCase tienen un comportamiento que es la composición de dos llamadas: llamar a
ToUpperInvariant en ambos argumentos de cadena y realizar una comparación mediante
StringComparison.Ordinal.
También hay sobrecargas para convertir a mayúsculas y minúsculas en una referencia cultural concreta, pasando
al método un objeto CultureInfo que representa esa referencia cultural.
Char.ToUpper y Char.ToLower
Interpretación predeterminada: StringComparison.CurrentCulture.
Estos métodos funcionan de manera similar a los métodos String.ToUpper y String.ToLower descritos en la
sección anterior.
String.StartsWith y String.EndsWith
Interpretación predeterminada: StringComparison.CurrentCulture.
De forma predeterminada, estos dos métodos realizan una comparación dependiente de la referencia cultural.
String.IndexOf y String.LastIndexOf
Interpretación predeterminada: StringComparison.CurrentCulture.
No hay coherencia en cómo las sobrecargas predeterminadas de estos métodos realizan las comparaciones. Todos
los métodos String.IndexOf y String.LastIndexOf que incluyen un parámetro Char realizan una comparación
ordinal, pero los métodos String.IndexOf y String.LastIndexOf predeterminados que incluyen un parámetro String
realizan una comparación dependiente de la referencia cultural.
Si llama al método String.IndexOf(String) o String.LastIndexOf(String) y le pasa una cadena para ubicar en la
instancia actual, se recomienda llamar a una sobrecarga que especifique explícitamente el tipo StringComparison .
Las sobrecargas que incluyen un argumento Char no le permiten especificar un tipo StringComparison .

Métodos que realizan la comparación de cadenas indirectamente


Algunos métodos sin cadenas que tienen la comparación de cadenas como operación fundamental usan el tipo
StringComparer . La clase StringComparer incluye seis propiedades estáticas que devuelven instancias de
StringComparer cuyos métodos StringComparer.Compare realizan los siguientes tipos de comparaciones de
cadenas:
Comparaciones de cadenas dependientes de la referencia cultural usando la referencia cultural actual. Este
objeto StringComparer está devuelto por la propiedad StringComparer.CurrentCulture .
Comparaciones sin distinción entre mayúsculas y minúsculas usando la referencia cultural actual. Este objeto
StringComparer está devuelto por la propiedad StringComparer.CurrentCultureIgnoreCase .
Comparaciones independientes de la referencia cultural usando las reglas de comparación de palabras de la
referencia cultural de todos los idiomas. Este objeto StringComparer está devuelto por la propiedad
StringComparer.InvariantCulture .
Comparaciones sin distinción entre mayúsculas y minúsculas e independientes de la referencia cultural usando
las reglas de comparación de palabras de la referencia cultural de todos los idiomas. Este objeto
StringComparer está devuelto por la propiedad StringComparer.InvariantCultureIgnoreCase .
Comparación ordinal. Este objeto StringComparer está devuelto por la propiedad StringComparer.Ordinal .
Comparación ordinal sin distinción entre mayúsculas y minúsculas. Este objeto StringComparer está devuelto
por la propiedad StringComparer.OrdinalIgnoreCase .
Array.Sort y Array.BinarySearch
Interpretación predeterminada: StringComparison.CurrentCulture.
Cuando se almacenan datos en una colección, o cuando se leen datos almacenados de un archivo o una base de
datos en una colección, el cambio de la referencia cultural actual puede invalidar los valores invariables de la
colección. El método Array.BinarySearch supone que los elementos de la matriz que se van a buscar ya están
ordenados. Para ordenar cualquier elemento de cadena de la matriz, el método Array.Sort llama al método
String.Compare para ordenar los elementos individuales. El uso de un comparador dependiente de la referencia
cultural puede ser peligroso si la referencia cultural cambia desde que se ordena la matriz hasta que se busca en
su contenido. Por ejemplo, en el código siguiente, el almacenamiento y la recuperación funcionan en el
comparador que la propiedad Thread.CurrentThread.CurrentCulture . Si la referencia cultural puede cambiar entre
las llamadas a StoreNames y DoesNameExist , y especialmente si el contenido de la matriz se conserva en alguna
parte entre las dos llamadas al método, se puede producir un error en la búsqueda binaria.

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)


{
int index = 0;
storedNames = new string[names.Length];

foreach (string name in names)


{
this.storedNames[index++] = name;
}

Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)


{
return (Array.BinarySearch(this.storedNames, name) >= 0); // Line B.
}

' Incorrect.
Dim storedNames() As String

Public Sub StoreNames(names() As String)


Dim index As Integer = 0
ReDim storedNames(names.Length - 1)

For Each name As String In names


Me.storedNames(index) = name
index+= 1
Next

Array.Sort(names) ' Line A.


End Sub

Public Function DoesNameExist(name As String) As Boolean


Return Array.BinarySearch(Me.storedNames, name) >= 0 ' Line B.
End Function

Aparece una variación recomendada en el ejemplo siguiente, que usa el mismo método de comparación ordinal
(independiente de la referencia cultural) para ordenar y buscar en la matriz. El código cambiado se refleja en las
líneas etiquetadas como Line A y Line B en los dos ejemplos.
// Correct.
string []storedNames;

public void StoreNames(string [] names)


{
int index = 0;
storedNames = new string[names.Length];

foreach (string name in names)


{
this.storedNames[index++] = name;
}

Array.Sort(names, StringComparer.Ordinal); // Line A.


}

public bool DoesNameExist(string name)


{
return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0); // Line B.
}

' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)


Dim index As Integer = 0
ReDim storedNames(names.Length - 1)

For Each name As String In names


Me.storedNames(index) = name
index+= 1
Next

Array.Sort(names, StringComparer.Ordinal) ' Line A.


End Sub

Public Function DoesNameExist(name As String) As Boolean


Return Array.BinarySearch(Me.storedNames, name, StringComparer.Ordinal) >= 0 ' Line B.
End Function

Si estos datos se conservan y mueven entre distintas referencias culturales, y se usa la ordenación para presentar
estos datos al usuario, es mejor usar StringComparison.InvariantCulture, que funciona lingüísticamente para
obtener una mejor salida para el usuario pero no se ve afectado por los cambios en la referencia cultural. En el
ejemplo siguiente se modifican los dos ejemplos anteriores para usar la referencia cultural de todos los idiomas
con el fin de ordenar y buscar en la matriz.
// Correct.
string []storedNames;

public void StoreNames(string [] names)


{
int index = 0;
storedNames = new string[names.Length];

foreach (string name in names)


{
this.storedNames[index++] = name;
}

Array.Sort(names, StringComparer.InvariantCulture); // Line A.


}

public bool DoesNameExist(string name)


{
return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0); // Line B.
}

' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)


Dim index As Integer = 0
ReDim storedNames(names.Length - 1)

For Each name As String In names


Me.storedNames(index) = name
index+= 1
Next

Array.Sort(names, StringComparer.InvariantCulture) ' Line A.


End Sub

Public Function DoesNameExist(name As String) As Boolean


Return Array.BinarySearch(Me.storedNames, name, StringComparer.InvariantCulture) >= 0 ' Line B.
End Function

Ejemplo de colecciones: Constructor de tablas hash


Al aplicar un algoritmo hash a las cadenas se proporciona un segundo ejemplo de una operación que se ve
afectada por la forma en que se comparan las cadenas.
En el ejemplo siguiente se crea una instancia de un objeto Hashtable pasándole el objeto StringComparer
devuelto por la propiedad StringComparer.OrdinalIgnoreCase . Puesto que una clase StringComparer que se
deriva de StringComparer implementa la interfaz IEqualityComparer , su método GetHashCode se usa para
calcular el código hash de cadenas de la tabla hash.
const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)


{
h = new Hashtable(initialTableCapacity,
StringComparer.OrdinalIgnoreCase);

foreach (string file in Directory.GetFiles(directory))


h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)


{
Object dt = h[targetFile];
if (dt != null)
{
Console.WriteLine("File {0} was created at time {1}.",
targetFile,
(DateTime) dt);
}
else
{
Console.WriteLine("File {0} does not exist.", targetFile);
}
}

Const initialTableCapacity As Integer = 100


Dim h As Hashtable

Public Sub PopulateFileTable(dir As String)


h = New Hashtable(initialTableCapacity, _
StringComparer.OrdinalIgnoreCase)

For Each filename As String In Directory.GetFiles(dir)


h.Add(filename, File.GetCreationTime(filename))
Next
End Sub

Public Sub PrintCreationTime(targetFile As String)


Dim dt As Object = h(targetFile)
If dt IsNot Nothing Then
Console.WriteLine("File {0} was created at {1}.", _
targetFile, _
CDate(dt))
Else
Console.WriteLine("File {0} does not exist.", targetFile)
End If
End Sub

Mostrar y conservar datos con formato


Cuando muestre a los usuarios datos que no sean de cadena, como números, y fechas y horas, asígneles formato
mediante la configuración de la referencia cultural del usuario. De forma predeterminada, los siguientes
elementos usan la referencia cultural del subproceso actual al dar formato a las operaciones:
Cadenas interpoladas compatibles con los compiladores C# y Visual Basic.
Operaciones de concatenación de cadenas que usan los operadores de concatenación C# o Visual Basic, o que
llaman al método String.Concat directamente.
El método String.Format .
Métodos ToString de los tipos numéricos y tipos de fecha y hora.
Para especificar explícitamente que se debe dar formato a una cadena mediante las convenciones de una
referencia cultural nombrada o la referencia cultural invariable, se puede hacer lo siguiente:
Cuando se usen los métodos String.Format y ToString , llame a una sobrecarga que tenga un parámetro
provider , como String.Format( IFormatProvider, String, Object[]) o DateTime.ToString( IFormatProvider ), y
pásela a la propiedad CultureInfo.CurrentCulture, a una instancia CultureInfo que represente la referencia
cultural que se quiera o a la propiedad CultureInfo.InvariantCulture.
Para la concatenación de cadenas, no permita que el compilador realice ninguna de las conversiones
implícitas. En su lugar, realice una conversión explícita mediante una llamada a una sobrecarga ToString
que tenga un parámetro provider . Por ejemplo, el compilador utiliza implícitamente la referencia cultural
actual cuando convierte un valor Double en una cadena en el código de C# siguiente:

string concat1 = "The amount is " + 126.03 + ".";


Console.WriteLine(concat1);

En su lugar, se puede especificar explícitamente la referencia cultural cuyas convenciones de formato se


usan en la conversión mediante una llamada al método Double.ToString(IFormatProvider), tal como hace el
código de C# siguiente:

string concat2 = "The amount is " + 126.03.ToString(CultureInfo.InvariantCulture) + ".";


Console.WriteLine(concat2);

Para la interpolación de cadenas, en lugar de asignar una cadena interpolada a una instancia String,
asígnela a un elemento FormattableString. Después, se puede llamar al método
FormattableString.ToString() para generar una cadena de resultado que refleje las convenciones de la
referencia cultural actual, o bien puede llamar al método FormattableString.ToString(IFormatProvider) para
generar una cadena de resultado que refleje las convenciones de la referencia cultural especificada.
También se puede pasar la cadena que admite formato al método estático FormattableString.Invariant con
el fin de generar una cadena de resultado que refleje las convenciones de la referencia cultural invariable.
En el ejemplo siguiente se muestra este enfoque. (La salida del ejemplo refleja una referencia cultural actual
de en-US ).

using System;
using System.Globalization;

class Program
{
static void Main()
{
Decimal value = 126.03m;
FormattableString amount = $"The amount is {value:C}";
Console.WriteLine(amount.ToString());
Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")));
Console.WriteLine(FormattableString.Invariant(amount));
}
}
// The example displays the following output:
// The amount is $126.03
// The amount is 126,03 €
// The amount is ¤126.03
Imports System.Globalization

Module Program
Sub Main()
Dim value As Decimal = 126.03
Dim amount As FormattableString = $"The amount is {value:C}"
Console.WriteLine(amount.ToString())
Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")))
Console.WriteLine(FormattableString.Invariant(amount))
End Sub
End Module
' The example displays the following output:
' The amount is $126.03
' The amount is 126,03 €
' The amount is ¤126.03

Puede conservar datos que no son de cadena como datos binarios o como datos con formato. Si decide
guardarlos como datos con formato, debe llamar a una sobrecarga del método de formato que incluya un
parámetro provider y pasarle la propiedad CultureInfo.InvariantCulture . La referencia cultural de todos los
idiomas proporciona un formato coherente para los datos con formato que es independiente de la referencia
cultural y del equipo. En cambio, si se conservan datos a los que se aplica formato con referencias culturales
distintas de la referencia cultural de todos los idiomas, se presentan varias limitaciones:
Es probable que los datos no puedan usarse si se recuperan en un sistema que tiene una referencia cultural
distinta, o si el usuario del sistema actual cambia la referencia cultural actual e intenta recuperar los datos.
Las propiedades de una referencia cultural en un equipo específico pueden diferir de los valores estándar. En
cualquier momento, un usuario puede personalizar la configuración de visualización que depende de la
cultural. Debido a esto, es posible que los datos con formato que se guardan en un sistema no sean legibles
después de que el usuario personalice la configuración de la referencia cultural. Es posible que la portabilidad
de los datos con formato entre equipos sea incluso más limitada.
Las normas internacionales, regionales o nacionales que rigen el formato de los números o las fechas y horas
cambian con el tiempo, y estos cambios se incorporan en las actualizaciones de los sistemas operativos
Windows. Cuando cambian las convenciones de formato, los datos a los que se aplicó formato usando las
convenciones anteriores pueden llegar a ser ilegibles.
En el ejemplo siguiente se muestra la portabilidad limitada que se deriva de usar el formato dependiente de la
referencia cultural para conservar los datos. En el ejemplo se guarda una matriz de valores de fecha y hora en un
archivo. Se les da formato con las convenciones de la referencia cultural Inglés (Estados Unidos). Después de que
la aplicación cambie la referencia cultural del subproceso actual a Francés (Suiza), intenta leer los valores
guardados usando las convenciones de formato de la referencia cultural actual. El intento de leer dos de los
elementos de datos genera una excepción FormatException y la matriz de fechas ahora contiene dos elementos
incorrectos que iguales a MinValue.

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;

public class Example


{
private static string filename = @".\dates.dat";

public static void Main()


{
DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0),
new DateTime(1818, 5, 5, 7, 19, 0),
new DateTime(1870, 4, 22, 23, 54, 0),
new DateTime(1890, 9, 8, 6, 47, 0),
new DateTime(1890, 9, 8, 6, 47, 0),
new DateTime(1905, 2, 18, 15, 12, 0) };
// Write the data to a file using the current culture.
WriteData(dates);
// Change the current culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
// Read the data using the current culture.
DateTime[] newDates = ReadData();
foreach (var newDate in newDates)
Console.WriteLine(newDate.ToString("g"));
}

private static void WriteData(DateTime[] dates)


{
StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);
for (int ctr = 0; ctr < dates.Length; ctr++) {
sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
if (ctr < dates.Length - 1) sw.Write("|");
}
sw.Close();
}

private static DateTime[] ReadData()


{
bool exceptionOccurred = false;

// Read file contents as a single string, then split it.


StreamReader sr = new StreamReader(filename, Encoding.UTF8);
string output = sr.ReadToEnd();
sr.Close();

string[] values = output.Split( new char[] { '|' } );


DateTime[] newDates = new DateTime[values.Length];
for (int ctr = 0; ctr < values.Length; ctr++) {
try {
newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
}
catch (FormatException) {
Console.WriteLine("Failed to parse {0}", values[ctr]);
exceptionOccurred = true;
}
}
if (exceptionOccurred) Console.WriteLine();
return newDates;
}
}
// The example displays the following output:
// Failed to parse 4/22/1870 11:54 PM
// Failed to parse 2/18/1905 3:12 PM
//
// 05.06.1758 21:26
// 05.05.1818 07:19
// 01.01.0001 00:00
// 09.08.1890 06:47
// 01.01.0001 00:00
// 01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading

Module Example
Private filename As String = ".\dates.dat"

Public Sub Main()


Dim dates() As Date = { #5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _
#4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _
#2/18/1905 3:12PM# }
' Write the data to a file using the current culture.
WriteData(dates)
' Change the current culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
' Read the data using the current culture.
Dim newDates() As Date = ReadData()
For Each newDate In newDates
Console.WriteLine(newDate.ToString("g"))
Next
End Sub

Private Sub WriteData(dates() As Date)


Dim sw As New StreamWriter(filename, False, Encoding.Utf8)
For ctr As Integer = 0 To dates.Length - 1
sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
If ctr < dates.Length - 1 Then sw.Write("|")
Next
sw.Close()
End Sub

Private Function ReadData() As Date()


Dim exceptionOccurred As Boolean = False

' Read file contents as a single string, then split it.


Dim sr As New StreamReader(filename, Encoding.Utf8)
Dim output As String = sr.ReadToEnd()
sr.Close()

Dim values() As String = output.Split( {"|"c } )


Dim newDates(values.Length - 1) As Date
For ctr As Integer = 0 To values.Length - 1
Try
newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
Catch e As FormatException
Console.WriteLine("Failed to parse {0}", values(ctr))
exceptionOccurred = True
End Try
Next
If exceptionOccurred Then Console.WriteLine()
Return newDates
End Function
End Module
' The example displays the following output:
' Failed to parse 4/22/1870 11:54 PM
' Failed to parse 2/18/1905 3:12 PM
'
' 05.06.1758 21:26
' 05.05.1818 07:19
' 01.01.0001 00:00
' 09.08.1890 06:47
' 01.01.0001 00:00
' 01.01.0001 00:00
'
Pero si reemplaza la propiedad CultureInfo.CurrentCulture por CultureInfo.InvariantCulture en las llamadas a
DateTime.ToString(String, IFormatProvider) y a DateTime.Parse(String, IFormatProvider), los datos persistentes
de fecha y hora se restauran correctamente, como se muestra en la salida siguiente:

06.05.1758 21:26
05.05.1818 07:19
22.04.1870 23:54
08.09.1890 06:47
18.02.1905 15:12

Vea también
Manipular cadenas
Operaciones básicas de cadenas en .NET
25/11/2019 • 2 minutes to read • Edit Online

A menudo, las aplicaciones responden a los usuarios mediante la construcción de mensajes basados en los datos
proporcionados por el usuario. Por ejemplo, no es raro que los sitios web respondan a un usuario que acaba de
iniciar sesión con un saludo especializado que incluye el nombre del usuario. Varios métodos de las clases
System.String y System.Text.StringBuilder le permiten construir cadenas personalizadas de forma dinámica para
mostrarlas en la interfaz de usuario. Estos métodos también le ayudan a realizar una serie de operaciones básicas
de cadenas, como crear cadenas nuevas a partir de matrices de bytes, comparar los valores de cadenas y
modificar cadenas existentes.

En esta sección
Creación de cadenas nuevas
Se describen formas básicas para convertir objetos en cadenas y combinar cadenas.
Recortar y quitar caracteres
Se describe cómo recortar o quitar caracteres de una cadena.
Rellenado de cadenas
Describe cómo insertar caracteres o espacios vacíos en una cadena.
Comparar cadenas
Se describe cómo comparar el contenido de dos o más cadenas.
Cambio de mayúsculas y minúsculas
Se describe cómo cambiar las mayúsculas y minúsculas de los caracteres de una cadena.
Utilizar la clase StringBuilder
Se describe cómo crear y modificar objetos de cadena dinámicos con la clase StringBuilder.
Cómo: para realizar manipulaciones de cadena básicas
Se describe el uso de las operaciones de cadena básicas.

Secciones relacionadas
Conversión de tipos en .NET
Se describe cómo convertir un tipo en otro.
Aplicación de formato a tipos
Se describe cómo dar formato a cadenas mediante los especificadores de formato.
Creación de cadenas en .NET
04/11/2019 • 7 minutes to read • Edit Online

.NET Framework permite crear cadenas mediante asignaciones simples y además sobrecarga un constructor de
clases para admitir la creación de cadenas con una serie de parámetros distintos. .NET Framework también
proporciona varios métodos en la clase System.String que crean nuevos objetos de cadena al combinar varias
cadenas, matrices de cadenas u objetos.

Creación de cadenas mediante asignaciones


La manera más sencilla de crear un objeto String es asignar un literal de cadena a un objeto String.

Creación de cadenas mediante un constructor de clase


Puede usar las sobrecargas del constructor de clases String para crear cadenas a partir de matrices de caracteres.
También puede crear una nueva cadena al duplicar un determinado carácter un número especificado de veces.

Métodos que devuelven cadenas


En la tabla siguiente se enumeran varios métodos útiles que devuelven nuevos objetos de cadena.

NOMBRE DEL MÉTODO USAR

String.Format Compila una cadena con formato a partir de un conjunto de


objetos de entrada.

String.Concat Compila cadenas a partir de dos o más cadenas.

String.Join Compila una nueva cadena al combinar una matriz de


cadenas.

String.Insert Compila una nueva cadena al insertar una cadena en el índice


especificado de una cadena existente.

String.CopyTo Copia los caracteres especificados de una cadena en la


posición especificada de una matriz de caracteres.

Formato
Puede usar el método String.Format para crear cadenas con formato y concatenar cadenas que representan a
varios objetos. Este método convierte automáticamente cualquier objeto pasado en una cadena. Por ejemplo, si la
aplicación debe mostrar un valor Int32 y un valor DateTime al usuario, puede construir fácilmente una cadena
para representar estos valores con el método Format. Para más información sobre las convenciones de formato
usadas con este método, consulte la sección sobre formatos compuestos.
En el ejemplo siguiente se usa el método Format para crear una cadena que emplea una variable de entero.
int numberOfFleas = 12;
string miscInfo = String.Format("Your dog has {0} fleas. " +
"It is time to get a flea collar. " +
"The current universal date is: {1:u}.",
numberOfFleas, DateTime.Now);
Console.WriteLine(miscInfo);
// The example displays the following output:
// Your dog has 12 fleas. It is time to get a flea collar.
// The current universal date is: 2008-03-28 13:31:40Z.

Dim numberOfFleas As Integer = 12


Dim miscInfo As String = String.Format("Your dog has {0} fleas. " & _
"It is time to get a flea collar. " & _
"The current universal date is: {1:u}.", _
numberOfFleas, Date.Now)
Console.WriteLine(miscInfo)
' The example displays the following output:
' Your dog has 12 fleas. It is time to get a flea collar.
' The current universal date is: 2008-03-28 13:31:40Z.

En este ejemplo, DateTime.Now muestra la fecha y hora actuales en el formato especificado por la referencia
cultural asociada al subproceso actual.
Concat
El método String.Concat se puede usar para crear fácilmente un objeto de cadena a partir de dos o más objetos
existentes. Proporciona una manera independiente del lenguaje de concatenar cadenas. Este método acepta
cualquier clase que derive de System.Object. En el ejemplo siguiente se crea una cadena a partir de dos objetos
de cadena existentes y un carácter de separación.

string helloString1 = "Hello";


string helloString2 = "World!";
Console.WriteLine(String.Concat(helloString1, ' ', helloString2));
// The example displays the following output:
// Hello World!

Dim helloString1 As String = "Hello"


Dim helloString2 As String = "World!"
Console.WriteLine(String.Concat(helloString1, " "c, helloString2))
' The example displays the following output:
' Hello World!

Join
El método String.Join crea una cadena a partir de una matriz de cadenas y una cadena separadora. Este método
resulta útil si quiere concatenar varias cadenas para formar una lista quizás separada por una coma.
En el ejemplo siguiente se usa un espacio para enlazar una matriz de cadenas.

string[] words = {"Hello", "and", "welcome", "to", "my" , "world!"};


Console.WriteLine(String.Join(" ", words));
// The example displays the following output:
// Hello and welcome to my world!
Dim words() As String = {"Hello", "and", "welcome", "to", "my" , "world!"}
Console.WriteLine(String.Join(" ", words))
' The example displays the following output:
' Hello and welcome to my world!

Insertar
El método String.Insert crea una cadena al insertar una cadena en la posición especificada de otra cadena. Este
método usa un índice basado en cero. En el ejemplo siguiente se inserta una cadena en la quinta posición del
índice de MyString y se crea una nueva cadena con este valor.

string sentence = "Once a time.";


Console.WriteLine(sentence.Insert(4, " upon"));
// The example displays the following output:
// Once upon a time.

Dim sentence As String = "Once a time."


Console.WriteLine(sentence.Insert(4, " upon"))
' The example displays the following output:
' Once upon a time.

CopyTo
El método String.CopyTo copia partes de una cadena en una matriz de caracteres. Puede especificar el índice
inicial de la cadena y el número de caracteres que se va a copiar. Este método toma el índice de origen, una matriz
de caracteres, el índice de destino y el número de caracteres que se va a copiar. Todos los índices se basan en cero.
En el ejemplo siguiente se usa el método CopyTo para copiar los caracteres de la palabra "Hello" de un objeto de
cadena en la primera posición del índice de una matriz de caracteres.

string greeting = "Hello World!";


char[] charArray = {'W','h','e','r','e'};
Console.WriteLine("The original character array: {0}", new string(charArray));
greeting.CopyTo(0, charArray,0 ,5);
Console.WriteLine("The new character array: {0}", new string(charArray));
// The example displays the following output:
// The original character array: Where
// The new character array: Hello

Dim greeting As String = "Hello World!"


Dim charArray() As Char = {"W"c, "h"c, "e"c, "r"c, "e"c}
Console.WriteLine("The original character array: {0}", New String(charArray))
greeting.CopyTo(0, charArray,0 ,5)
Console.WriteLine("The new character array: {0}", New String(charArray))
' The example displays the following output:
' The original character array: Where
' The new character array: Hello

Vea también
Operaciones básicas de cadenas
Formatos compuestos
Recorte y eliminación de caracteres de cadenas en
.NET
04/11/2019 • 8 minutes to read • Edit Online

Si va a analizar una frase en las palabras que la forman, el resultado pueden ser palabras con espacios en blanco
delante y detrás. En este caso, puede usar uno de los métodos de recorte de la clase System.String para quitar
espacios u otros caracteres de una posición especificada de la cadena. En la tabla siguiente se describen los
métodos de recorte disponibles.

NOMBRE DEL MÉTODO USAR

String.Trim Quita del comienzo y del final de una cadena los espacios en
blanco o los caracteres especificados en una matriz de
caracteres.

String.TrimEnd Quita los caracteres especificados de una matriz de caracteres


del final de una cadena.

String.TrimStart Quita los caracteres especificados de una matriz de caracteres


del comienzo de una cadena.

String.Remove Quita un número especificado de caracteres de una posición


de índice especificada de una cadena.

Trim
Los espacios en blanco situados delante y detrás de una cadena se pueden quitar fácilmente con el método
String.Trim, como se muestra en el ejemplo siguiente.

String^ MyString = " Big ";


Console::WriteLine("Hello{0}World!", MyString);
String^ TrimString = MyString->Trim();
Console::WriteLine("Hello{0}World!", TrimString);
// The example displays the following output:
// Hello Big World!
// HelloBigWorld!

string MyString = " Big ";


Console.WriteLine("Hello{0}World!", MyString);
string TrimString = MyString.Trim();
Console.WriteLine("Hello{0}World!", TrimString);
// The example displays the following output:
// Hello Big World!
// HelloBigWorld!
Dim MyString As String = " Big "
Console.WriteLine("Hello{0}World!", MyString)
Dim TrimString As String = MyString.Trim()
Console.WriteLine("Hello{0}World!", TrimString)
' The example displays the following output:
' Hello Big World!
' HelloBigWorld!

También se pueden quitar del principio y el final de una cadena los caracteres especificados en una matriz de
caracteres. En el ejemplo siguiente se quitan los caracteres de espacio en blanco, los puntos y asteriscos.

using System;

public class Example


{
public static void Main()
{
String header = "* A Short String. *";
Console.WriteLine(header);
Console.WriteLine(header.Trim( new Char[] { ' ', '*', '.' } ));
}
}
// The example displays the following output:
// * A Short String. *
// A Short String

Module Example
Public Sub Main()
Dim header As String = "* A Short String. *"
Console.WriteLine(header)
Console.WriteLine(header.Trim( { " "c, "*"c, "."c } ))
End Sub
End Module
' The example displays the following output:
' * A Short String. *
' A Short String

TrimEnd
El método String.TrimEnd quita caracteres del final de una cadena, creando un nuevo objeto de cadena. A este
método se le pasa una matriz de caracteres para especificar los caracteres que se van a quitar. El orden de los
elementos en la matriz de caracteres no afecta a la operación de recorte. El recorte se detiene cuando se encuentra
un carácter no especificado en la matriz.
En el ejemplo siguiente se quitan las últimas letras de una cadena con el método TrimEnd. En este ejemplo, se
invierte la posición de los caracteres 'r' y 'W' para ilustrar que el orden de los caracteres en la matriz no tiene
importancia. Observe que este código quita la última palabra de MyString y parte de la primera.

String^ MyString = "Hello World!";


array<Char>^ MyChar = {'r','o','W','l','d','!',' '};
String^ NewString = MyString->TrimEnd(MyChar);
Console::WriteLine(NewString);
string MyString = "Hello World!";
char[] MyChar = {'r','o','W','l','d','!',' '};
string NewString = MyString.TrimEnd(MyChar);
Console.WriteLine(NewString);

Dim MyString As String = "Hello World!"


Dim MyChar() As Char = {"r","o","W","l","d","!"," "}
Dim NewString As String = MyString.TrimEnd(MyChar)
Console.WriteLine(NewString)

Con este código se muestra He en la consola.


En el ejemplo siguiente se quita la última palabra de una cadena con el método TrimEnd. En este código hay una
coma después de Hello y, como la coma no está especificada en la matriz de caracteres que se deben recortar, la
operación se detiene en la coma.

String^ MyString = "Hello, World!";


array<Char>^ MyChar = {'r','o','W','l','d','!',' '};
String^ NewString = MyString->TrimEnd(MyChar);
Console::WriteLine(NewString);

string MyString = "Hello, World!";


char[] MyChar = {'r','o','W','l','d','!',' '};
string NewString = MyString.TrimEnd(MyChar);
Console.WriteLine(NewString);

Dim MyString As String = "Hello, World!"


Dim MyChar() As Char = {"r","o","W","l","d","!"," "}
Dim NewString As String = MyString.TrimEnd(MyChar)
Console.WriteLine(NewString)

Con este código se muestra Hello, en la consola.

TrimStart
El método String.TrimStart es parecido al método String.TrimEnd, con la diferencia de que crea una nueva
cadena quitando caracteres del comienzo de un objeto de cadena existente. Al método TrimStart se le pasa una
matriz de caracteres para especificar los caracteres que se van a quitar. Lo mismo que en el método TrimEnd, el
orden de los elementos en la matriz de caracteres no afecta a la operación de recorte. El recorte se detiene cuando
se encuentra un carácter no especificado en la matriz.
En el siguiente ejemplo se quita la primera palabra de una cadena. En este ejemplo, se invierte la posición de los
caracteres 'l' y 'H' para ilustrar que el orden de los caracteres en la matriz no tiene importancia.

String^ MyString = "Hello World!";


array<Char>^ MyChar = {'e', 'H','l','o',' ' };
String^ NewString = MyString->TrimStart(MyChar);
Console::WriteLine(NewString);
string MyString = "Hello World!";
char[] MyChar = {'e', 'H','l','o',' ' };
string NewString = MyString.TrimStart(MyChar);
Console.WriteLine(NewString);

Dim MyString As String = "Hello World!"


Dim MyChar() As Char = {"e","H","l","o"," " }
Dim NewString As String = MyString.TrimStart(MyChar)
Console.WriteLine(NewString)

Con este código se muestra World! en la consola.

Quitar
El método String.Remove quita un número especificado de caracteres, comenzando en una posición especificada
de una cadena existente. Este método utiliza un índice basado en cero.
En el ejemplo siguiente se quitan diez caracteres de una cadena, comenzando en la posición cinco de un índice de
base cero de la cadena.

String^ MyString = "Hello Beautiful World!";


Console::WriteLine(MyString->Remove(5,10));
// The example displays the following output:
// Hello World!

string MyString = "Hello Beautiful World!";


Console.WriteLine(MyString.Remove(5,10));
// The example displays the following output:
// Hello World!

Dim MyString As String = "Hello Beautiful World!"


Console.WriteLine(MyString.Remove(5,10))
' The example displays the following output:
' Hello World!

Sustituya
También puede quitar un carácter o una subcadena de una cadena llamando al método String.Replace(String,
String) y especificando una cadena vacía (String.Empty) como reemplazo. En el ejemplo siguiente se quitan todas
las comas de una cadena.
using System;

public class Example


{
public static void Main()
{
String phrase = "a cold, dark night";
Console.WriteLine("Before: {0}", phrase);
phrase = phrase.Replace(",", "");
Console.WriteLine("After: {0}", phrase);
}
}
// The example displays the following output:
// Before: a cold, dark night
// After: a cold dark night

Module Example
Public Sub Main()
Dim phrase As String = "a cold, dark night"
Console.WriteLine("Before: {0}", phrase)
phrase = phrase.Replace(",", "")
Console.WriteLine("After: {0}", phrase)
End Sub
End Module
' The example displays the following output:
' Before: a cold, dark night
' After: a cold dark night

Vea también
Operaciones básicas de cadenas
Relleno de cadenas en .NET
04/11/2019 • 2 minutes to read • Edit Online

Use uno de los siguientes métodos String para crear una cadena que conste de una cadena original rellenada con
caracteres iniciales o finales hasta una longitud total especificada. El carácter de relleno puede ser un espacio o un
carácter especificado. La cadena resultante aparece alineada a la derecha o bien a la izquierda. Si la longitud de la
cadena original ya es igual o mayor que la longitud total deseada, los métodos de relleno devuelven la cadena
original sin modificarla. Para obtener más información, vea las secciones Devoluciones de las dos sobrecargas de
los métodos String.PadLeft y String.PadRight.

NOMBRE DEL MÉTODO USAR

String.PadLeft Rellena una cadena con caracteres iniciales hasta una longitud
total especificada.

String.PadRight Rellena una cadena con caracteres finales hasta una longitud
total especificada.

PadLeft
El método String.PadLeft crea una cadena mediante la concatenación de suficientes caracteres de relleno iniciales
con una cadena original para alcanzar la longitud total especificada. El método String.PadLeft(Int32) usa el espacio
en blanco como carácter de relleno y el método String.PadLeft(Int32, Char) le permite especificar su propio
carácter de relleno.
En el ejemplo de código siguiente se usa el método PadLeft para crear una cadena con una longitud de veinte
caracteres. En el ejemplo se muestra " --------Hello World! " en la consola.

String^ MyString = "Hello World!";


Console::WriteLine(MyString->PadLeft(20, '-'));

string MyString = "Hello World!";


Console.WriteLine(MyString.PadLeft(20, '-'));

Dim MyString As String = "Hello World!"


Console.WriteLine(MyString.PadLeft(20, "-"c))

PadRight
El método String.PadRight crea una cadena mediante la concatenación de suficientes caracteres de relleno finales
con una cadena original para alcanzar la longitud total especificada. El método String.PadRight(Int32) usa el
espacio en blanco como carácter de relleno y el método String.PadRight(Int32, Char) le permite especificar su
propio carácter de relleno.
En el ejemplo de código siguiente se usa el método PadRight para crear una cadena con una longitud de veinte
caracteres. En el ejemplo se muestra " Hello World!-------- " en la consola.
String^ MyString = "Hello World!";
Console::WriteLine(MyString->PadRight(20, '-'));

string MyString = "Hello World!";


Console.WriteLine(MyString.PadRight(20, '-'));

Dim MyString As String = "Hello World!"


Console.WriteLine(MyString.PadRight(20, "-"c))

Vea también
Operaciones básicas de cadenas
Comparación de cadenas en .NET
04/11/2019 • 13 minutes to read • Edit Online

.NET proporciona varios métodos para comparar los valores de cadenas. En la tabla siguiente se enumeran y
describen los métodos de comparación de valores.

NOMBRE DEL MÉTODO USAR

String.Compare Compara los valores de dos cadenas. Devuelve un valor


entero.

String.CompareOrdinal Compara dos cadenas independientemente de la referencia


cultural local. Devuelve un valor entero.

String.CompareTo Compara el objeto de cadena actual con otra cadena.


Devuelve un valor entero.

String.StartsWith Determina si una cadena comienza con la cadena que se pasa.


Devuelve un valor booleano.

String.EndsWith Determina si una cadena termina con la cadena que se pasa.


Devuelve un valor booleano.

String.Equals Determina si dos cadenas son iguales. Devuelve un valor


booleano.

String.IndexOf Devuelve la posición de índice de un carácter o cadena,


empezando en el comienzo de la cadena que se examina.
Devuelve un valor entero.

String.LastIndexOf Devuelve la posición de índice de un carácter o cadena,


empezando en el final de la cadena que se examina. Devuelve
un valor entero.

Comparar
El método String.Compare estático proporciona una manera de comparar dos cadenas exhaustivamente. En este
método se tiene en cuenta la referencia cultural. Esta función se puede usar para comparar dos cadenas o
subcadenas de dos cadenas. Además, se proporcionan sobrecargas para tener en cuenta o no las diferencias de
referencia cultural y de mayúsculas y minúsculas. En la tabla siguiente, se muestran los tres valores enteros que
este método puede devolver.

VALOR DEVUELTO CONDICIÓN

Un entero negativo La primera cadena precede a la segunda cadena en el criterio


de ordenación.

O bien

La primera cadena es null .


VALOR DEVUELTO CONDICIÓN

0 La primera y la segunda cadena son iguales.

O bien

Ambas cadenas son null .

Un entero positivo. La primera cadena sigue a la segunda cadena en el criterio de


ordenación.
O bien
O bien
1
La segunda cadena es null .

IMPORTANT
La finalidad principal del método String.Compare es que se utilice para la ordenación o clasificación de cadenas. El método
String.Compare no debe utilizarse para comprobar la igualdad (es decir, para buscar explícitamente un valor devuelto que sea
0 sin tener en cuenta si una cadena es menor o mayor que otra). En su lugar, para determinar si dos cadenas son iguales, use
el método String.Equals(String, String, StringComparison) .

En el ejemplo siguiente, se usa el método String.Compare para determinar los valores relativos de dos cadenas.

String^ string1 = "Hello World!";


Console::WriteLine(String::Compare(string1, "Hello World?"));

string string1 = "Hello World!";


Console.WriteLine(String.Compare(string1, "Hello World?"));

Dim string1 As String = "Hello World!"


Console.WriteLine(String.Compare(string1, "Hello World?"))

Con este ejemplo se muestra -1 en la consola.


En el ejemplo anterior se tienen en cuenta las referencias culturales de forma predeterminada. Para realizar una
comparación de cadenas que no tenga en cuenta las referencias culturales, utilice una sobrecarga del método
String.Compare ya que permite especificar la referencia cultural que se debe utilizar mediante un parámetro de
referencia cultural . Para obtener un ejemplo que muestra cómo utilizar el método String.Compare para realizar
una comparación de este tipo, consulte Realizar comparaciones de cadenas que no tienen en cuenta las referencias
culturales.

CompareOrdinal
El método String.CompareOrdinal compara dos objetos de cadena sin tener en cuenta la referencia cultural local.
Los valores devueltos de este método son idénticos a los que devolvía el método Compare en la tabla anterior.
IMPORTANT
La finalidad principal del método String.CompareOrdinal es que se utilice para la ordenación o clasificación de cadenas. El
método String.CompareOrdinal no debe utilizarse para comprobar la igualdad (es decir, para buscar explícitamente un valor
devuelto que sea 0 sin tener en cuenta si una cadena es menor o mayor que otra). En su lugar, para determinar si dos
cadenas son iguales, use el método String.Equals(String, String, StringComparison) .

En el ejemplo siguiente se usa el método CompareOrdinal para comparar los valores de dos cadenas.

String^ string1 = "Hello World!";


Console::WriteLine(String::CompareOrdinal(string1, "hello world!"));

string string1 = "Hello World!";


Console.WriteLine(String.CompareOrdinal(string1, "hello world!"));

Dim string1 As String = "Hello World!"


Console.WriteLine(String.CompareOrdinal(string1, "hello world!"))

Con este ejemplo se muestra -32 en la consola.

CompareTo
El método String.CompareTo compara la cadena que encapsula el objeto de cadena actual con otra cadena u
objeto. Los valores devueltos de este método son idénticos a los que devolvía el método String.Compare en la
tabla anterior.

IMPORTANT
La finalidad principal del método String.CompareTo es que se utilice para la ordenación o clasificación de cadenas. El método
String.CompareTo no debe utilizarse para comprobar la igualdad (es decir, para buscar explícitamente un valor devuelto que
sea 0 sin tener en cuenta si una cadena es menor o mayor que otra). En su lugar, para determinar si dos cadenas son iguales,
use el método String.Equals(String, String, StringComparison) .

En el ejemplo siguiente se usa el método String.CompareTo para comparar los objetos string1 y string2 .

String^ string1 = "Hello World";


String^ string2 = "Hello World!";
int MyInt = string1->CompareTo(string2);
Console::WriteLine( MyInt );

string string1 = "Hello World";


string string2 = "Hello World!";
int MyInt = string1.CompareTo(string2);
Console.WriteLine( MyInt );

Dim string1 As String = "Hello World"


Dim string2 As String = "Hello World!"
Dim MyInt As Integer = string1.CompareTo(string2)
Console.WriteLine(MyInt)
Con este ejemplo se muestra -1 en la consola.
Todas las sobrecargas del método String.CompareTo realizan comparaciones que tienen en cuenta las referencias
culturales y las mayúsculas y minúsculas de manera predeterminada. No se proporcionan sobrecargas de este
método que permitan realizar una comparación que no tenga en cuenta las referencias culturales Para lograr
claridad en el código, se recomienda utilizar el método String.Compare en su lugar, especificando
CultureInfo.CurrentCulture para las operaciones que tienen en cuenta la referencia cultural o
CultureInfo.InvariantCulture para las operaciones que no la tienen en cuenta. Para obtener ejemplos que muestran
cómo utilizar el método String.Compare para realizar comparaciones de este tipo, vea Realizar comparaciones de
cadenas que no tienen en cuenta las referencias culturales.

Es igual a
El método String.Equals puede determinar con facilidad si dos cadenas son iguales. Este método distingue entre
mayúsculas y minúsculas y devuelve un valor booleano True o False . Se puede usar desde una clase existente,
como se muestra en el siguiente ejemplo. En el ejemplo siguiente se usa el método Equals para determinar si un
objeto de cadena contiene la frase "Hello World".

String^ string1 = "Hello World";


Console::WriteLine(string1->Equals("Hello World"));

string string1 = "Hello World";


Console.WriteLine(string1.Equals("Hello World"));

Dim string1 As String = "Hello World"


Console.WriteLine(string1.Equals("Hello World"))

Con este ejemplo se muestra True en la consola.


Este método se puede usar también como método estático. En el ejemplo siguiente se comparan dos objetos de
cadena utilizando un método estático.

String^ string1 = "Hello World";


String^ string2 = "Hello World";
Console::WriteLine(String::Equals(string1, string2));

string string1 = "Hello World";


string string2 = "Hello World";
Console.WriteLine(String.Equals(string1, string2));

Dim string1 As String = "Hello World"


Dim string2 As String = "Hello World"
Console.WriteLine(String.Equals(string1, string2))

Con este ejemplo se muestra True en la consola.

StartsWith y EndsWith
El método String.StartsWith se puede usar para determinar si un objeto de cadena comienza con los mismos
caracteres que forman otra cadena. Este método distingue entre mayúsculas y minúsculas y devuelve true si el
objeto de cadena actual comienza con la cadena que se pasa y false si no lo hace. En el ejemplo siguiente se usa
este método para determinar si un objeto de cadena comienza con "Hello".

String^ string1 = "Hello World";


Console::WriteLine(string1->StartsWith("Hello"));

string string1 = "Hello World";


Console.WriteLine(string1.StartsWith("Hello"));

Dim string1 As String = "Hello World!"


Console.WriteLine(string1.StartsWith("Hello"))

Con este ejemplo se muestra True en la consola.


El método String.EndsWith compara la cadena que se pasa con los caracteres del final del objeto de cadena
actual. También devuelve un valor booleano. En el ejemplo siguiente se comprueba el final de una cadena con el
método EndsWith .

String^ string1 = "Hello World";


Console::WriteLine(string1->EndsWith("Hello"));

string string1 = "Hello World";


Console.WriteLine(string1.EndsWith("Hello"));

Dim string1 As String = "Hello World!"


Console.WriteLine(string1.EndsWith("Hello"))

Con este ejemplo se muestra False en la consola.

IndexOf y LastIndexOf
El método String.IndexOf se puede usar para determinar la posición de la primera aparición de un carácter
concreto dentro de una cadena. Este método, que distingue entre mayúsculas y minúsculas, empieza a contar
desde el comienzo de una cadena y devuelve la posición del carácter que se pasa utilizando un índice de base cero.
Si no encuentra el carácter, se devuelve un valor de –1.
En el ejemplo siguiente se usa el método IndexOf para buscar la primera aparición del carácter ' l ' en una
cadena.

String^ string1 = "Hello World";


Console::WriteLine(string1->IndexOf('l'));

string string1 = "Hello World";


Console.WriteLine(string1.IndexOf('l'));

Dim string1 As String = "Hello World!"


Console.WriteLine(string1.IndexOf("l"))

Con este ejemplo se muestra 2 en la consola.


El método String.LastIndexOf es parecido al método String.IndexOf , con la diferencia de que devuelve la
posición de la última instancia de un carácter concreto en una cadena. Distingue mayúsculas y minúsculas y utiliza
un índice de base cero.
En el ejemplo siguiente se usa el método LastIndexOf para buscar la última aparición del carácter ' l ' en una
cadena.

String^ string1 = "Hello World";


Console::WriteLine(string1->LastIndexOf('l'));

string string1 = "Hello World";


Console.WriteLine(string1.LastIndexOf('l'));

Dim string1 As String = "Hello World!"


Console.WriteLine(string1.LastIndexOf("l"))

Con este ejemplo se muestra 9 en la consola.


Los dos métodos resultan útiles si se usan junto con el método String.Remove . Se pueden usar los métodos
IndexOf o LastIndexOf para recuperar la posición de un carácter y, a continuación, proporcionar esa posición al
método Remove para quitar un carácter o una palabra que comience por ese carácter.

Vea también
Operaciones básicas de cadenas
Realizar operaciones de cadenas que no distinguen entre referencias culturales
Ordenación de tablas de peso (para .NET en Windows)
Tabla de elementos de intercalación predeterminada Unicode (para .NET Core en macOS y Linux)
Cambiar mayúsculas y minúsculas en .NET
13/01/2020 • 8 minutes to read • Edit Online

Si escribe una aplicación que acepta la entrada de un usuario, nunca podrá estar seguro de si usará mayúsculas o
minúsculas para escribir los datos. Normalmente querrá que las cadenas usen mayúsculas y minúsculas de forma
coherente, especialmente si se van a mostrar en la interfaz de usuario. En la tabla siguiente se describen tres
métodos para cambiar las mayúsculas y minúsculas. Los dos primeros métodos proporcionan una sobrecarga que
acepta una referencia cultural.

NOMBRE DEL MÉTODO USAR

String.ToUpper Convierte todos los caracteres de una cadena a mayúsculas.

String.ToLower Convierte todos los caracteres de una cadena a minúsculas.

TextInfo.ToTitleCase Convierte una cadena a mayúsculas de tipo título.

WARNING
Tenga en cuenta que los métodos String.ToUpper y String.ToLower no deben usarse para convertir cadenas para compararlas
ni para comprobar su igualdad. Para más información, vea la sección Comparar cadenas con mayúsculas y minúsculas
mezcladas.

Comparar cadenas con mayúsculas y minúsculas mezcladas


Para comparar cadenas con mayúsculas y minúsculas mezcladas para determinar su orden, llame a una de las
sobrecargas del método String.CompareTo con un parámetro comparisonType y proporcione un valor
StringComparison.CurrentCultureIgnoreCase, StringComparison.InvariantCultureIgnoreCase o
StringComparison.OrdinalIgnoreCase para el argumento comparisonType . Para realizar una comparación usando
una referencia cultural específica que no sea la referencia cultural actual, llame a una sobrecarga del método
String.CompareTo con los parámetros culture y options , y proporcione el valor CompareOptions.IgnoreCase
como el argumento options .
Para comparar cadenas con mayúsculas y minúsculas mezcladas para determinar si son iguales, llame a una de las
sobrecargas del método String.Equals con un parámetro comparisonType y proporcione un valor
StringComparison.CurrentCultureIgnoreCase, StringComparison.InvariantCultureIgnoreCase o
StringComparison.OrdinalIgnoreCase para el argumento comparisonType .
Para obtener más información, consulte Procedimientos recomendados para el uso de cadenas.

ToUpper
El método String.ToUpper convierte todos los caracteres de una cadena a mayúsculas. En el siguiente ejemplo, se
convierte la cadena "Hello World!" de mayúsculas y minúsculas mezcladas a mayúsculas.

string properString = "Hello World!";


Console.WriteLine(properString.ToUpper());
// This example displays the following output:
// HELLO WORLD!
Dim MyString As String = "Hello World!"
Console.WriteLine(MyString.ToUpper())
' This example displays the following output:
' HELLO WORLD!

El ejemplo anterior tiene en cuenta la referencia cultural de forma predeterminada; aplica las convenciones de
mayúsculas y minúsculas de la referencia cultural actual. Para realizar un cambio de mayúsculas y minúsculas sin
tener en cuenta la referencia cultural o para aplicar las convenciones de mayúsculas y minúsculas de una referencia
cultural determinada, use la sobrecarga del método String.ToUpper(CultureInfo) y proporcione un valor
CultureInfo.InvariantCulture o un objeto System.Globalization.CultureInfo que representa la referencia cultural
especificada al parámetro culture. Para obtener un ejemplo que muestra cómo usar el método ToUpper para
realizar un cambio de mayúsculas y minúsculas sin tener en cuenta la referencia cultural, consulte Realizar cambios
de mayúsculas y minúsculas que no tienen en cuenta las referencias culturales.

ToLower
El método String.ToLower es similar al método anterior, pero en su lugar convierte todos los caracteres de una
cadena a minúsculas. En el siguiente ejemplo, se convierte la cadena "Hello World!" en minúsculas.

string properString = "Hello World!";


Console.WriteLine(properString.ToLower());
// This example displays the following output:
// hello world!

Dim MyString As String = "Hello World!"


Console.WriteLine(MyString.ToLower())
' This example displays the following output:
' hello world!

El ejemplo anterior tiene en cuenta la referencia cultural de forma predeterminada; aplica las convenciones de
mayúsculas y minúsculas de la referencia cultural actual. Para realizar un cambio de mayúsculas y minúsculas sin
tener en cuenta la referencia cultural o para aplicar las convenciones de mayúsculas y minúsculas de una referencia
cultural determinada, use la sobrecarga del método String.ToLower(CultureInfo) y proporcione un valor
CultureInfo.InvariantCulture o un objeto System.Globalization.CultureInfo que representa la referencia cultural
especificada al parámetro culture. Para obtener un ejemplo que muestra cómo usar el método
ToLower(CultureInfo) para realizar un cambio de mayúsculas y minúsculas sin tener en cuenta la referencia
cultural, consulte Realizar cambios de mayúsculas y minúsculas que no tienen en cuenta las referencias culturales.

ToTitleCase
El método TextInfo.ToTitleCase convierte el primer carácter de cada palabra a mayúsculas y el resto de los
caracteres a minúsculas. Sin embargo, se da por hecho que las palabras que están completamente en mayúsculas
son siglas y no se convierten.
El método TextInfo.ToTitleCase tiene en cuenta la referencia cultural; es decir, usa las convenciones de mayúsculas y
minúsculas de una referencia cultural determinada. Para llamar al método, recupere primero el objeto TextInfo que
representa las convenciones de mayúsculas y minúsculas de la referencia cultural determinada a partir de la
propiedad CultureInfo.TextInfo de una referencia cultural determinada.
En el ejemplo siguiente, se pasa cada cadena de una matriz al método TextInfo.ToTitleCase. Las cadenas incluyen
cadenas de título correctas así como acrónimos. Las cadenas se convierten a mayúsculas de tipo título usando las
convenciones de mayúsculas y minúsculas de la referencia cultural Inglés (Estados Unidos).
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
string[] values = { "a tale of two cities", "gROWL to the rescue",
"inside the US government", "sports and MLB baseball",
"The Return of Sherlock Holmes", "UNICEF and children"};

TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
foreach (var value in values)
Console.WriteLine("{0} --> {1}", value, ti.ToTitleCase(value));
}
}
// The example displays the following output:
// a tale of two cities --> A Tale Of Two Cities
// gROWL to the rescue --> Growl To The Rescue
// inside the US government --> Inside The US Government
// sports and MLB baseball --> Sports And MLB Baseball
// The Return of Sherlock Holmes --> The Return Of Sherlock Holmes
// UNICEF and children --> UNICEF And Children

Imports System.Globalization

Module Example
Public Sub Main()
Dim values() As String = { "a tale of two cities", "gROWL to the rescue",
"inside the US government", "sports and MLB baseball",
"The Return of Sherlock Holmes", "UNICEF and children"}

Dim ti As TextInfo = CultureInfo.CurrentCulture.TextInfo


For Each value In values
Console.WriteLine("{0} --> {1}", value, ti.ToTitleCase(value))
Next
End Sub
End Module
' The example displays the following output:
' a tale of two cities --> A Tale Of Two Cities
' gROWL to the rescue --> Growl To The Rescue
' inside the US government --> Inside The US Government
' sports and MLB baseball --> Sports And MLB Baseball
' The Return of Sherlock Holmes --> The Return Of Sherlock Holmes
' UNICEF and children --> UNICEF And Children

Recuerde que, aunque tiene en cuenta la referencia cultural, el método TextInfo.ToTitleCase no proporciona reglas
de mayúsculas y minúsculas lingüísticamente correctas. En el ejemplo anterior, el método convierte "a tale of two
cities" en "A Tale Of Two Cities". Sin embargo, el uso lingüísticamente correcto de las mayúsculas y minúsculas de
título para la referencia cultural en-US es "A Tale of Two Cities".

Vea también
Operaciones básicas de cadenas
Realizar operaciones de cadenas que no distinguen entre referencias culturales
Utilizar la clase StringBuilder en .NET
04/11/2019 • 11 minutes to read • Edit Online

El objeto String es inmutable. Cada vez que se usa uno de los métodos de la clase System.String, se crea un objeto
de cadena en la memoria, lo que requiere una nueva asignación de espacio para ese objeto. En las situaciones en
las que es necesario realizar modificaciones repetidas en una cadena, la sobrecarga asociada a la creación de un
objeto String puede ser costosa. La clase System.Text.StringBuilder se puede usar para modificar una cadena sin
crear un objeto. Por ejemplo, el uso de la clase StringBuilder puede mejorar el rendimiento al concatenar muchas
cadenas en un bucle.

Importar el espacio de nombres System.Text


La clase StringBuilder se encuentra en el espacio de nombres System.Text. Para evitar proporcionar un nombre de
tipo completo en el código, se puede importar el espacio de nombres System.Text:

using namespace System;


using namespace System::Text;

using System;
using System.Text;

Imports System.Text

Crear instancias de un objeto StringBuilder


Para crear una instancia de la clase StringBuilder, inicialice la variable con uno de los métodos de constructor
sobrecargado, como se muestra en el ejemplo siguiente.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!");

StringBuilder myStringBuilder = new StringBuilder("Hello World!");

Dim myStringBuilder As New StringBuilder("Hello World!")

Configurar la capacidad y la longitud


Aunque StringBuilder es un objeto dinámico que permite expandir el número de caracteres de la cadena que
encapsula, se puede especificar un valor para el número máximo de caracteres que puede contener. Este valor se
conoce como la capacidad del objeto y no debe confundirse con la longitud de la cadena que el objeto
StringBuilder actual contiene. Por ejemplo, puede crear una instancia de la clase StringBuilder con la cadena
"Hello", que tiene una longitud de 5, y especificar que el objeto tiene una capacidad máxima de 25. Al modificar
StringBuilder, este no reasigna el tamaño para sí mismo hasta que se alcanza la capacidad. Cuando esto sucede, el
nuevo espacio se asigna automáticamente y se duplica la capacidad. La capacidad de la clase StringBuilder se
puede especificar con uno de los constructores sobrecargados. En el ejemplo siguiente se especifica que el objeto
myStringBuilder se puede expandir hasta un máximo de 25 espacios.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!", 25);

StringBuilder myStringBuilder = new StringBuilder("Hello World!", 25);

Dim myStringBuilder As New StringBuilder("Hello World!", 25)

Además, se puede usar la propiedad de lectura y escritura Capacity para establecer la longitud máxima del objeto.
En el ejemplo siguiente se usa la propiedad Capacity para definir la longitud máxima del objeto.

myStringBuilder->Capacity = 25;

myStringBuilder.Capacity = 25;

myStringBuilder.Capacity = 25

El método EnsureCapacity se puede usar para comprobar la capacidad del objeto StringBuilder actual. Si la
capacidad es mayor que el valor transmitido, no se realiza ningún cambio, pero si es menor que este, la capacidad
actual se cambia para que coincida con el valor en cuestión.
También se puede ver o establecer la propiedad Length. Si la propiedad Length se establece en un valor mayor
que el de la propiedad Capacity, la propiedad Capacity se cambia automáticamente al mismo valor de la
propiedad Length. Si la propiedad Length se establece en un valor menor que la longitud de la cadena de
StringBuilder actual, se acorta la cadena.

Modificar la cadena StringBuilder


En la tabla siguiente se enumeran los métodos que se pueden usar para modificar el contenido de StringBuilder.

NOMBRE DEL MÉTODO USAR

StringBuilder.Append Anexa información al final del objeto StringBuilder actual.

StringBuilder.AppendFormat Reemplaza a un especificador de formato que se pasa en una


cadena con texto con formato

StringBuilder.Insert Inserta una cadena o un objeto en el índice especificado del


elemento StringBuilder actual.

StringBuilder.Remove Quita el número de caracteres especificado del objeto


StringBuilder actual.

StringBuilder.Replace Reemplaza un carácter concreto en un índice especificado.

Anexar
El método Append se puede usar para agregar texto o la representación de cadena de un objeto al final de una
cadena representada por el objeto StringBuilder actual. En el ejemplo siguiente, se inicializa StringBuilder en
"Hello World" y, después, se anexa texto al final del objeto. El espacio se asigna automáticamente según sea
necesario.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!");


myStringBuilder->Append(" What a beautiful day.");
Console::WriteLine(myStringBuilder);
// The example displays the following output:
// Hello World! What a beautiful day.

StringBuilder myStringBuilder = new StringBuilder("Hello World!");


myStringBuilder.Append(" What a beautiful day.");
Console.WriteLine(myStringBuilder);
// The example displays the following output:
// Hello World! What a beautiful day.

Dim myStringBuilder As New StringBuilder("Hello World!")


myStringBuilder.Append(" What a beautiful day.")
Console.WriteLine(myStringBuilder)
' The example displays the following output:
' Hello World! What a beautiful day.

AppendFormat
El método StringBuilder.AppendFormat agrega texto al final del objeto StringBuilder. Admite la característica de
formatos compuestos (para obtener más información, consulte Formatos compuestos) mediante la llamada a la
implementación de IFormattable del objeto u objetos a los que se va a dar formato. Por tanto, acepta las cadenas
de formato estándar para valores numéricos, de fecha y hora y de enumeración; las cadenas de formato
personalizado para valores numéricos y de fecha y hora; y las cadenas de formato definidas para los tipos
personalizados. (Para obtener información acerca del formato, consulte Aplicar formato a tipos.) Este método se
puede usar para personalizar el formato de las variables y anexar esos valores a StringBuilder. En el ejemplo
siguiente se usa el método AppendFormat para colocar un valor entero con formato de valor de divisa al final de
un objeto StringBuilder.

int MyInt = 25;


StringBuilder^ myStringBuilder = gcnew StringBuilder("Your total is ");
myStringBuilder->AppendFormat("{0:C} ", MyInt);
Console::WriteLine(myStringBuilder);
// The example displays the following output:
// Your total is $25.00

int MyInt = 25;


StringBuilder myStringBuilder = new StringBuilder("Your total is ");
myStringBuilder.AppendFormat("{0:C} ", MyInt);
Console.WriteLine(myStringBuilder);
// The example displays the following output:
// Your total is $25.00

Dim MyInt As Integer = 25


Dim myStringBuilder As New StringBuilder("Your total is ")
myStringBuilder.AppendFormat("{0:C} ", MyInt)
Console.WriteLine(myStringBuilder)
' The example displays the following output:
' Your total is $25.00

Insertar
El método Insert agrega una cadena o un objeto en una posición especificada del objeto StringBuilder actual. En el
ejemplo siguiente se usa este método para insertar una palabra en la sexta posición de un objeto StringBuilder.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!");


myStringBuilder->Insert(6,"Beautiful ");
Console::WriteLine(myStringBuilder);
// The example displays the following output:
// Hello Beautiful World!

StringBuilder myStringBuilder = new StringBuilder("Hello World!");


myStringBuilder.Insert(6,"Beautiful ");
Console.WriteLine(myStringBuilder);
// The example displays the following output:
// Hello Beautiful World!

Dim myStringBuilder As New StringBuilder("Hello World!")


myStringBuilder.Insert(6, "Beautiful ")
Console.WriteLine(myStringBuilder)
' The example displays the following output:
' Hello Beautiful World!

Quitar
El método Remove se puede usar para quitar un número de caracteres especificado del objeto StringBuilder, a
partir de un índice de base cero definido. En el ejemplo siguiente se usa el método Remove para acortar un objeto
StringBuilder.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!");


myStringBuilder->Remove(5,7);
Console::WriteLine(myStringBuilder);
// The example displays the following output:
// Hello

StringBuilder myStringBuilder = new StringBuilder("Hello World!");


myStringBuilder.Remove(5,7);
Console.WriteLine(myStringBuilder);
// The example displays the following output:
// Hello

Dim myStringBuilder As New StringBuilder("Hello World!")


myStringBuilder.Remove(5, 7)
Console.WriteLine(myStringBuilder)
' The example displays the following output:
' Hello

Sustituya
El método Replace se puede usar para reemplazar caracteres del objeto StringBuilder por otro carácter
especificado. En el ejemplo siguiente se usa el método Replace para buscar todas las instancias del carácter de
signo de exclamación (!) y reemplazarlas por el carácter de signo de interrogación (?) en un objeto StringBuilder.

StringBuilder^ myStringBuilder = gcnew StringBuilder("Hello World!");


myStringBuilder->Replace('!', '?');
Console::WriteLine(myStringBuilder);
// The example displays the following output:
// Hello World?
StringBuilder myStringBuilder = new StringBuilder("Hello World!");
myStringBuilder.Replace('!', '?');
Console.WriteLine(myStringBuilder);
// The example displays the following output:
// Hello World?

Dim myStringBuilder As New StringBuilder("Hello World!")


myStringBuilder.Replace("!"c, "?"c)
Console.WriteLine(myStringBuilder)
' The example displays the following output:
' Hello World?

Convertir un objeto StringBuilder en String


Debe convertir primero el objeto StringBuilder en un objeto String para poder pasar la cadena representada por el
objeto StringBuilder a un método con un parámetro String o mostrarla en la interfaz de usuario. Para hacer esta
conversión, llame al método StringBuilder.ToString. En el ejemplo siguiente se llama a varios métodos de
StringBuilder y después se llama al método StringBuilder.ToString() para mostrar la cadena.

using System;
using System.Text;

public class Example


{
public static void Main()
{
StringBuilder sb = new StringBuilder();
bool flag = true;
string[] spellings = { "recieve", "receeve", "receive" };
sb.AppendFormat("Which of the following spellings is {0}:", flag);
sb.AppendLine();
for (int ctr = 0; ctr <= spellings.GetUpperBound(0); ctr++) {
sb.AppendFormat(" {0}. {1}", ctr, spellings[ctr]);
sb.AppendLine();
}
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
}
// The example displays the following output:
// Which of the following spellings is True:
// 0. recieve
// 1. receeve
// 2. receive
Imports System.Text

Module Example
Public Sub Main()
Dim sb As New StringBuilder()
Dim flag As Boolean = True
Dim spellings() As String = { "recieve", "receeve", "receive" }
sb.AppendFormat("Which of the following spellings is {0}:", flag)
sb.AppendLine()
For ctr As Integer = 0 To spellings.GetUpperBound(0)
sb.AppendFormat(" {0}. {1}", ctr, spellings(ctr))
sb.AppendLine()
Next
sb.AppendLine()
Console.WriteLine(sb.ToString())
End Sub
End Module
' The example displays the following output:
' Which of the following spellings is True:
' 0. recieve
' 1. receeve
' 2. receive

Vea también
System.Text.StringBuilder
Operaciones básicas de cadenas
Aplicación de formato a tipos
Procedimiento para realizar manipulaciones de
cadena básicas en .NET
13/01/2020 • 5 minutes to read • Edit Online

En el ejemplo siguiente, se usan algunos de los métodos descritos en los temas de Operaciones básicas de cadenas
para construir una clase que realice manipulaciones de cadena de una manera que podría encontrarse en una
aplicación real. La clase MailToData almacena el nombre y dirección de los individuos en propiedades distintas y
proporciona una forma de combinar los campos City , State y Zip en una única cadena para mostrar al usuario.
Además, la clase permite al usuario que escriba la información sobre la ciudad, estado y código postal como una
sola cadena; de forma automática, la aplicación analiza la cadena única y escribe la información adecuada en la
propiedad correspondiente.
Para simplificar, en este ejemplo se usa una aplicación de consola con una interfaz de línea de comandos.

Ejemplo
using System;

class MainClass
{
static void Main()
{
MailToData MyData = new MailToData();

Console.Write("Enter Your Name: ");


MyData.Name = Console.ReadLine();
Console.Write("Enter Your Address: ");
MyData.Address = Console.ReadLine();
Console.Write("Enter Your City, State, and ZIP Code separated by spaces: ");
MyData.CityStateZip = Console.ReadLine();
Console.WriteLine();

if (MyData.Validated) {
Console.WriteLine("Name: {0}", MyData.Name);
Console.WriteLine("Address: {0}", MyData.Address);
Console.WriteLine("City: {0}", MyData.City);
Console.WriteLine("State: {0}", MyData.State);
Console.WriteLine("Zip: {0}", MyData.Zip);

Console.WriteLine("\nThe following address will be used:");


Console.WriteLine(MyData.Address);
Console.WriteLine(MyData.CityStateZip);
}
}
}

public class MailToData


{
string name = "";
string address = "";
string citystatezip = "";
string city = "";
string state = "";
string zip = "";
bool parseSucceeded = false;

public string Name


{
{
get{return name;}
set{name = value;}
}

public string Address


{
get{return address;}
set{address = value;}
}

public string CityStateZip


{
get {
return String.Format("{0}, {1} {2}", city, state, zip);
}
set {
citystatezip = value.Trim();
ParseCityStateZip();
}
}

public string City


{
get{return city;}
set{city = value;}
}

public string State


{
get{return state;}
set{state = value;}
}

public string Zip


{
get{return zip;}
set{zip = value;}
}

public bool Validated


{
get { return parseSucceeded; }
}

private void ParseCityStateZip()


{
string msg = "";
const string msgEnd = "\nYou must enter spaces between city, state, and zip code.\n";

// Throw a FormatException if the user did not enter the necessary spaces
// between elements.
try
{
// City may consist of multiple words, so we'll have to parse the
// string from right to left starting with the zip code.
int zipIndex = citystatezip.LastIndexOf(" ");
if (zipIndex == -1) {
msg = "\nCannot identify a zip code." + msgEnd;
throw new FormatException(msg);
}
zip = citystatezip.Substring(zipIndex + 1);

int stateIndex = citystatezip.LastIndexOf(" ", zipIndex - 1);


if (stateIndex == -1) {
msg = "\nCannot identify a state." + msgEnd;
throw new FormatException(msg);
}
state = citystatezip.Substring(stateIndex + 1, zipIndex - stateIndex - 1);
state = state.ToUpper();
state = state.ToUpper();

city = citystatezip.Substring(0, stateIndex);


if (city.Length == 0) {
msg = "\nCannot identify a city." + msgEnd;
throw new FormatException(msg);
}
parseSucceeded = true;
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
}

private string ReturnCityStateZip()


{
// Make state uppercase.
state = state.ToUpper();

// Put the value of city, state, and zip together in the proper manner.
string MyCityStateZip = String.Concat(city, ", ", state, " ", zip);

return MyCityStateZip;
}
}

Class MainClass
Public Shared Sub Main()
Dim MyData As New MailToData()

Console.Write("Enter Your Name: ")


MyData.Name = Console.ReadLine()
Console.Write("Enter Your Address: ")
MyData.Address = Console.ReadLine()
Console.Write("Enter Your City, State, and ZIP Code separated by spaces: ")
MyData.CityStateZip = Console.ReadLine()
Console.WriteLine()

If MyData.Validated Then
Console.WriteLine("Name: {0}", MyData.Name)
Console.WriteLine("Address: {0}", MyData.Address)
Console.WriteLine("City: {0}", MyData.City)
Console.WriteLine("State: {0}", MyData.State)
Console.WriteLine("ZIP Code: {0}", MyData.Zip)

Console.WriteLine("The following address will be used:")


Console.WriteLine(MyData.Address)
Console.WriteLine(MyData.CityStateZip)
End If
End Sub
End Class

Public Class MailToData


Private strName As String = ""
Private strAddress As String = ""
Private strCityStateZip As String = ""
Private strCity As String = ""
Private strState As String = ""
Private strZip As String = ""
Private parseSucceeded As Boolean = False

Public Property Name() As String


Get
Return strName
End Get
Set
strName = value
strName = value
End Set
End Property

Public Property Address() As String


Get
Return strAddress
End Get
Set
strAddress = value
End Set
End Property

Public Property CityStateZip() As String


Get
Return String.Format("{0}, {1} {2}", strCity, strState, strZip)
End Get
Set
strCityStateZip = value.Trim()
ParseCityStateZip()
End Set
End Property

Public Property City() As String


Get
Return strCity
End Get
Set
strCity = value
End Set
End Property

Public Property State() As String


Get
Return strState
End Get
Set
strState = value
End Set
End Property

Public Property Zip() As String


Get
Return strZip
End Get
Set
strZip = value
End Set
End Property

Public ReadOnly Property Validated As Boolean


Get
Return parseSucceeded
End Get
End Property

Private Sub ParseCityStateZip()


Dim msg As String = Nothing
Const msgEnd As String = vbCrLf +
"You must enter spaces between city, state, and zip code." +
vbCrLf

' Throw a FormatException if the user did not enter the necessary spaces
' between elements.
Try
' City may consist of multiple words, so we'll have to parse the
' string from right to left starting with the zip code.
Dim zipIndex As Integer = strCityStateZip.LastIndexOf(" ")
If zipIndex = -1 Then
msg = vbCrLf + "Cannot identify a zip code." + msgEnd
msg = vbCrLf + "Cannot identify a zip code." + msgEnd
Throw New FormatException(msg)
End If
strZip = strCityStateZip.Substring(zipIndex + 1)

Dim stateIndex As Integer = strCityStateZip.LastIndexOf(" ", zipIndex - 1)


If stateIndex = -1 Then
msg = vbCrLf + "Cannot identify a state." + msgEnd
Throw New FormatException(msg)
End If
strState = strCityStateZip.Substring(stateIndex + 1, zipIndex - stateIndex - 1)
strState = strState.ToUpper()

strCity = strCityStateZip.Substring(0, stateIndex)


If strCity.Length = 0 Then
msg = vbCrLf + "Cannot identify a city." + msgEnd
Throw New FormatException(msg)
End If
parseSucceeded = True
Catch ex As FormatException
Console.WriteLine(ex.Message)
End Try
End Sub
End Class

Cuando se ejecuta el código anterior, se le pide al usuario que escriba su nombre y dirección. La aplicación coloca
la información en las propiedades adecuadas y muestra la información al usuario, creando una única cadena que
muestra la información sobre la ciudad, el estado y el código postal.

Vea también
Operaciones básicas de cadenas
Expresiones regulares de .NET
04/11/2019 • 16 minutes to read • Edit Online

Las expresiones regulares proporcionan un método eficaz y flexible para procesar texto. La notación extensiva de
búsqueda de patrones coincidentes de las expresiones regulares permite analizar rápidamente grandes
cantidades de texto para buscar patrones de caracteres específicos; para validar un texto con el fin de asegurar
que se corresponde con un patrón predefinido (por ejemplo, una dirección de correo electrónico); para extraer,
editar, reemplazar o eliminar subcadenas de texto; y para agregar las cadenas extraídas a una colección con el fin
de generar un informe. Para muchas aplicaciones que usan cadenas o analizan grandes bloques de texto, las
expresiones regulares son una herramienta indispensable.

Funcionamiento de las expresiones regulares


El eje del procesamiento de texto mediante expresiones regulares es el motor de expresiones regulares, que
viene representado por el objeto System.Text.RegularExpressions.Regex en .NET. Como mínimo, el
procesamiento de texto mediante expresiones regulares necesita que el motor de expresiones regulares
disponga de los dos elementos de información siguientes:
El patrón de expresión regular que se debe identificar en el texto.
En .NET, los patrones de expresiones regulares se definen mediante una sintaxis o un lenguaje especial,
que es compatible con las expresiones regulares de Perl 5 y agrega algunas características adicionales,
como búsquedas de coincidencias de derecha a izquierda. Para obtener más información, consulte
Lenguaje de expresiones regulares: Referencia rápida.
El texto que se debe analizar para el patrón de expresión regular.
Los métodos de la clase Regex permiten realizar las operaciones siguientes:
Determinar si el patrón de expresión regular se produce en el texto de entrada llamando al método
Regex.IsMatch. Para obtener un ejemplo en donde se utiliza el método IsMatch para validar texto, vea
Procedimiento: Comprobación de que las cadenas están en un formato de correo electrónico válido.
Recuperar una o todas las apariciones del texto que coincide con el patrón de expresión regular llamando
al método Regex.Match o Regex.Matches. El primer método devuelve un objeto
System.Text.RegularExpressions.Match que proporciona información sobre el texto coincidente. El
segundo método devuelve un objeto MatchCollection que contiene un objeto
System.Text.RegularExpressions.Match por cada coincidencia encontrada en el texto analizado.
Reemplazar el texto que coincide con el patrón de expresión regular llamando al método Regex.Replace.
Para obtener ejemplos en donde se utiliza el método Replace para cambiar formatos de fecha y quitar
caracteres no válidos de una cadena, vea Procedimiento: Eliminación de caracteres no válidos de una
cadena y Ejemplo: Cambio de formatos de fecha.
Para obtener información general acerca del modelo de objetos de expresiones regulares, consulte El modelo de
objetos de expresión regular.
Para obtener más información acerca del lenguaje de expresiones regulares, consulte Lenguaje de expresiones
regulares - Referencia rápida o descargue e imprima uno de estos folletos:
Referencia rápida en formato Word (.docx)
Referencia rápida en formato PDF (.pdf)
Ejemplos de expresiones regulares
La clase String incluye varios métodos de búsqueda y reemplazo de cadenas que puede usar cuando desee
buscar cadenas literales en una cadena mayor. Las expresiones regulares son muy útiles cuando se desea buscar
una de varias subcadenas en una cadena mayor o cuando se desea identificar patrones en una cadena, como se
muestra en los ejemplos siguientes.
Ejemplo 1: Reemplazo de subcadenas
Suponga que una lista de distribución de correo contiene nombres que a veces incluyen un tratamiento (Sr., Sra.
o Srta.) junto con un nombre y un apellido. Si no desea incluir los tratamientos al generar las etiquetas de los
sobres a partir de la lista, puede usar una expresión regular para quitarlos, como se muestra en el ejemplo
siguiente.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "(Mr\\.? |Mrs\\.? |Miss |Ms\\.? )";
string[] names = { "Mr. Henry Hunt", "Ms. Sara Samuels",
"Abraham Adams", "Ms. Nicole Norris" };
foreach (string name in names)
Console.WriteLine(Regex.Replace(name, pattern, String.Empty));
}
}
// The example displays the following output:
// Henry Hunt
// Sara Samuels
// Abraham Adams
// Nicole Norris

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(Mr\.? |Mrs\.? |Miss |Ms\.? )"
Dim names() As String = { "Mr. Henry Hunt", "Ms. Sara Samuels", _
"Abraham Adams", "Ms. Nicole Norris" }
For Each name As String In names
Console.WriteLine(Regex.Replace(name, pattern, String.Empty))
Next
End Sub
End Module
' The example displays the following output:
' Henry Hunt
' Sara Samuels
' Abraham Adams
' Nicole Norris

El patrón de expresión regular (Mr\.? |Mrs\.? |Miss |Ms\.? ) busca coincidencias con cualquier aparición de
"Mr ", "Mr. ", "Mrs ", "Mrs. ", "Miss ", "Ms " o "Ms. ". La llamada al método Regex.Replace reemplaza la cadena
coincidente con String.Empty; es decir, la quita de la cadena original.
Ejemplo 2: Identificación de palabras duplicadas
Duplicar palabras accidentalmente es un error frecuente que cometen los escritores. Se puede usar una
expresión regular para identificar palabras duplicadas, como se muestra en el ejemplo siguiente.
using System;
using System.Text.RegularExpressions;

public class Class1


{
public static void Main()
{
string pattern = @"\b(\w+?)\s\1\b";
string input = "This this is a nice day. What about this? This tastes good. I saw a a dog.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("{0} (duplicates '{1}') at position {2}",
match.Value, match.Groups[1].Value, match.Index);
}
}
// The example displays the following output:
// This this (duplicates 'This') at position 0
// a a (duplicates 'a') at position 66

Imports System.Text.RegularExpressions

Module modMain
Public Sub Main()
Dim pattern As String = "\b(\w+?)\s\1\b"
Dim input As String = "This this is a nice day. What about this? This tastes good. I saw a a dog."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("{0} (duplicates '{1}') at position {2}", _
match.Value, match.Groups(1).Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' This this (duplicates 'This') at position 0
' a a (duplicates 'a') at position 66

El patrón de expresión regular \b(\w+?)\s\1\b se puede interpretar de la manera siguiente:

\b Empieza en un límite de palabras.

(\w+?) Coincide con uno o más caracteres de palabra, pero con el


menor número de caracteres posible. Juntos, forman un
grupo al que se puede hacer referencia como \1 .

\s Coincide con un carácter de espacio en blanco.

\1 Coincide con la subcadena que es igual al grupo denominado


\1 .

\b Coincide con un límite de palabras.

Se llama al método Regex.Matches con las opciones de expresiones regulares establecidas en


RegexOptions.IgnoreCase. Por tanto, la operación de coincidencia no distingue mayúsculas de minúsculas y el
ejemplo identifica la subcadena "Esto esto" como una duplicación.
Observe que la cadena de entrada incluye la subcadena "this? This". Sin embargo, debido al signo de puntuación
intermedio, no se identifica como una duplicación.
Ejemplo 3: Creación dinámica de una expresión regular de referencia cultural
En el ejemplo siguiente se muestra la eficacia de las expresiones regulares, además de la flexibilidad que ofrecen
las características de globalización de .NET. Se usa el objeto NumberFormatInfo para determinar el formato de
los valores de divisa en la referencia cultural actual del sistema. A continuación, se usa dicha información para
construir dinámicamente una expresión regular que extrae los valores de divisa del texto. Para cada coincidencia,
se extrae el subgrupo que solo contiene la cadena numérica, se convierte el subgrupo en un valor Decimal y se
calcula un total acumulativo.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
// Define text to be parsed.
string input = "Office expenses on 2/13/2008:\n" +
"Paper (500 sheets) $3.95\n" +
"Pencils (box of 10) $1.00\n" +
"Pens (box of 10) $4.49\n" +
"Erasers $2.19\n" +
"Ink jet printer $69.95\n\n" +
"Total Expenses $ 81.58\n";

// Get current culture's NumberFormatInfo object.


NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
// Assign needed property values to variables.
string currencySymbol = nfi.CurrencySymbol;
bool symbolPrecedesIfPositive = nfi.CurrencyPositivePattern % 2 == 0;
string groupSeparator = nfi.CurrencyGroupSeparator;
string decimalSeparator = nfi.CurrencyDecimalSeparator;

// Form regular expression pattern.


string pattern = Regex.Escape( symbolPrecedesIfPositive ? currencySymbol : "") +
@"\s*[-+]?" + "([0-9]{0,3}(" + groupSeparator + "[0-9]{3})*(" +
Regex.Escape(decimalSeparator) + "[0-9]+)?)" +
(! symbolPrecedesIfPositive ? currencySymbol : "");
Console.WriteLine( "The regular expression pattern is:");
Console.WriteLine(" " + pattern);

// Get text that matches regular expression pattern.


MatchCollection matches = Regex.Matches(input, pattern,
RegexOptions.IgnorePatternWhitespace);
Console.WriteLine("Found {0} matches.", matches.Count);

// Get numeric string, convert it to a value, and add it to List object.


List<decimal> expenses = new List<Decimal>();

foreach (Match match in matches)


expenses.Add(Decimal.Parse(match.Groups[1].Value));

// Determine whether total is present and if present, whether it is correct.


decimal total = 0;
foreach (decimal value in expenses)
total += value;

if (total / 2 == expenses[expenses.Count - 1])


Console.WriteLine("The expenses total {0:C2}.", expenses[expenses.Count - 1]);
else
Console.WriteLine("The expenses total {0:C2}.", total);
}
}
// The example displays the following output:
// The regular expression pattern is:
// \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?)
// Found 6 matches.
// The expenses total $81.58.
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Module Example


Public Sub Main()
' Define text to be parsed.
Dim input As String = "Office expenses on 2/13/2008:" + vbCrLf + _
"Paper (500 sheets) $3.95" + vbCrLf + _
"Pencils (box of 10) $1.00" + vbCrLf + _
"Pens (box of 10) $4.49" + vbCrLf + _
"Erasers $2.19" + vbCrLf + _
"Ink jet printer $69.95" + vbCrLf + vbCrLf + _
"Total Expenses $ 81.58" + vbCrLf
' Get current culture's NumberFormatInfo object.
Dim nfi As NumberFormatInfo = CultureInfo.CurrentCulture.NumberFormat
' Assign needed property values to variables.
Dim currencySymbol As String = nfi.CurrencySymbol
Dim symbolPrecedesIfPositive As Boolean = CBool(nfi.CurrencyPositivePattern Mod 2 = 0)
Dim groupSeparator As String = nfi.CurrencyGroupSeparator
Dim decimalSeparator As String = nfi.CurrencyDecimalSeparator

' Form regular expression pattern.


Dim pattern As String = Regex.Escape(CStr(IIf(symbolPrecedesIfPositive, currencySymbol, ""))) + _
"\s*[-+]?" + "([0-9]{0,3}(" + groupSeparator + "[0-9]{3})*(" + _
Regex.Escape(decimalSeparator) + "[0-9]+)?)" + _
CStr(IIf(Not symbolPrecedesIfPositive, currencySymbol, ""))
Console.WriteLine("The regular expression pattern is: ")
Console.WriteLine(" " + pattern)

' Get text that matches regular expression pattern.


Dim matches As MatchCollection = Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace)
Console.WriteLine("Found {0} matches. ", matches.Count)

' Get numeric string, convert it to a value, and add it to List object.
Dim expenses As New List(Of Decimal)

For Each match As Match In matches


expenses.Add(Decimal.Parse(match.Groups.Item(1).Value))
Next

' Determine whether total is present and if present, whether it is correct.


Dim total As Decimal
For Each value As Decimal In expenses
total += value
Next

If total / 2 = expenses(expenses.Count - 1) Then


Console.WriteLine("The expenses total {0:C2}.", expenses(expenses.Count - 1))
Else
Console.WriteLine("The expenses total {0:C2}.", total)
End If
End Sub
End Module
' The example displays the following output:
' The regular expression pattern is:
' \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?)
' Found 6 matches.
' The expenses total $81.58.

En un equipo cuya referencia cultural actual sea Inglés - Estados Unidos (en-US ), el ejemplo crea dinámicamente
la expresión regular \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?) . Este patrón de expresión regular se puede
interpretar de la manera siguiente:
\$ Busque una sola aparición del símbolo de dólar ( $ ) en la
cadena de entrada. La cadena del patrón de expresión regular
incluye una barra diagonal inversa para indicar que el símbolo
de dólar debe interpretarse literalmente en lugar de
interpretarse como un delimitador de la expresión regular. (Si
solo apareciese el símbolo $ , esto indicaría que el motor de
expresión regular debe intentar comenzar su búsqueda de
coincidencias al final de una cadena). Para asegurarse de que
el símbolo de divisa de la referencia cultural actual no se
interprete erróneamente como un símbolo de expresión
regular, en el ejemplo se llama al método Regex.Escape como
escape de caracteres.

\s* Buscar cero o más apariciones de un carácter de espacio en


blanco.

[-+]? Buscar cero o una aparición de un signo positivo o un signo


negativo.

([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?) Los paréntesis externos alrededor de esta expresión la


definen como un grupo de captura o una subexpresión. Si se
encuentra una coincidencia, la información sobre esta parte
de la cadena coincidente se puede recuperar del segundo
objeto Group en el objeto GroupCollection devuelto por la
propiedad Match.Groups. (El primer elemento de la colección
representa la coincidencia completa.)

[0-9]{0,3} Buscar de cero a tres apariciones de los dígitos decimales


comprendidos entre 0 y 9.

(,[0-9]{3})* Buscar cero o más apariciones de un separador de grupos


seguido de tres dígitos decimales.

\. Buscar una única aparición del separador decimal.

[0-9]+ Buscar uno o más dígitos decimales.

(\.[0-9]+)? Buscar cero o una aparición del separador decimal seguido de


al menos un dígito decimal.

Si se encuentra cada uno de estos subpatrones en la cadena de entrada, la búsqueda de coincidencias se realiza
correctamente y se agrega al objeto Match un objeto MatchCollection que contiene información sobre la
coincidencia.

Temas relacionados
TITLE DESCRIPCIÓN

Lenguaje de expresiones regulares: referencia rápida Ofrece información sobre el conjunto de caracteres,
operadores y construcciones que se pueden utilizar para
definir expresiones regulares.

Modelo de objetos de expresión regular Proporciona información y ejemplos de código que muestran
cómo usar las clases de expresiones regulares.
TITLE DESCRIPCIÓN

Detalles del comportamiento de expresiones regulares Proporciona información sobre las funcionalidades y el
comportamiento de las expresiones regulares de .NET.

Ejemplos de expresiones regulares Proporciona ejemplos de código que muestran los usos
habituales de las expresiones regulares.

Referencia
System.Text.RegularExpressions
System.Text.RegularExpressions.Regex
Expresiones regulares: referencia rápida (descarga en formato Word)
Expresiones regulares: referencia rápida (descarga en formato PDF )
Lenguaje de expresiones regulares - Referencia
rápida
25/11/2019 • 22 minutes to read • Edit Online

Una expresión regular es un modelo con el que el motor de expresiones regulares intenta buscar una
coincidencia en el texto de entrada. Un modelo consta de uno o más literales de carácter, operadores o
estructuras. Para obtener una breve introducción, consulte Expresiones regulares de .NET.
Cada sección de esta referencia rápida enumera una categoría determinada de caracteres, operadores y
construcciones que puede usar para definir expresiones regulares.
Esta información también se proporciona en dos formatos que se pueden descargar e imprimir para facilitar su
consulta:
Descargar en formato Word (.docx)
Descarga en formato PDF (.pdf)

Escapes de carácter
El carácter de barra diagonal inversa (\) en una expresión regular indica que el carácter que le sigue es un
carácter especial (como se muestra en la tabla siguiente) o que se debe interpretar literalmente. Para más
información, consulte Escapes de carácter.

CARÁCTER DE ESCAPE DESCRIPCIÓN MODELO COINCIDENCIAS

\a Coincide con un carácter de \a "\u0007" en


campana, \u0007. "Error!" + '\u0007'

\b En una clase de caracteres, [\b]{3,} "\b\b\b\b" en


coincide con un retroceso, "\b\b\b\b"
\u0008.

\t Coincide con una (\w+)\t "item1\t" , "item2\t"


tabulación, \u0009. en "item1\titem2\t"

\r Coincide con un retorno de \r\n(\w+) "\r\nThese" en


carro, \u000D. ( \r no es "\r\nThese are\ntwo
equivalente al carácter de lines."
nueva línea, \n ).

\v Coincide con una tabulación [\v]{2,} "\v\v\v" en "\v\v\v"


vertical, \u000B.

\f Coincide con un avance de [\f]{2,} "\f\f\f" en "\f\f\f"


página, \u000C.

\n Coincide con una nueva \r\n(\w+) "\r\nThese" en


línea, \u000A. "\r\nThese are\ntwo
lines."
CARÁCTER DE ESCAPE DESCRIPCIÓN MODELO COINCIDENCIAS

\e Coincide con un escape, \e "\x001B" en "\x001B"


\u001B.

\ nnn Usa la representación octal \w\040\w "a b" , "c d" en


para especificar un carácter "a bc d"
(nnn consta de dos o tres
dígitos).

\x nn Usa la representación \w\x20\w "a b" , "c d" en


hexadecimal para especificar "a bc d"
un carácter (nn consta de
exactamente dos dígitos).

\c X Coincide con el carácter de \cC "\x0003" en "\x0003"


control ASCII especificado (Ctrl-C)
\c x por X o x, donde X o x es la
letra del carácter de control.

\u nnnn Coincide con un carácter \w\u0020\w "a b" , "c d" en


Unicode usando la "a bc d"
representación hexadecimal
(exactamente cuatro dígitos,
según representa nnnn).

\ Cuando va seguido de un \d+[\+-x\*]\d+ "2+2" y "3*9" en


carácter que no se reconoce "(2+2) * 3*9"
como un carácter de escape
en esta y otras tablas de
este tema, coincide con ese
carácter. Por ejemplo, \*
es igual que \x2A y \. es
igual que \x2E . Esto
permite que el motor de
expresiones regulares
elimine la ambigüedad de
los elementos del lenguaje
(como * o ?) y los literales
de carácter (representados
por \* o \? ).

Clases de caracteres
Una clase de caracteres coincide con cualquiera de un juego de caracteres. Las clases de caracteres incluyen los
elementos del lenguaje enumerados en la tabla siguiente. Para más información, consulte Clases de caracteres.

CLASE DE CARÁCTER DESCRIPCIÓN MODELO COINCIDENCIAS

[ grupo_caracteres ] Coincide con cualquier [ae] "a" en "gray"


carácter individual de
grupo_caracteres. De forma "a" , "e" en "lane"
predeterminada, la
coincidencia distingue entre
mayúsculas y minúsculas.
CLASE DE CARÁCTER DESCRIPCIÓN MODELO COINCIDENCIAS

[^ grupo_caracteres ] Negativo: coincide con [^aei] "r" , "g" , "n" en


cualquier carácter individual "reign"
que no esté en
grupo_caracteres. De forma
predeterminada, los
caracteres de
grupo_caracteres
distinguen entre
mayúsculas y minúsculas.

[ primero - último ] Rango de caracteres: [A-Z] "A" , "B" en "AB123"


coincide con cualquier
carácter individual en el
intervalo de primero a
último.

. Carácter comodín: coincide a.e "ave" en "nave"


con cualquier carácter
excepto con \n. "ate" en "water"

Para coincidir con un


carácter de punto literal (. o
\u002E ), debe anteponerle
el carácter de escape ( \. ).

\p{ nombre } Coincide con cualquier \p{Lu} "C" , "L" en


carácter individual que "City Lights"
pertenezca a la categoría \p{IsCyrillic}
general Unicode o al bloque "Д" , "Ж" en "ДЖem"
con nombre especificado
por nombre.

\P{ nombre } Coincide con cualquier \P{Lu} "i" , "t" , "y" en


carácter individual que no "City"
pertenezca a la categoría \P{IsCyrillic}
general Unicode o al bloque "e" , "m" en "ДЖem"
con nombre especificado
por nombre.

\w Coincide con cualquier \w "I" , "D" , "A" , "1" ,


carácter de una palabra. "3" en "ID A1.3"

\W Coincide con cualquier \W " " , "." en "ID A1.3"


carácter que no pertenezca
a una palabra.

\s Coincide con cualquier \w\s "D " en "ID A1.3"


carácter que sea un espacio
en blanco.

\S Coincide con cualquier \s\S " _" en "int __ctr"


carácter que no sea un
espacio en blanco.

\d Coincide con cualquier \d "4" en "4 = IV"


dígito decimal.
CLASE DE CARÁCTER DESCRIPCIÓN MODELO COINCIDENCIAS

\D Coincide con cualquier \D " " , "=" , " " , "I" ,


carácter que no sea un "V" en "4 = IV"
dígito decimal.

Delimitadores
Los delimitadores, o aserciones atómicas de ancho cero, hacen que una coincidencia tenga éxito o no
dependiendo de la posición actual en la cadena, pero no hacen que el motor avance por la cadena ni consuma
caracteres. Los metacaracteres enumerados en la tabla siguiente son delimitadores. Para obtener más
información, consulte Delimitadores.

ASERCIÓN DESCRIPCIÓN MODELO COINCIDENCIAS

^ De forma predeterminada, ^\d{3} "901" en "901-333-"


la coincidencia debe
comenzar al principio de la
cadena; en el modo
multilínea, debe comenzar
al principio de la línea.

$ De forma predeterminada, -\d{3}$ "-333" en "-901-333"


la coincidencia se debe
producir al final de la
cadena o antes de \n al
final de la cadena; en el
modo multilínea, se debe
producir antes del final de la
línea o antes de \n al final
de la línea.

\A La coincidencia se debe \A\d{3} "901" en "901-333-"


producir al principio de la
cadena.

\Z La coincidencia se debe -\d{3}\Z "-333" en "-901-333"


producir al final de la
cadena o antes de \n al
final de la cadena.

\z La coincidencia se debe -\d{3}\z "-333" en "-901-333"


producir al final de la
cadena.

\G La coincidencia se debe \G\(\d\) "(1)" , "(3)" , "(5)"


producir en el punto en el en "(1)(3)(5)[7](9)"
que finalizó la coincidencia
anterior.

\b La coincidencia se debe \b\w+\s\w+\b "them theme" ,


producir en un límite entre "them them" en
un carácter \w "them theme them them"
(alfanumérico) y un carácter
\W (no alfanumérico).
ASERCIÓN DESCRIPCIÓN MODELO COINCIDENCIAS

\B La coincidencia no se debe \Bend\w*\b "ends" , "ender" en


producir en un límite \b . "end sends endure
lender"

Construcciones de agrupamiento
Las construcciones de agrupamiento definen subexpresiones de una expresión regular y, normalmente,
capturan subcadenas de una cadena de entrada. Las construcciones de agrupamiento incluyen los elementos
del lenguaje enumerados en la tabla siguiente. Para obtener más información, consulte Construcciones de
agrupamiento.

CONSTRUCCIÓN DE
AGRUPAMIENTO DESCRIPCIÓN MODELO COINCIDENCIAS

( subexpresión ) Captura la subexpresión (\w)\1 "ee" en "deep"


coincidente y le asigna un
número ordinal basado en
uno.

(?< nombre > Captura la subexpresión (? "ee" en "deep"


subexpresión ) coincidente en un grupo <double>\w)\k<double>
con nombre.

(?<nombre1 - Define una definición de (((?'Open'\()[^\ "((1-3)*(3-1))" en


nombre2 > subexpresión grupo de equilibrio. Para (\)]*)+((?'Close- "3+2^((1-3)*(3-1))"
Open'\))[^\(\)]*)+)*(?
) obtener más información, (Open)(?!))$
consulte la sección
"Definiciones de grupos de
equilibrio" en
Construcciones de
agrupamiento.

(?: subexpresión ) Define un grupo sin Write(?:Line)? "WriteLine" en


captura. "Console.WriteLine()"

"Write" en
"Console.Write(value)"

(?imnsx-imnsx: Aplica o deshabilita las A\d{2}(?i:\w+)\b "A12xl" , "A12XL" en


subexpresión ) opciones especificadas "A12xl A12XL a12xl"
dentro de subexpresión.
Para obtener más
información, consulte
Opciones de expresiones
regulares.

(?= subexpresión ) Aserción de búsqueda \w+(?=\.) "is" , "ran" y "out"


anticipada positiva de en
ancho cero. "He is. The dog ran.
The sun is out."

(?! subexpresión ) Aserción de búsqueda \b(?!un)\w+\b "sure" , "used" en


anticipada negativa de "unsure sure unity
ancho cero. used"
CONSTRUCCIÓN DE
AGRUPAMIENTO DESCRIPCIÓN MODELO COINCIDENCIAS

(?<= subexpresión ) Aserción de búsqueda (?<=19)\d{2}\b "99" , "50" , "05" en


tardía positiva de ancho "1851 1999 1950 1905
cero. 2003"

(?<! subexpresión ) Aserción de búsqueda (?<!19)\d{2}\b "51" , "03" en


tardía negativa de ancho "1851 1999 1950 1905
cero. 2003"

(?> subexpresión ) Subexpresión sin retroceso [13579](?>A+B+) "1ABB" , "3ABB" y


(o "expansiva"). "5AB" en
"1ABB 3ABBC 5AB 5AC"

Cuantificadores
Un cuantificador especifica cuántas instancias del elemento anterior (que puede ser un carácter, un grupo o una
clase de caracteres) debe haber en la cadena de entrada para que se encuentre una coincidencia. Los
cuantificadores incluyen los elementos del lenguaje enumerados en la tabla siguiente. Para obtener más
información, consulte Cuantificadores.

CUANTIFICADOR DESCRIPCIÓN MODELO COINCIDENCIAS

* Coincide con el elemento \d*\.\d ".0" , "19.9" , "219.9"


anterior cero o más veces.

+ Coincide con el elemento "be+" "bee" en "been" , "be"


anterior una o más veces. en "bent"

? Coincide con el elemento "rai?n" "ran" , "rain"


anterior cero veces o una
vez.

{ n } Coincide con el elemento ",\d{3}" ",043" en "1,043.6" ,


anterior exactamente n ",876" , ",543" y
veces. ",210" en
"9,876,543,210"

{ n ,} Coincide con el elemento "\d{2,}" "166" , "29" , "1930"


anterior al menos n veces.

{ n , m } Coincide con el elemento "\d{3,5}" "166" , "17668"


anterior al menos n veces,
pero no más de m veces. "19302" en "193024"

*? Coincide con el elemento \d*?\.\d ".0" , "19.9" , "219.9"


anterior cero o más veces,
pero el menor número de
veces que sea posible.

+? Coincide con el elemento "be+?" "be" en "been" , "be"


anterior una o más veces, en "bent"
pero el menor número de
veces que sea posible.
CUANTIFICADOR DESCRIPCIÓN MODELO COINCIDENCIAS

?? Coincide con el elemento "rai??n" "ran" , "rain"


anterior cero o una vez,
pero el menor número de
veces que sea posible.

{ n }? Coincide con el elemento ",\d{3}?" ",043" en "1,043.6" ,


precedente exactamente n ",876" , ",543" y
veces. ",210" en
"9,876,543,210"

{ n ,}? Coincide con el elemento "\d{2,}?" "166" , "29" , "1930"


anterior al menos n veces,
pero el menor número de
veces posible.

{ n , m }? Coincide con el elemento "\d{3,5}?" "166" , "17668"


anterior entre n y m veces,
pero el menor número de "193" , "024" en
veces posible. "193024"

Construcciones de referencia inversa


Una referencia inversa permite identificar una subexpresión coincidente previamente más adelante en la misma
expresión regular. En la tabla siguiente se enumeran las construcciones de referencia inversa admitidas en las
expresiones regulares de .NET. Para obtener más información, consulte Construcciones de referencia inversa.

CONSTRUCCIÓN DE
REFERENCIAS INVERSAS DESCRIPCIÓN MODELO COINCIDENCIAS

\ número Referencia inversa Coincide (\w)\1 "ee" en "seek"


con el valor de una
subexpresión numerada.

\k< nombre > Referencia inversa con (?<char>\w)\k<char> "ee" en "seek"


nombre Coincide con el
valor de una expresión con
nombre.

Construcciones de alternancia
Las estructuras de alternancia modifican una expresión regular para habilitar o no la coincidencia. Estas
construcciones incluyen los elementos del lenguaje enumerados en la tabla siguiente. Para obtener más
información, consulte Construcciones de alternancia.

CONSTRUCCIONES DE
ALTERNANCIA DESCRIPCIÓN MODELO COINCIDENCIAS

| Coincide con cualquier th(e|is|at) "the" , "this" en


elemento separado por el "this is the day."
carácter de barra vertical (
| ).
CONSTRUCCIONES DE
ALTERNANCIA DESCRIPCIÓN MODELO COINCIDENCIAS

(?( expresión ) sí | Coincide con sí si el patrón (? "A10" , "910" en


no ) de expresión regular (A)A\d{2}\b|\b\d{3}\b) "A10 C103 910"
designado por expresión
coincide; de lo contrario,
coincide con la parte
opcional no. expresión se
interpreta como una
aserción de ancho cero.

(?( nombre ) sí | no Coincide con sí si nombre, (?<quoted>")?(? "Dogs.jpg " ,


) un grupo de captura con (quoted).+?"|\S+\s) "\"Yiska
nombre o numerado, tiene playing.jpg\""
una coincidencia; de lo en
contrario, coincide con la "Dogs.jpg \"Yiska
parte opcional no. playing.jpg\""

Sustituciones
Las sustituciones son elementos del lenguaje de expresiones regulares que se admiten en modelos de
reemplazo. Para obtener más información, consulte Substituciones. Los metacaracteres enumerados en la tabla
siguiente son aserciones atómicas de ancho cero.

MODELO DE CADENA DE CADENA DE


CARÁCTER DESCRIPCIÓN MODELO REEMPLAZO ENTRADA RESULTADO

$ número Sustituye la \b(\w+)(\s) $3$2$1 "one two" "two one"


subcadena que (\w+)\b
coincide con el
grupo número.

${ nombre } Sustituye la \b(? ${word2} "one two" "two one"


subcadena que <word1>\w+) ${word1}
(\s)(?
coincide con el <word2>\w+)\b
grupo con
nombre nombre.

$$ Sustituye un "$" \b(\d+)\s?USD $$$1 "103 USD" "$103"


literal.

$& Sustituye una \$?\d*\.?\d+ **$&** "$1.30" "**$1.30**"


copia de toda la
coincidencia.

$` Sustituye todo el B+ $` "AABBCC" "AAAACC"


texto de la
cadena de
entrada delante
de la
coincidencia.
MODELO DE CADENA DE CADENA DE
CARÁCTER DESCRIPCIÓN MODELO REEMPLAZO ENTRADA RESULTADO

$' Sustituye todo el B+ $' "AABBCC" "AACCCC"


texto de la
cadena de
entrada detrás
de la
coincidencia.

$+ Sustituye el B+(C+) $+ "AABBCCDD" "AACCDD"


último grupo
capturado.

$_ Sustituye toda la B+ $_ "AABBCC" "AAAABBCCCC"


cadena de
entrada.

Opciones de expresiones regulares


Puede especificar opciones que controlen cómo debe interpretar el motor de expresiones regulares un patrón
de expresión regular. Muchas de estas opciones pueden especificarse alineadas (en el patrón de expresión
regular) o como una o más constantes de RegexOptions. Esta referencia rápida solo muestra las opciones
alineadas. Para obtener más información sobre las opciones alineadas y RegexOptions, consulte el artículo
Opciones de expresiones regulares.
Puede especificar una opción alineada de dos formas:
Con la construcción miscelánea (?imnsx-imnsx) , donde el signo menos (-) delante de una opción o un
conjunto de opciones desactiva dichas opciones. Por ejemplo, (?i-mn) activa una coincidencia sin distinción
entre mayúsculas y minúsculas ( i ), desactiva el modo multilínea ( m ) y desactiva las capturas de grupo sin
nombre ( n ). La opción se aplica al patrón de expresión regular a partir del punto en el que esta se define y
es efectiva hasta el final del patrón o hasta el punto en el que otro constructor invierte la opción.
Con la Construcciones de agrupamiento (?imnsx-imnsx: subexpresión ) , que define opciones solo para el
grupo especificado.
El motor de expresiones regulares de .NET admite las siguientes opciones insertadas:

OPCIÓN DESCRIPCIÓN MODELO COINCIDENCIAS

i Usa la coincidencia sin \b(?i)a(?-i)a\w+\b "aardvark" , "aaaAuto"


distinción entre mayúsculas en
y minúsculas. "aardvark AAAuto
aaaAuto Adam
breakfast"

m Usa el modo multilínea. ^ Para obtener un ejemplo,


y $ coinciden con el consulte la sección "Modo
principio y el final de una multilínea" en Opciones de
línea, en lugar del principio expresiones regulares.
y el final de una cadena.

n No se capturan grupos sin Para obtener un ejemplo,


nombre. consulte la sección "Solo
capturas explícitas" en
Opciones de expresiones
regulares.
OPCIÓN DESCRIPCIÓN MODELO COINCIDENCIAS

s Usa el modo de una sola Para obtener un ejemplo,


línea. consulte la sección "Modo
de una sola línea" en
Opciones de expresiones
regulares.

x Se omite el espacio en \b(?x) \d+ \s \w+ "1 aardvark" , "2 cats"


blanco sin escape en el en
patrón de expresión regular. "1 aardvark 2 cats IV
centurions"

Construcciones misceláneas
Las estructuras misceláneas modifican un modelo de expresión regular o proporcionan información sobre él. En
la tabla siguiente se enumeran las construcciones misceláneas admitidas por .NET. Para obtener más
información, consulte Construcciones misceláneas.

CONSTRUCCIÓN DEFINICIÓN EJEMPLO

(?imnsx-imnsx) Establece o deshabilita opciones como \bA(?i)b\w+\b coincide con "ABA" ,


la no distinción entre mayúsculas y "Able" en "ABA Able Act"
minúsculas en medio de un patrón.
Para más información, consulte
Opciones de expresiones regulares.

(?# comentario ) Comentario alineado El comentario \bA(?#Matches words starting


termina en el primer paréntesis de with A)\w+\b
cierre.

# [hasta el final de la línea] Comentario en modo X El comentario (?x)\bA\w+\b#Matches words


comienza en un carácter # sin escape starting with A
y continúa hasta el final de la línea.

Vea también
System.Text.RegularExpressions
System.Text.RegularExpressions.Regex
Expresiones regulares
Clases de expresiones regulares
Ejemplos de expresiones regulares
Expresiones regulares: referencia rápida (descarga en formato Word)
Expresiones regulares: referencia rápida (descarga en formato PDF )
Escapes de carácter en expresiones regulares
20/01/2020 • 8 minutes to read • Edit Online

La barra diagonal inversa (\) en una expresión regular indica una de las siguientes situaciones:
El carácter que va detrás de ella es un carácter especial, como se muestra en la tabla de la sección siguiente.
Por ejemplo, \b es un delimitador que indica que una coincidencia de expresión regular debería comenzar
en un límite de palabras, \t representa un carácter de tabulación y \x020 representa un espacio.
Un carácter que de otro modo se interpretaría como una construcción de lenguaje sin escape, se debe
interpretar literalmente. Por ejemplo, una llave ( { ) inicia la definición de un cuantificador, pero una barra
diagonal inversa seguida de una llave ( \{ ) indica que el motor de expresiones regulares debería coincidir
con la llave. De igual forma, una sola barra diagonal inversa marca el principio de una construcción de
lenguaje con escape, pero dos barras diagonales inversas ( \\ ) indican que el motor de expresiones
regulares debería coincidir con la barra diagonal inversa.

NOTE
Los escapes de caracteres se reconocen en los patrones de expresiones regulares, pero no en los patrones de reemplazo.

Escapes de carácter en .NET


En la tabla siguiente se enumeran los escapes de caracteres admitidos en las expresiones regulares de .NET.

CARÁCTER O SECUENCIA DESCRIPCIÓN

Todos los caracteres excepto los siguientes: Los caracteres que no aparecen en la columna Carácter o
secuencia no tienen ningún significado especial en las
.$^{[(|)*+?\ expresiones regulares, sino que equivalen a sí mismos.

Los caracteres incluidos en la columna Carácter o secuencia


son elementos del lenguaje especial de expresiones regulares.
Para que coincidan en una expresión regular, deben escribirse
entre secuencias de escape o incluirse en un grupo de
caracteres positivos. Por ejemplo, las expresiones regulares
\$\d+ o [$]\d+ coinciden con "$1200".

\a Coincide con un carácter de campana (alarma), \u0007 .

\b En una clase de caracteres [ grupo_caracteres ] , coincide


con un retroceso, \u0008 . (Consulte Clases de caracteres).
Fuera de una clase de caracteres, \b es un delimitador que
coincide con un límite de palabras. (Consulte Delimitadores).

\t Coincide con un carácter de tabulación, \u0009 .

\r Coincide con un retorno de carro, \u000D . Observe que \r


no es equivalente al carácter de nueva línea, \n .

\v Coincide con una tabulación vertical, \u000B .


CARÁCTER O SECUENCIA DESCRIPCIÓN

\f Coincide con un avance de página, \u000C .

\n Coincide con una nueva línea, \u000A .

\e Coincide con un escape, \u001B .

\ nnn Coincide con un carácter ASCII, donde nnn está compuesto


de dos o tres dígitos que representan el código de carácter
octal. Por ejemplo, \040 representa un carácter de espacio.
Esta construcción se interpreta como una referencia inversa si
tiene un solo dígito (por ejemplo, \2 ) o si se corresponde
con el número de un grupo de captura. (Consulte
Construcciones de referencia inversa).

\x nn Coincide con un carácter ASCII, donde nn es un código de


carácter hexadecimal de dos dígitos.

\c X Coincide con un carácter de control ASCII, donde X es la letra


del carácter de control. Por ejemplo, \cC es CTRL-C.

\u nnnn Coincide con una unidad de código UTF-16 cuyo valor


hexadecimal es nnnn. Nota: .NET no admite el escape de
caracteres de Perl 5 usado para especificar Unicode. El escape
de caracteres de Perl 5 tiene el formato \x{ #### …} ,
donde #### … es una serie de dígitos hexadecimales. En su
lugar, use \u nnnn.

\ Si va seguido de un carácter que no se reconoce como


carácter de escape, coincide con ese carácter. Por ejemplo,
\* coincide con un asterisco (*) y es igual que \x2A .

Un ejemplo
En el ejemplo siguiente se muestra el uso de escapes de carácter en una expresión regular. Analiza una cadena que
contiene los nombres de las ciudades más grandes del mundo y sus poblaciones en 2009. Cada nombre de ciudad
se separa de su población por un carácter de tabulación ( \t ) o una barra vertical (| o \u007c ). Cada ciudad y su
población está separada de la siguiente por un retorno de carro y un avance de línea.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string delimited = @"\G(.+)[\t\u007c](.+)\r?\n";
string input = "Mumbai, India|13,922,125\t\n" +
"Shanghai, China\t13,831,900\n" +
"Karachi, Pakistan|12,991,000\n" +
"Delhi, India\t12,259,230\n" +
"Istanbul, Turkey|11,372,613\n";
Console.WriteLine("Population of the World's Largest Cities, 2009");
Console.WriteLine();
Console.WriteLine("{0,-20} {1,10}", "City", "Population");
Console.WriteLine();
foreach (Match match in Regex.Matches(input, delimited))
Console.WriteLine("{0,-20} {1,10}", match.Groups[1].Value,
match.Groups[2].Value);
}
}
// The example displays the following output:
// Population of the World's Largest Cities, 2009
//
// City Population
//
// Mumbai, India 13,922,125
// Shanghai, China 13,831,900
// Karachi, Pakistan 12,991,000
// Delhi, India 12,259,230
// Istanbul, Turkey 11,372,613

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim delimited As String = "\G(.+)[\t\u007c](.+)\r?\n"
Dim input As String = "Mumbai, India|13,922,125" + vbCrLf + _
"Shanghai, China" + vbTab + "13,831,900" + vbCrLf + _
"Karachi, Pakistan|12,991,000" + vbCrLf + _
"Delhi, India" + vbTab + "12,259,230" + vbCrLf + _
"Istanbul, Turkey|11,372,613" + vbCrLf
Console.WriteLine("Population of the World's Largest Cities, 2009")
Console.WriteLine()
Console.WriteLine("{0,-20} {1,10}", "City", "Population")
Console.WriteLine()
For Each match As Match In Regex.Matches(input, delimited)
Console.WriteLine("{0,-20} {1,10}", match.Groups(1).Value, _
match.Groups(2).Value)
Next
End Sub
End Module
' The example displays the following output:
' Population of the World's Largest Cities, 2009
'
' City Population
'
' Mumbai, India 13,922,125
' Shanghai, China 13,831,900
' Karachi, Pakistan 12,991,000
' Delhi, India 12,259,230
' Istanbul, Turkey 11,372,613

La expresión regular \G(.+)[\t|\u007c](.+)\r?\n se interpreta como se muestra en la tabla siguiente.


MODELO DESCRIPCIÓN

\G Comienza la búsqueda de coincidencias donde finalizó la


última coincidencia.

(.+) Buscar cualquier carácter coincidente una o más veces. Este es


el primer grupo de captura.

[\t\u007c] Coincide con un carácter de tabulación ( \t ) o una barra


vertical (|).

(.+) Buscar cualquier carácter coincidente una o más veces. Este es


el segundo grupo de captura.

\r?\n Coincide con cero o un retorno de carro seguido de una


nueva línea.

Vea también
Lenguaje de expresiones regulares: referencia rápida
Clases de caracteres en expresiones regulares
11/02/2020 • 58 minutes to read • Edit Online

Una clase de caracteres define un conjunto de caracteres, cualquiera de los cuales puede estar en una cadena de
entrada para que se produzca una coincidencia. El lenguaje de expresiones regulares de .NET admite las
siguientes clases de caracteres:
Grupos de caracteres positivos. Un carácter de la cadena de entrada debe coincidir con uno de los
caracteres del conjunto especificado. Para obtener más información, consulte Grupo de caracteres
positivos.
Grupos de caracteres negativos. Ningún carácter de la cadena de entrada debe coincidir con ninguno de
los caracteres del conjunto especificado. Para obtener más información, consulte Grupo de caracteres
negativos.
Cualquier carácter. El carácter . (punto) en una expresión regular es un carácter comodín que coincide
con cualquier carácter excepto con \n . Para obtener más información, consulte Cualquier carácter.
Una categoría general o un bloque con nombre Unicode. Para que se produzca una coincidencia, un
carácter de la cadena de entrada debe ser miembro de una categoría Unicode determinada o debe estar
dentro de un intervalo contiguo de caracteres Unicode. Para obtener más información, consulte Categoría
Unicode o bloque Unicode.
Un bloque con nombre o una categoría general negativa Unicode. Para que se produzca una coincidencia,
un carácter de la cadena de entrada no debe ser miembro de una categoría Unicode determinada o no
debe estar dentro de un intervalo contiguo de caracteres Unicode. Para obtener más información,
consulte Categoría Unicode o bloque Unicode negativo.
Un carácter de palabra. Un carácter de la cadena de entrada puede pertenecer a cualquiera de las
categorías Unicode que son adecuadas para los caracteres que se usan para formar palabras. Para
obtener más información, consulte Carácter de palabra.
Un carácter que no se usa en las palabras. Un carácter de la cadena de entrada puede pertenecer a
cualquier categoría Unicode que no se usa para formar palabras. Para obtener más información, consulte
Carácter que no se usa en las palabras.
Un carácter de espacio en blanco. Un carácter de la cadena de entrada puede ser cualquiera de los
caracteres separadores Unicode, así como cualquiera de los caracteres de una serie de caracteres de
control. Para obtener más información, consulte Carácter de espacio en blanco.
Un carácter que no sea un espacio en blanco. Un carácter de la cadena de entrada puede ser cualquier
carácter que no sea un espacio en blanco. Para obtener más información, consulte Carácter que no sea un
espacio en blanco.
Un dígito decimal. Un carácter de la cadena de entrada puede ser cualquiera de los caracteres clasificados
como dígitos decimales de Unicode. Para obtener más información, consulte Carácter de dígito decimal.
Un carácter que no sea un dígito decimal. Un carácter de la cadena de entrada puede ser cualquier
carácter que no sea un dígito decimal de Unicode. Para obtener más información, consulte Carácter de
dígito decimal.
.NET admite expresiones de sustracción de clases de caracteres, que permiten definir un conjunto de caracteres
como el resultado de excluir una clase de caracteres de otra clase de caracteres. Para obtener más información,
consulte Sustracción de clases de caracteres.

NOTE
Las clases que coinciden con los caracteres por categoría, como \w para que coincidan con caracteres alfabéticos o \p{} para
que coincidan con una categoría Unicode, que se basan en la clase CharUnicodeInfo para proporcionar información sobre
las categorías de caracteres. A partir de .NET Framework 4.6.2, las categorías de caracteres se basan en el estándar Unicode,
versión 8.0.0. Desde .NET Framework 4 hasta .NET Framework 4.6.1, se basan en el estándar Unicode, versión 6.3.0.

Grupo de caracteres positivos: [ ]


Un grupo de caracteres positivos especifica una lista de caracteres cualquiera de los cuales puede aparecer en
una cadena de entrada para que se produzca una coincidencia. Los caracteres de la lista se pueden especificar
individualmente, como un intervalo o de ambas formas.
La sintaxis para especificar la lista de caracteres individuales es la siguiente:
[*character_group*]

donde grupo_caracteres es una lista de cada uno de los caracteres que pueden aparecer en la cadena de entrada
para que se produzca una coincidencia. grupo_caracteres puede estar formado por cualquier combinación de
uno o varios caracteres literales, caracteres de escape o clases de caracteres.
La sintaxis para especificar un intervalo de caracteres es la siguiente:
[firstCharacter-lastCharacter]

donde firstCharacter es el carácter que comienza el intervalo y lastCharacter es el carácter final del intervalo. Un
intervalo de caracteres es una serie contigua de caracteres que se define especificando el primer carácter de la
serie, un guion (-) y, a continuación, el último carácter de la serie. Dos caracteres son contiguos si tienen puntos
de código Unicode adyacentes. firstCharacter debe ser el carácter con el punto de código inferior y lastCharacter
debe ser el carácter con el punto de código superior.

NOTE
Dado que un grupo de caracteres positivos puede incluir un conjunto de caracteres y un rango de caracteres, un carácter
de guión ( - ) siempre se interpreta como el separador de rango, a menos que sea el primer carácter del grupo o el último.

En la tabla siguiente se recogen algunos de los patrones de expresiones regulares comunes que contienen clases
de caracteres positivos.

MODELO DESCRIPCIÓN

[aeiou] Coincide con todas las vocales.

[\p{P}\d] Coincide con todos los caracteres de puntuación y de dígitos


decimales.

[\s\p{P}] Coincide con todos los caracteres de espacio en blanco y de


puntuación.

En el ejemplo siguiente se define un grupo de caracteres positivos que contiene los caracteres "a" y "e" de
manera que la cadena de entrada deba contener las palabras "grey" o "gray" seguidas de cualquier otra palabra
para que se produzca una coincidencia.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"gr[ae]y\s\S+?[\s\p{P}]";
string input = "The gray wolf jumped over the grey wall.";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match match in matches)
Console.WriteLine($"'{match.Value}'");
}
}
// The example displays the following output:
// 'gray wolf '
// 'grey wall.'

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "gr[ae]y\s\S+?[\s\p{P}]"
Dim input As String = "The gray wolf jumped over the grey wall."
Dim matches As MatchCollection = Regex.Matches(input, pattern)
For Each match As Match In matches
Console.WriteLine($"'{match.Value}'")
Next
End Sub
End Module
' The example displays the following output:
' 'gray wolf '
' 'grey wall.'

La expresión regular gr[ae]y\s\S+?[\s|\p{P}] se define de la siguiente manera:

MODELO DESCRIPCIÓN

gr Coincide con los caracteres literales "gr".

[ae] Coincide con una "a" o una "e".

y\s Coincide con el carácter literal "y" seguido de un carácter de


espacio en blanco.

\S+? Coincide con uno o varios caracteres que no sean un espacio


en blanco, pero con la menor cantidad posible de caracteres.

[\s\p{P}] Coincide con un carácter de espacio en blanco o un signo de


puntuación.

En el ejemplo siguiente se buscan palabras que comienzan por cualquier letra mayúscula. Utiliza la subexpresión
[A-Z] para representar el intervalo de letras mayúsculas de la A a la Z.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b[A-Z]\w*\b";
string input = "A city Albany Zulu maritime Marseilles";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// A
// Albany
// Zulu
// Marseilles

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b[A-Z]\w*\b"
Dim input As String = "A city Albany Zulu maritime Marseilles"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module

La expresión regular \b[A-Z]\w*\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

[A-Z] Coincide con cualquier letra mayúscula de la A a la Z.

\w* Buscar una coincidencia con cero o más caracteres


alfabéticos.

\b Coincide con un límite de palabras.

Grupo de caracteres negativos: [^]


Un grupo de caracteres negativos especifica una lista de caracteres que no deben aparecer en una cadena de
entrada para que se produzca una coincidencia. Los caracteres de la lista se pueden especificar individualmente,
como un intervalo o de ambas formas.
La sintaxis para especificar la lista de caracteres individuales es la siguiente:
[*^character_group*]

donde grupo_caracteres es una lista de cada uno de los caracteres que no pueden aparecer en la cadena de
entrada para que se produzca una coincidencia. grupo_caracteres puede estar formado por cualquier
combinación de uno o varios caracteres literales, caracteres de escape o clases de caracteres.
La sintaxis para especificar un intervalo de caracteres es la siguiente:
[^*firstCharacter*-*lastCharacter*]

donde firstCharacter es el carácter que comienza el intervalo y lastCharacter es el carácter final del intervalo. Un
intervalo de caracteres es una serie contigua de caracteres que se define especificando el primer carácter de la
serie, un guion (-) y, a continuación, el último carácter de la serie. Dos caracteres son contiguos si tienen puntos
de código Unicode adyacentes. firstCharacter debe ser el carácter con el punto de código inferior y lastCharacter
debe ser el carácter con el punto de código superior.

NOTE
Dado que un grupo de caracteres negativos puede incluir un conjunto de caracteres y un rango de caracteres, un carácter
de guión ( - ) siempre se interpreta como el separador de rango, a menos que sea el primer carácter del grupo o el último.

Es posible concatenar dos o más intervalos de caracteres. Por ejemplo, para especificar el intervalo de dígitos
decimales del "0" al "9", el intervalo de letras minúsculas de la "a" a la "f" y el intervalo de letras mayúsculas de la
"A" a la "F", utilice [0-9a-fA-F] .
El carácter inicial de acento circunflejo ( ^ ) de un grupo de caracteres negativos es obligatorio e indica que el
grupo de caracteres es un grupo de caracteres negativos en lugar de un grupo de caracteres positivos.

IMPORTANT
Un grupo de caracteres negativos dentro de un patrón de expresión regular más grande no es una aserción de ancho cero.
Es decir, después de evaluar el grupo de caracteres negativos, el motor de expresiones regulares avanza un carácter en la
cadena de entrada.

En la tabla siguiente se recogen algunos de los patrones de expresiones regulares comunes que contienen
grupos de caracteres negativos.

MODELO DESCRIPCIÓN

[^aeiou] Coincide con todos los caracteres excepto las vocales.

[^\p{P}\d] Coincide con todos los caracteres excepto los caracteres de


puntuación y de dígitos decimales.

En el ejemplo siguiente se busca cualquier palabra que comience por los caracteres "th" y no vaya seguida de
una "o".
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\bth[^o]\w+\b";
string input = "thought thing though them through thus thorough this";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// thing
// them
// through
// thus
// this

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\bth[^o]\w+\b"
Dim input As String = "thought thing though them through thus " + _
"thorough this"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' thing
' them
' through
' thus
' this

La expresión regular \bth[^o]\w+\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

th Coincide con los caracteres literales "th".

[^o] Coincide con cualquier carácter que no sea una "o".

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

\b Finaliza en un límite de palabras.

Cualquier carácter: .
El carácter de punto (.) coincide con cualquier carácter excepto con \n (carácter de nueva línea, \u000A), con los
dos requisitos siguientes:
Si la opción RegexOptions.Singleline modifica un patrón de expresión regular o si la opción . modifica
la parte del patrón que contiene la clase de caracteres s , . coincide con cualquier carácter. Para obtener
más información, consulte Opciones de expresiones regulares.
El ejemplo siguiente muestra el comportamiento predeterminado de la clase de caracteres . y con la
opción RegexOptions.Singleline. La expresión regular ^.+ comienza en el principio de la cadena y
coincide con todos los caracteres. De forma predeterminada, la coincidencia termina al final de la primera
línea; el patrón de la expresión regular coincide con el carácter de retorno de carro, \r o \u000D, pero no
coincide con \n . Dado que la opción RegexOptions.Singleline interpreta la cadena de entrada completa
como una sola línea, coincide con cada carácter de la cadena de entrada, incluido \n .

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "^.+";
string input = "This is one line and" + Environment.NewLine + "this is the second.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(Regex.Escape(match.Value));

Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Singleline))
Console.WriteLine(Regex.Escape(match.Value));
}
}
// The example displays the following output:
// This\ is\ one\ line\ and\r
//
// This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^.+"
Dim input As String = "This is one line and" + vbCrLf + "this is the second."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(Regex.Escape(match.Value))
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.SingleLine)
Console.WriteLine(Regex.Escape(match.Value))
Next
End Sub
End Module
' The example displays the following output:
' This\ is\ one\ line\ and\r
'
' This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.

NOTE
Dado que coincide con cualquier carácter excepto con \n , la clase de caracteres . también coincide con \r (el carácter
de retorno de carro, \u000D).

En un grupo de caracteres positivos o negativos, un punto se considera un carácter de punto literal, no


una clase de caracteres. Para más información, consulte las secciones Grupo de caracteres positivos y
Grupo de caracteres negativos anteriormente en este tema. En el ejemplo siguiente se define una
expresión regular que incluye el carácter de punto ( . ) como una clase de caracteres y como un miembro
de un grupo de caracteres positivos. La expresión regular \b.*[.?!;:](\s|\z) comienza en un límite de
palabras, coincide con cualquier carácter hasta que encuentra uno de cinco signos de puntuación, incluido
el punto, y después coincide con un carácter de espacio en blanco o con el final de la cadena.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b.*[.?!;:](\s|\z)";
string input = "this. what: is? go, thing.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// this. what: is? go, thing.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As STring = "\b.*[.?!;:](\s|\z)"
Dim input As String = "this. what: is? go, thing."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' this. what: is? go, thing.

NOTE
Dado que coincide con cualquier carácter, el elemento del lenguaje . se utiliza a menudo con un cuantificador no
expansivo si un patrón de expresión regular intenta coincidir varias veces con cualquier carácter. Para obtener más
información, consulte Cuantificadores.

Categoría Unicode o bloque Unicode: \p{}


El estándar Unicode asigna una categoría general a cada carácter. Por ejemplo, un carácter concreto puede ser
una letra mayúscula (representada por la categoría Lu ), un dígito decimal (categoría Nd ), un símbolo
matemático (categoría Sm ) o un separador de párrafos (categoría Zl ). Determinados juegos de caracteres del
estándar Unicode también ocupan un intervalo o bloque específico de puntos de código consecutivos. Por
ejemplo, el juego de caracteres latinos básico se encuentra desde \u0000 hasta \u007F, mientras que el juego de
caracteres árabes se encuentra desde \u0600 hasta \u06FF.
La construcción de expresión regular
\p{ nombre }

coincide con cualquier carácter que pertenezca a una categoría general o bloque con nombre de Unicode, donde
nombre es la abreviatura de la categoría o el nombre del bloque con nombre. Para obtener una lista de
abreviaturas de categorías, consulte la sección Categorías generales Unicode compatibles más adelante en este
tema. Para obtener una lista de bloques con nombre, consulte la sección Bloques con nombre compatibles más
adelante en este tema.
En el ejemplo siguiente se usa la construcción \p{ nombre } para buscar coincidencias con una categoría
general de Unicode (en este caso, Pd o Punctuation, Dash) y un bloque con nombre (los bloques con nombre
IsGreek e IsBasicLatin ).

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\p{IsGreek}+(\s)?)+\p{Pd}\s(\p{IsBasicLatin}+(\s)?)+";
string input = "Κατα Μαθθαίον - The Gospel of Matthew";

Console.WriteLine(Regex.IsMatch(input, pattern)); // Displays True.


}
}

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\p{IsGreek}+(\s)?)+\p{Pd}\s(\p{IsBasicLatin}+(\s)?)+"
Dim input As String = "Κατα Μαθθαίον - The Gospel of Matthew"

Console.WriteLine(Regex.IsMatch(input, pattern)) ' Displays True.


End Sub
End Module

La expresión regular \b(\p{IsGreek}+(\s)?)+\p{Pd}\s(\p{IsBasicLatin}+(\s)?)+ se define como se muestra en la


tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

\p{IsGreek}+ Coincide con uno o varios caracteres griegos.

(\s)? Busca coincidencias con cero o un carácter de espacio en


blanco.

(\p{IsGreek}+(\s)?)+ Coincide una o varias veces con el patrón de uno o varios


caracteres griegos seguidos de cero o un carácter de espacio
en blanco.

\p{Pd} Coincide con un carácter de puntuación, guion.

\s Coincide con un carácter de espacio en blanco.

\p{IsBasicLatin}+ Coincide con uno o varios caracteres latinos básicos.


MODELO DESCRIPCIÓN

(\s)? Busca coincidencias con cero o un carácter de espacio en


blanco.

(\p{IsBasicLatin}+(\s)?)+ Coincide una o varias veces con el patrón de uno varios


caracteres latinos básicos seguidos de cero o un carácter de
espacio en blanco.

Categoría Unicode o bloque Unicode negativo: \P{}


El estándar Unicode asigna una categoría general a cada carácter. Por ejemplo, un carácter concreto puede ser
una letra mayúscula (representada por la categoría Lu ), un dígito decimal (categoría Nd ), un símbolo
matemático (categoría Sm ) o un separador de párrafos (categoría Zl ). Determinados juegos de caracteres del
estándar Unicode también ocupan un intervalo o bloque específico de puntos de código consecutivos. Por
ejemplo, el juego de caracteres latinos básico se encuentra desde \u0000 hasta \u007F, mientras que el juego de
caracteres árabes se encuentra desde \u0600 hasta \u06FF.
La construcción de expresión regular
\P{ nombre }

coincide con cualquier carácter que no pertenezca a una categoría general o bloque con nombre de Unicode,
donde nombre es la abreviatura de la categoría o el nombre del bloque con nombre. Para obtener una lista de
abreviaturas de categorías, consulte la sección Categorías generales Unicode compatibles más adelante en este
tema. Para obtener una lista de bloques con nombre, consulte la sección Bloques con nombre compatibles más
adelante en este tema.
En el siguiente ejemplo se usa la construcción \P{ nombre } para quitar cualquier símbolo de divisa (en este
caso, la categoría Sc , o Symbol, Currency) de las cadenas numéricas.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(\P{Sc})+";

string[] values = { "$164,091.78", "£1,073,142.68", "73¢", "€120" };


foreach (string value in values)
Console.WriteLine(Regex.Match(value, pattern).Value);
}
}
// The example displays the following output:
// 164,091.78
// 1,073,142.68
// 73
// 120
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(\P{Sc})+"

Dim values() As String = { "$164,091.78", "£1,073,142.68", "73¢", "€120"}


For Each value As String In values
Console.WriteLine(Regex.Match(value, pattern).Value)
Next
End Sub
End Module
' The example displays the following output:
' 164,091.78
' 1,073,142.68
' 73
' 120

El patrón de expresión regular (\P{Sc})+ coincide con uno o varios caracteres que no son símbolos de divisa;
quita eficazmente cualquier símbolo de divisa de la cadena de resultado.

Carácter de palabra: \w
\w coincide con cualquier carácter de palabra. Un carácter de palabra es un miembro de alguna de las
categorías Unicode enumeradas en la tabla siguiente.

CATEGORÍA DESCRIPCIÓN

Ll Letra, minúscula

Lu Letra, mayúscula

Lt Letra, inicial en mayúscula

Lo Letra, otra

Lm Letra, modificador

Mn Marca, sin espacios

Nd Número, dígito decimal

Pc Puntuación, Conector Esta categoría incluye diez caracteres,


el más usado de los cuales es el carácter LOWLINE (),
u+005F.

Si se especifica un comportamiento conforme a ECMAScript, \w es equivalente a [a-zA-Z_0-9] . Para obtener


información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.

NOTE
Dado que coincide con cualquier carácter de palabra, el elemento del lenguaje \w se suele usar con un cuantificador
diferido si un patrón de expresión regular intenta coincidir varias veces con cualquier carácter de palabra, seguido de un
carácter de palabra específico. Para obtener más información, consulte Cuantificadores.
En el ejemplo siguiente se usa el elemento del lenguaje \w para buscar coincidencias de caracteres duplicados
en una palabra. El ejemplo define un patrón de expresión regular, (\w)\1 , que se puede interpretar de la
siguiente manera.

ELEMENTO DESCRIPCIÓN

(\w) Coincide con un carácter de palabra. Este es el primer grupo


de captura.

\1 Coincide con el valor de la primera captura.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(\w)\1";
string[] words = { "trellis", "seer", "latter", "summer",
"hoarse", "lesser", "aardvark", "stunned" };
foreach (string word in words)
{
Match match = Regex.Match(word, pattern);
if (match.Success)
Console.WriteLine("'{0}' found in '{1}' at position {2}.",
match.Value, word, match.Index);
else
Console.WriteLine("No double characters in '{0}'.", word);
}
}
}
// The example displays the following output:
// 'll' found in 'trellis' at position 3.
// 'ee' found in 'seer' at position 1.
// 'tt' found in 'latter' at position 2.
// 'mm' found in 'summer' at position 2.
// No double characters in 'hoarse'.
// 'ss' found in 'lesser' at position 2.
// 'aa' found in 'aardvark' at position 0.
// 'nn' found in 'stunned' at position 3.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(\w)\1"
Dim words() As String = { "trellis", "seer", "latter", "summer", _
"hoarse", "lesser", "aardvark", "stunned" }
For Each word As String In words
Dim match As Match = Regex.Match(word, pattern)
If match.Success Then
Console.WriteLine("'{0}' found in '{1}' at position {2}.", _
match.Value, word, match.Index)
Else
Console.WriteLine("No double characters in '{0}'.", word)
End If
Next
End Sub
End Module
' The example displays the following output:
' 'll' found in 'trellis' at position 3.
' 'ee' found in 'seer' at position 1.
' 'tt' found in 'latter' at position 2.
' 'mm' found in 'summer' at position 2.
' No double characters in 'hoarse'.
' 'ss' found in 'lesser' at position 2.
' 'aa' found in 'aardvark' at position 0.
' 'nn' found in 'stunned' at position 3.

Carácter que no se usa para formar palabras: \W


\W coincide con cualquier carácter que no sea de palabra. El elemento del lenguaje \W es equivalente a la clase
de caracteres siguiente:
[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]

En otras palabras, coincide con cualquier carácter excepto con los que figuran en las categorías Unicode de la
tabla siguiente.

CATEGORÍA DESCRIPCIÓN

Ll Letra, minúscula

Lu Letra, mayúscula

Lt Letra, inicial en mayúscula

Lo Letra, otra

Lm Letra, modificador

Mn Marca, sin espacios

Nd Número, dígito decimal

Pc Puntuación, Conector Esta categoría incluye diez caracteres,


el más usado de los cuales es el carácter LOWLINE (),
u+005F.

Si se especifica un comportamiento conforme a ECMAScript, \W es equivalente a [^a-zA-Z_0-9] . Para obtener


información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.

NOTE
Dado que coincide con cualquier carácter que no sea de palabra, el elemento del lenguaje \W se suele usar con un
cuantificador diferido si un patrón de expresión regular intenta coincidir varias veces con cualquier carácter que no sea de
palabra, seguido de un carácter que no sea de palabra específico. Para obtener más información, consulte Cuantificadores.

En el ejemplo siguiente se ilustra la clase de caracteres \W . Define un patrón de expresión regular,


\b(\w+)(\W){1,2} , que coincide con una palabra seguida de uno o dos caracteres que no son de palabra, como
un espacio en blanco o un signo de puntuación. La expresión regular se interpreta como se muestra en la tabla
siguiente.

ELEMENTO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este es el primer grupo de captura.

(\W){1,2} Coincide una o dos veces con un carácter que no se usa para
formar palabras. Este es el segundo grupo de captura.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\w+)(\W){1,2}";
string input = "The old, grey mare slowly walked across the narrow, green pasture.";
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine(match.Value);
Console.Write(" Non-word character(s):");
CaptureCollection captures = match.Groups[2].Captures;
for (int ctr = 0; ctr < captures.Count; ctr++)
Console.Write(@"'{0}' (\u{1}){2}", captures[ctr].Value,
Convert.ToUInt16(captures[ctr].Value[0]).ToString("X4"),
ctr < captures.Count - 1 ? ", " : "");
Console.WriteLine();
}
}
}
// The example displays the following output:
// The
// Non-word character(s):' ' (\u0020)
// old,
// Non-word character(s):',' (\u002C), ' ' (\u0020)
// grey
// Non-word character(s):' ' (\u0020)
// mare
// Non-word character(s):' ' (\u0020)
// slowly
// Non-word character(s):' ' (\u0020)
// walked
// Non-word character(s):' ' (\u0020)
// across
// Non-word character(s):' ' (\u0020)
// the
// Non-word character(s):' ' (\u0020)
// narrow,
// Non-word character(s):',' (\u002C), ' ' (\u0020)
// green
// Non-word character(s):' ' (\u0020)
// pasture.
// Non-word character(s):'.' (\u002E)
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\w+)(\W){1,2}"
Dim input As String = "The old, grey mare slowly walked across the narrow, green pasture."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Console.Write(" Non-word character(s):")
Dim captures As CaptureCollection = match.Groups(2).Captures
For ctr As Integer = 0 To captures.Count - 1
Console.Write("'{0}' (\u{1}){2}", captures(ctr).Value, _
Convert.ToUInt16(captures(ctr).Value.Chars(0)).ToString("X4"), _
If(ctr < captures.Count - 1, ", ", ""))
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' The
' Non-word character(s):' ' (\u0020)
' old,
' Non-word character(s):',' (\u002C), ' ' (\u0020)
' grey
' Non-word character(s):' ' (\u0020)
' mare
' Non-word character(s):' ' (\u0020)
' slowly
' Non-word character(s):' ' (\u0020)
' walked
' Non-word character(s):' ' (\u0020)
' across
' Non-word character(s):' ' (\u0020)
' the
' Non-word character(s):' ' (\u0020)
' narrow,
' Non-word character(s):',' (\u002C), ' ' (\u0020)
' green
' Non-word character(s):' ' (\u0020)
' pasture.
' Non-word character(s):'.' (\u002E)

Dado que el objeto Group del segundo grupo de captura contiene solo un carácter que no se usa para formar
palabras, el ejemplo recupera todos los caracteres que no se usan para formar palabras capturados del objeto
CaptureCollection que devuelve la propiedad Group.Captures.

Carácter de espacio en blanco: \s


\s coincide con cualquier carácter de espacio en blanco. Equivale a las secuencias de escape y las categorías
Unicode que figuran en la tabla siguiente.

CATEGORÍA DESCRIPCIÓN

\f El carácter de avance de página, \u000C.

\n El carácter de nueva línea, \u000A.

\r El carácter de retorno de carro, \u000D.

\t El carácter de tabulación, \u0009.


CATEGORÍA DESCRIPCIÓN

\v El carácter de tabulación vertical, \u000B.

\x85 Los puntos suspensivos o el carácter de LÍNEA SIGUIENTE


(…), \u0085.

\p{Z} Coincide con cualquier carácter separador.

Si se especifica un comportamiento conforme a ECMAScript, \s es equivalente a [ \f\n\r\t\v] . Para obtener


información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.
En el ejemplo siguiente se ilustra la clase de caracteres \s . Define un patrón de expresión regular,
\b\w+(e)?s(\s|$) , que coincide con una palabra que termina por "s" o "es" seguida de un carácter de espacio en
blanco o el final de la cadena de entrada. La expresión regular se interpreta como se muestra en la tabla
siguiente.

ELEMENTO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

(e)? Coincide cero o una vez con una "e".

s Coincide con una "s".

(\s|$) Coincide con un carácter de espacio en blanco o el final de la


cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b\w+(e)?s(\s|$)";
string input = "matches stores stops leave leaves";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// matches
// stores
// stops
// leaves
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b\w+(e)?s(\s|$)"
Dim input As String = "matches stores stops leave leaves"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' matches
' stores
' stops
' leaves

Carácter que no sea un espacio en blanco: \S


\S coincide con cualquier carácter que no sea un espacio en blanco. Equivale al patrón de expresión regular
[^\f\n\r\t\v\x85\p{Z}] o es lo contrario del patrón de expresión regular equivalente a \s , que coincide con los
caracteres de espacio en blanco. Para más información, consulte Carácter de espacio en blanco: \s.
Si se especifica un comportamiento conforme a ECMAScript, \S es equivalente a [^ \f\n\r\t\v] . Para obtener
información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.
En el ejemplo siguiente se ilustra el elemento del lenguaje \S . El patrón de expresión regular \b(\S+)\s?
coincide con cadenas delimitadas por caracteres de espacio en blanco. El segundo elemento del objeto
GroupCollection de la coincidencia contiene la cadena coincidente. La expresión regular puede interpretarse
como se muestra en la tabla siguiente.

ELEMENTO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

(\S+) Coincide con caracteres que no son espacio en blanco. Este


es el primer grupo de captura.

\s? Busca coincidencias con cero o un carácter de espacio en


blanco.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\S+)\s?";
string input = "This is the first sentence of the first paragraph. " +
"This is the second sentence.\n" +
"This is the only sentence of the second paragraph.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Groups[1]);
}
}
// The example displays the following output:
// This
// is
// the
// first
// sentence
// of
// the
// first
// paragraph.
// This
// is
// the
// second
// sentence.
// This
// is
// the
// only
// sentence
// of
// the
// second
// paragraph.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\S+)\s?"
Dim input As String = "This is the first sentence of the first paragraph. " + _
"This is the second sentence." + vbCrLf + _
"This is the only sentence of the second paragraph."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Groups(1))
Next
End Sub
End Module
' The example displays the following output:
' This
' is
' the
' first
' sentence
' of
' the
' first
' paragraph.
' This
' is
' the
' second
' sentence.
' This
' is
' the
' only
' sentence
' of
' the
' second
' paragraph.

Carácter de dígito decimal: \d


\d coincide con cualquier dígito decimal. Equivale al patrón de expresión regular \p{Nd} , que incluye los
dígitos decimales estándar 0-9 así como los dígitos decimales de varios juegos de caracteres.
Si se especifica un comportamiento conforme a ECMAScript, \d es equivalente a [0-9] . Para obtener
información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.
En el ejemplo siguiente se ilustra el elemento del lenguaje \d . Comprueba si una cadena de entrada representa
un número de teléfono válido de los Estados Unidos y Canadá. El patrón de expresión regular
^(\(?\d{3}\)?[\s-])?\d{3}-\d{4}$ se define como se muestra en la tabla siguiente.

ELEMENTO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias con el principio de la


cadena de entrada.

\(? Coincide con cero o un carácter "(" literal.

\d{3} Coincide con tres dígitos decimales.


ELEMENTO DESCRIPCIÓN

\)? Coincide con cero o un carácter ")" literal.

[\s-] Coincide con un guion o un carácter de espacio en blanco.

(\(?\d{3}\)?[\s-])? Coincide cero o una vez con un paréntesis de apertura


opcional seguido de tres dígitos decimales, un paréntesis de
cierre opcional y un carácter de espacio en blanco o un
guion. Este es el primer grupo de captura.

\d{3}-\d{4} Coincide con tres dígitos decimales seguidos de un guion y


otros cuatro dígitos decimales.

$ Coincide con el final de la cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"^(\(?\d{3}\)?[\s-])?\d{3}-\d{4}$";
string[] inputs = { "111 111-1111", "222-2222", "222 333-444",
"(212) 111-1111", "111-AB1-1111",
"212-111-1111", "01 999-9999" };

foreach (string input in inputs)


{
if (Regex.IsMatch(input, pattern))
Console.WriteLine(input + ": matched");
else
Console.WriteLine(input + ": match failed");
}
}
}
// The example displays the following output:
// 111 111-1111: matched
// 222-2222: matched
// 222 333-444: match failed
// (212) 111-1111: matched
// 111-AB1-1111: match failed
// 212-111-1111: matched
// 01 999-9999: match failed
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^(\(?\d{3}\)?[\s-])?\d{3}-\d{4}$"
Dim inputs() As String = { "111 111-1111", "222-2222", "222 333-444", _
"(212) 111-1111", "111-AB1-1111", _
"212-111-1111", "01 999-9999" }

For Each input As String In inputs


If Regex.IsMatch(input, pattern) Then
Console.WriteLine(input + ": matched")
Else
Console.WriteLine(input + ": match failed")
End If
Next
End Sub
End Module
' The example displays the following output:
' 111 111-1111: matched
' 222-2222: matched
' 222 333-444: match failed
' (212) 111-1111: matched
' 111-AB1-1111: match failed
' 212-111-1111: matched
' 01 999-9999: match failed

Carácter que no sea un dígito: \D


\D coincide con cualquier carácter que no sea un dígito. Equivale al patrón de expresión regular \P{Nd} .
Si se especifica un comportamiento conforme a ECMAScript, \D es equivalente a [^0-9] . Para obtener
información sobre las expresiones regulares ECMAScript, consulte la sección "Comportamiento de la búsqueda
de coincidencias de ECMAScript" en Opciones de expresiones regulares.
En el ejemplo siguiente se muestra el elemento del lenguaje \D. Comprueba si una cadena, como un número de
pieza, consta de la combinación adecuada de caracteres decimales y no decimales. El patrón de expresión regular
^\D\d{1,5}\D*$ se define como se muestra en la tabla siguiente.

ELEMENTO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias con el principio de la


cadena de entrada.

\D Coincide con un carácter que no sea un dígito.

\d{1,5} Coincide con entre uno y cinco dígitos decimales.

\D* Coincide con cero, uno o más caracteres no decimales.

$ Coincide con el final de la cadena de entrada.


using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"^\D\d{1,5}\D*$";
string[] inputs = { "A1039C", "AA0001", "C18A", "Y938518" };

foreach (string input in inputs)


{
if (Regex.IsMatch(input, pattern))
Console.WriteLine(input + ": matched");
else
Console.WriteLine(input + ": match failed");
}
}
}
// The example displays the following output:
// A1039C: matched
// AA0001: match failed
// C18A: matched
// Y938518: match failed

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^\D\d{1,5}\D*$"
Dim inputs() As String = { "A1039C", "AA0001", "C18A", "Y938518" }

For Each input As String In inputs


If Regex.IsMatch(input, pattern) Then
Console.WriteLine(input + ": matched")
Else
Console.WriteLine(input + ": match failed")
End If
Next
End Sub
End Module
' The example displays the following output:

Categorías generales Unicode compatibles


Unicode define las categorías generales que se muestran en la tabla siguiente. Para obtener más información,
consulte las secciones sobre el "formato de archivo UCD" y los "valores de categorías generales" en la base de
datos de caracteres Unicode.

CATEGORÍA DESCRIPCIÓN

Lu Letra, mayúscula

Ll Letra, minúscula

Lt Letra, inicial en mayúscula

Lm Letra, modificador
CATEGORÍA DESCRIPCIÓN

Lo Letra, otra

L Todos los caracteres de letras. Esto incluye los caracteres Lu


, Ll , Lt , Lm y Lo .

Mn Marca, sin espacios

Mc Marca, con espacios y combinación

Me Marca, inclusión

M Todas las marcas diacríticas. Esto incluye las categorías Mn ,


Mc y Me .

Nd Número, dígito decimal

Nl Número, letra

No Número, otro

N Todos los números. Esto incluye las categorías Nd , Nl y


No .

Pc Puntuación, conector

Pd Puntuación, raya

Ps Puntuación, abrir

Pe Puntuación, cerrar

Pi Puntuación, comilla de apertura (puede comportarse como


Ps o Pe, en función del uso)

Pf Puntuación, comilla de cierre (puede comportarse como Ps o


Pe, en función del uso)

Po Puntuación, otro

P Todos los signos de puntuación. Esto incluye las categorías


Pc , Pd , Ps , Pe , Pi , Pf y Po .

Sm Símbolo, matemático

Sc Símbolo, divisa

Sk Símbolo, modificador

So Símbolo, otro
CATEGORÍA DESCRIPCIÓN

S Todos los símbolos. Esto incluye las categorías Sm , Sc ,


Sk y So .

Zs Separador, espacio

Zl Separador, línea

Zp Separador, párrafo

Z Todos los caracteres separadores. Esto incluye las categorías


Zs , Zl y Zp .

Cc Otro, control

Cf Otro, formato

Cs Otro, suplente

Co Otro, uso privado

Cn Otro, no asignado (ningún carácter tiene esta propiedad)

C Todos los caracteres de control. Esto incluye las categorías


Cc , Cf , Cs , Co y Cn .

Puede determinar la categoría Unicode de cualquier carácter concreto pasando dicho carácter al método
GetUnicodeCategory. En el ejemplo siguiente se utiliza el método GetUnicodeCategory para determinar la
categoría de cada elemento de una matriz que contiene determinados caracteres latinos.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
char[] chars = { 'a', 'X', '8', ',', ' ', '\u0009', '!' };

foreach (char ch in chars)


Console.WriteLine("'{0}': {1}", Regex.Escape(ch.ToString()),
Char.GetUnicodeCategory(ch));
}
}
// The example displays the following output:
// 'a': LowercaseLetter
// 'X': UppercaseLetter
// '8': DecimalDigitNumber
// ',': OtherPunctuation
// '\ ': SpaceSeparator
// '\t': Control
// '!': OtherPunctuation
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim chars() As Char = { "a"c, "X"c, "8"c, ","c, " "c, ChrW(9), "!"c }

For Each ch As Char In chars


Console.WriteLine("'{0}': {1}", Regex.Escape(ch.ToString()), _
Char.GetUnicodeCategory(ch))
Next
End Sub
End Module
' The example displays the following output:
' 'a': LowercaseLetter
' 'X': UppercaseLetter
' '8': DecimalDigitNumber
' ',': OtherPunctuation
' '\ ': SpaceSeparator
' '\t': Control
' '!': OtherPunctuation

Bloques con nombre compatibles


.NET proporciona los bloques con nombre que se muestran en la tabla siguiente. El conjunto de bloques con
nombre compatibles está basado en Unicode 4.0 y Perl 5.6. Para una expresión regular que utiliza bloques con
nombre, consulte la sección Categoría Unicode o bloque Unicode: \p{}.

INTERVALO DE PUNTOS DE CÓDIGO NOMBRE DEL BLOQUE

0000 - 007F IsBasicLatin

0080 - 00FF IsLatin-1Supplement

0100 - 017F IsLatinExtended-A

0180 - 024F IsLatinExtended-B

0250 - 02AF IsIPAExtensions

02B0 - 02FF IsSpacingModifierLetters

0300 - 036F IsCombiningDiacriticalMarks

0370 - 03FF IsGreek

o bien

IsGreekandCoptic

0400 - 04FF IsCyrillic

0500 - 052F IsCyrillicSupplement

0530 - 058F IsArmenian


INTERVALO DE PUNTOS DE CÓDIGO NOMBRE DEL BLOQUE

0590 - 05FF IsHebrew

0600 - 06FF IsArabic

0700 - 074F IsSyriac

0780 - 07BF IsThaana

0900 - 097F IsDevanagari

0980 - 09FF IsBengali

0A00 - 0A7F IsGurmukhi

0A80 - 0AFF IsGujarati

0B00 - 0B7F IsOriya

0B80 - 0BFF IsTamil

0C00 - 0C7F IsTelugu

0C80 - 0CFF IsKannada

0D00 - 0D7F IsMalayalam

0D80 - 0DFF IsSinhala

0E00 - 0E7F IsThai

0E80 - 0EFF IsLao

0F00 - 0FFF IsTibetan

1000 - 109F IsMyanmar

10A0 - 10FF IsGeorgian

1100 - 11FF IsHangulJamo

1200 - 137F IsEthiopic

13A0 - 13FF IsCherokee

1400 - 167F IsUnifiedCanadianAboriginalSyllabics

1680 - 169F IsOgham


INTERVALO DE PUNTOS DE CÓDIGO NOMBRE DEL BLOQUE

16A0 - 16FF IsRunic

1700 - 171F IsTagalog

1720 - 173F IsHanunoo

1740 - 175F IsBuhid

1760 - 177F IsTagbanwa

1780 - 17FF IsKhmer

1800 - 18AF IsMongolian

1900 - 194F IsLimbu

1950 - 197F IsTaiLe

19E0 - 19FF IsKhmerSymbols

1D00 - 1D7F IsPhoneticExtensions

1E00 - 1EFF IsLatinExtendedAdditional

1F00 - 1FFF IsGreekExtended

2000 - 206F IsGeneralPunctuation

2070 - 209F IsSuperscriptsandSubscripts

20A0 - 20CF IsCurrencySymbols

20D0 - 20FF IsCombiningDiacriticalMarksforSymbols

o bien

IsCombiningMarksforSymbols

2100 - 214F IsLetterlikeSymbols

2150 - 218F IsNumberForms

2190 - 21FF IsArrows

2200 - 22FF IsMathematicalOperators

2300 - 23FF IsMiscellaneousTechnical

2400 - 243F IsControlPictures


INTERVALO DE PUNTOS DE CÓDIGO NOMBRE DEL BLOQUE

2440 - 245F IsOpticalCharacterRecognition

2460 - 24FF IsEnclosedAlphanumerics

2500 - 257F IsBoxDrawing

2580 - 259F IsBlockElements

25A0 - 25FF IsGeometricShapes

2600 - 26FF IsMiscellaneousSymbols

2700 - 27BF IsDingbats

27C0 - 27EF IsMiscellaneousMathematicalSymbols-A

27F0 - 27FF IsSupplementalArrows-A

2800 - 28FF IsBraillePatterns

2900 - 297F IsSupplementalArrows-B

2980 - 29FF IsMiscellaneousMathematicalSymbols-B

2A00 - 2AFF IsSupplementalMathematicalOperators

2B00 - 2BFF IsMiscellaneousSymbolsandArrows

2E80 - 2EFF IsCJKRadicalsSupplement

2F00 - 2FDF IsKangxiRadicals

2FF0 - 2FFF IsIdeographicDescriptionCharacters

3000 - 303F IsCJKSymbolsandPunctuation

3040 - 309F IsHiragana

30A0 - 30FF IsKatakana

3100 - 312F IsBopomofo

3130 - 318F IsHangulCompatibilityJamo

3190 - 319F IsKanbun

31A0 - 31BF IsBopomofoExtended


INTERVALO DE PUNTOS DE CÓDIGO NOMBRE DEL BLOQUE

31F0 - 31FF IsKatakanaPhoneticExtensions

3200 - 32FF IsEnclosedCJKLettersandMonths

3300 - 33FF IsCJKCompatibility

3400 - 4DBF IsCJKUnifiedIdeographsExtensionA

4DC0 - 4DFF IsYijingHexagramSymbols

4E00 - 9FFF IsCJKUnifiedIdeographs

A000 - A48F IsYiSyllables

A490 - A4CF IsYiRadicals

AC00 - D7AF IsHangulSyllables

D800 - DB7F IsHighSurrogates

DB80 - DBFF IsHighPrivateUseSurrogates

DC00 - DFFF IsLowSurrogates

E000 - F8FF IsPrivateUse o IsPrivateUseArea

F900 - FAFF IsCJKCompatibilityIdeographs

FB00 - FB4F IsAlphabeticPresentationForms

FB50 - FDFF IsArabicPresentationForms-A

FE00 - FE0F IsVariationSelectors

FE20 - FE2F IsCombiningHalfMarks

FE30 - FE4F IsCJKCompatibilityForms

FE50 - FE6F IsSmallFormVariants

FE70 - FEFF IsArabicPresentationForms-B

FF00 - FFEF IsHalfwidthandFullwidthForms

FFF0 - FFFF IsSpecials

Sustracción de clases de caracteres: [grupo_base - [grupo_excluido]]


Una clase de caracteres define un conjunto de caracteres. La sustracción de clases de caracteres genera un
conjunto de caracteres que es el resultado de excluir los caracteres de una clase de caracteres de otra clase de
caracteres.
Una expresión de sustracción de clases de caracteres tiene el formato siguiente:
[ base_group -[ excluded_group ]]

Los corchetes ( [] ) y el guion ( - ) son obligatorios. El grupo_base es un grupo de caracteres positivos o un


grupo de caracteres negativos. El componente grupo_excluido es otro grupo de caracteres positivos o negativos,
u otra expresión de sustracción de clases de caracteres (es decir, pueden anidarse expresiones de sustracción de
clases de caracteres).
Por ejemplo, supongamos que tiene un grupo base formado por el intervalo de caracteres de "a" a "z". Para
definir el conjunto de caracteres formado por el grupo base, salvo el carácter "m", utilice [a-z-[m]] . Para definir
el conjunto de caracteres formado por el grupo base, salvo el conjunto de caracteres "d", "j" y "p", utilice
[a-z-[djp]] . Para definir el conjunto de caracteres formado por el grupo base, salvo el intervalo de caracteres
de "m" a "p", utilice [a-z-[m-p]] .
Considere la expresión de sustracción de clases de caracteres anidada [a-z-[d-w-[m-o]]] . La expresión se evalúa
desde el intervalo de caracteres más profundo hacia el exterior. Primero, el intervalo de caracteres de "m" a "o"
se resta del intervalo de caracteres de "d" a "w", lo que da como resultado el conjunto de caracteres de "d" a "l" y
de "p" a "w". A continuación, ese conjunto se resta del intervalo de caracteres de "a" a "z", lo que da lugar al
conjunto de caracteres [abcmnoxyz] .
Puede utilizar cualquier clase de caracteres con la sustracción de clases de caracteres. Para definir el conjunto de
caracteres formado por todos los caracteres Unicode desde \u0000 hasta \uFFFF, a excepción de los caracteres
de espacio en blanco ( \s ), los caracteres de la categoría general de puntuación ( \p{P} ), los caracteres del
bloque con nombre IsGreek ( \p{IsGreek} ) y el carácter de control Unicode NEXT LINE (\x85), use
[\u0000-\uFFFF-[\s\p{P}\p{IsGreek}\x85]] .

Elija las clases de caracteres para que una expresión de sustracción de clases de caracteres produzca resultados
satisfactorios. Evite el uso de expresiones que produzcan un conjunto vacío de caracteres, que no coincidan con
nada, o expresiones equivalentes al grupo base original. Por ejemplo, el conjunto vacío es el resultado de la
expresión [\p{IsBasicLatin}-[\x00-\x7F]] , que resta todos los caracteres del intervalo de caracteres
IsBasicLatin de la categoría general IsBasicLatin . Ocurre lo mismo con el grupo base original, que es el
resultado de la expresión [a-z-[0-9]] . Esto se debe a que el grupo base, que está formado por el intervalo de
caracteres comprendido entre las letras de la "a" a la "z", no contiene ningún carácter del grupo excluido, que es
el intervalo de caracteres formado por los dígitos decimales del "0" al "9".
En el ejemplo siguiente se define una expresión regular, ^[0-9-[2468]]+$ , que coincide con cero y con los dígitos
impares de una cadena de entrada. La expresión regular se interpreta como se muestra en la tabla siguiente.

ELEMENTO DESCRIPCIÓN

^ Comienza la búsqueda de coincidencias al principio de la


cadena de entrada.

[0-9-[2468]]+ Coincide con una o varias apariciones de cualquier carácter


del 0 al 9, salvo con el 2, 4, 6 y 8. En otras palabras, busca
una o varias coincidencias con cero o un dígito impar.

$ Finalizar la búsqueda de coincidencias al final de la cadena de


entrada.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "123", "13579753", "3557798", "335599901" };
string pattern = @"^[0-9-[2468]]+$";

foreach (string input in inputs)


{
Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine(match.Value);
}
}
}
// The example displays the following output:
// 13579753
// 335599901

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "123", "13579753", "3557798", "335599901" }
Dim pattern As String = "^[0-9-[2468]]+$"

For Each input As String In inputs


Dim match As Match = Regex.Match(input, pattern)
If match.Success Then Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' 13579753
' 335599901

Vea también
GetUnicodeCategory
Lenguaje de expresiones regulares: referencia rápida
Opciones de expresiones regulares
Delimitadores en expresiones regulares
13/01/2020 • 30 minutes to read • Edit Online

Los delimitadores, o aserciones atómicas de ancho cero, especifican la posición de la cadena en que se debe
producir una coincidencia. Cuando se usa un delimitador en una expresión de búsqueda, el motor de expresiones
regulares no avanza por la cadena o ni consume caracteres, sino que solo busca una coincidencia en la posición
especificada. Por ejemplo, ^ especifica que la coincidencia debe empezar al principio de una cadena o línea. Por
consiguiente, la expresión regular ^http: coincide con "http": solo cuando se encuentra al principio de una línea.
En la tabla siguiente, se enumeran los delimitadores que admiten las expresiones regulares de .NET.

DELIMITADOR DESCRIPCIÓN

^ De forma predeterminada, la coincidencia se debe producir al


principio de la cadena. Por su parte, en el modo multilínea, se
debe producir al principio de la línea. Para obtener más
información, vea Principio de cadena o línea.

$ De forma predeterminada, la coincidencia se debe producir al


final de la cadena o antes de \n al final de la cadena. Por su
parte, en el modo multilínea, se debe producir al final de la
línea o antes de \n al final de la línea. Para obtener más
información, vea Final de cadena o línea.

\A La coincidencia se debe producir solo al principio de la cadena


(no se admiten varias líneas). Para obtener más información,
vea Principio de cadena solamente.

\Z La coincidencia se debe producir al final de la cadena o antes


de \n al final de la cadena. Para obtener más información,
vea Final de cadena o antes de nueva línea al final.

\z La coincidencia se debe producir solo al final de la cadena.


Para obtener más información, vea Final de cadena
solamente.

\G La coincidencia se debe iniciar en la posición en que finalizó la


coincidencia anterior. Para obtener más información, vea
Coincidencias contiguas.

\b La coincidencia se debe producir en un límite de palabras.


Para obtener más información, vea Límite de palabras.

\B La coincidencia no se debe producir en un límite de palabras.


Para obtener más información, vea Fuera de un límite de
palabras.

Principio de cadena o línea: ^


De forma predeterminada, el delimitador ^ especifica que el patrón siguiente debe comenzar en la posición del
primer carácter de la cadena. Si usa ^ con la opción RegexOptions.Multiline (vea Opciones de expresiones
regulares), la coincidencia se debe producir al principio de cada línea.
En el ejemplo siguiente se usa el delimitador ^ en una expresión regular que extrae información sobre los años
durante los que existieron algunos equipos de béisbol profesionales. En el ejemplo se llama a dos sobrecargas del
método Regex.Matches :
La llamada a la sobrecarga Matches(String, String) encuentra solo la primera subcadena que coincide con
el patrón de la expresión regular en la cadena de entrada.
La llamada a la sobrecarga Matches(String, String, RegexOptions) con el parámetro options establecido
en RegexOptions.Multiline encuentra las cinco subcadenas.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957\n" +
"Chicago Cubs, National League, 1903-present\n" +
"Detroit Tigers, American League, 1901-present\n" +
"New York Giants, National League, 1885-1957\n" +
"Washington Senators, American League, 1901-1960\n";
string pattern = @"^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+";
Match match;

match = Regex.Match(input, pattern);


while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();

match = Regex.Match(input, pattern, RegexOptions.Multiline);


while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();
}
}
// The example displays the following output:
// The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
//
// The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
// The Chicago Cubs played in the National League in 1903-present.
// The Detroit Tigers played in the American League in 1901-present.
// The New York Giants played in the National League in 1885-1957.
// The Washington Senators played in the American League in 1901-1960.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957" + vbCrLf +
"Chicago Cubs, National League, 1903-present" + vbCrLf +
"Detroit Tigers, American League, 1901-present" + vbCrLf +
"New York Giants, National League, 1885-1957" + vbCrLf +
"Washington Senators, American League, 1901-1960" + vbCrLf

Dim pattern As String = "^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+"


Dim match As Match

match = Regex.Match(input, pattern)


Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
match = match.NextMatch()
Loop
Console.WriteLine()

match = Regex.Match(input, pattern, RegexOptions.Multiline)


Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
match = match.NextMatch()
Loop
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
'
' The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
' The Chicago Cubs played in the National League in 1903-present.
' The Detroit Tigers played in the American League in 1901-present.
' The New York Giants played in the National League in 1885-1957.
' The Washington Senators played in the American League in 1901-1960.

El patrón de expresión regular ^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+ se define como se


muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Comienza la búsqueda de coincidencias al principio de la


cadena de entrada (o al principio de la línea si se llama al
método con la opción RegexOptions.Multiline ).

((\w+(\s?)){2,} Coincide con uno o varios caracteres que se usan para formar
palabras seguidos de cero o un espacio, al menos dos veces.
Este es el primer grupo de captura. Esta expresión también
define un segundo y tercer grupo de captura: El segundo
grupo está compuesto por la palabra capturada y el tercero
consta de los espacios en blanco capturados.
MODELO DESCRIPCIÓN

,\s Coincide con una coma seguida de un carácter de espacio en


blanco.

(\w+\s\w+) Coincide con uno o varios caracteres que se usan para formar
palabras seguidos de un espacio, seguidos de uno o varios
caracteres que se usan para formar palabras. Este es el cuarto
grupo de captura.

, Coincide con una coma.

\s\d{4} Coincide con un espacio seguido de cuatro dígitos decimales.

(-(\d{4}|present))? Coincide con cero o un guion seguido de cuatro dígitos


decimales o de la cadena "present". Este es el sexto grupo de
captura. También incluye un séptimo grupo de captura.

,? Coincide con una coma o ninguna.

(\s\d{4}(-(\d{4}|present))?,?)+ Coincide con una o más apariciones de lo siguiente: un


espacio, cuatro dígitos decimales, cero o un guion seguido de
cuatro dígitos decimales o de la cadena "present", y una coma
o ninguna. Este es el quinto grupo de captura.

Final de cadena o línea: $


El delimitador $ especifica que el patrón que le precede debe aparecer al final de la cadena de entrada o antes de
\n al final de la cadena de entrada.

Si usa $ con la opción RegexOptions.Multiline , la coincidencia también se puede producir al final de una línea.
Observe que $ coincide con \n , pero no coincide con \r\n (la combinación de caracteres de retorno de carro
y nueva línea, o CR/LF ). Para buscar la combinación de caracteres CR/LF, incluya \r?$ en el patrón de expresión
regular.
En el ejemplo siguiente se agrega el delimitador $ al patrón de expresión regular usado en el ejemplo de la
sección Principio de cadena o línea . Cuando se usa con la cadena de entrada original, que incluye cinco líneas de
texto, el método Regex.Matches(String, String) no puede encontrar una coincidencia, porque el final de la primera
línea no coincide con el patrón $ . Cuando la cadena de entrada original se divide en una matriz de cadenas, el
método Regex.Matches(String, String) consigue encontrar coincidencias en cada una de las cinco líneas. Cuando
se llama al método Regex.Matches(String, String, RegexOptions) con el parámetro options establecido en
RegexOptions.Multiline, no se encuentra ninguna coincidencia porque el patrón de la expresión regular no tiene
en cuenta el elemento de retorno de carro (\u+000D ). Sin embargo, cuando el patrón de la expresión regular se
modifica al remplazar $ por \r?$ , si se llama al método Regex.Matches(String, String, RegexOptions) con el
parámetro options establecido en RegexOptions.Multiline , ahora encuentra cinco coincidencias.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string cr = Environment.NewLine;
string input = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957" + cr +
"Chicago Cubs, National League, 1903-present" + cr +
"Detroit Tigers, American League, 1901-present" + cr +
"Detroit Tigers, American League, 1901-present" + cr +
"New York Giants, National League, 1885-1957" + cr +
"Washington Senators, American League, 1901-1960" + cr;
Match match;

string basePattern = @"^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+";


string pattern = basePattern + "$";
Console.WriteLine("Attempting to match the entire input string:");
match = Regex.Match(input, pattern);
while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();

string[] teams = input.Split(new String[] { cr }, StringSplitOptions.RemoveEmptyEntries);


Console.WriteLine("Attempting to match each element in a string array:");
foreach (string team in teams)
{
match = Regex.Match(team, pattern);
if (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);
Console.WriteLine(".");
}
}
Console.WriteLine();

Console.WriteLine("Attempting to match each line of an input string with '$':");


match = Regex.Match(input, pattern, RegexOptions.Multiline);
while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();

pattern = basePattern + "\r?$";


Console.WriteLine(@"Attempting to match each line of an input string with '\r?$':");
match = Regex.Match(input, pattern, RegexOptions.Multiline);
while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();
}
}
// The example displays the following output:
// Attempting to match the entire input string:
//
// Attempting to match each element in a string array:
// The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
// The Chicago Cubs played in the National League in 1903-present.
// The Detroit Tigers played in the American League in 1901-present.
// The New York Giants played in the National League in 1885-1957.
// The Washington Senators played in the American League in 1901-1960.
//
// Attempting to match each line of an input string with '$':
//
// Attempting to match each line of an input string with '\r?$':
// The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
// The Chicago Cubs played in the National League in 1903-present.
// The Detroit Tigers played in the American League in 1901-present.
// The New York Giants played in the National League in 1885-1957.
// The Washington Senators played in the American League in 1901-1960.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957" + vbCrLf +
"Chicago Cubs, National League, 1903-present" + vbCrLf +
"Detroit Tigers, American League, 1901-present" + vbCrLf +
"New York Giants, National League, 1885-1957" + vbCrLf +
"Washington Senators, American League, 1901-1960" + vbCrLf

Dim basePattern As String = "^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+"


Dim match As Match

Dim pattern As String = basePattern + "$"


Console.WriteLine("Attempting to match the entire input string:")
match = Regex.Match(input, pattern)
Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
match = match.NextMatch()
Loop
Console.WriteLine()

Dim teams() As String = input.Split(New String() {vbCrLf}, StringSplitOptions.RemoveEmptyEntries)


Console.WriteLine("Attempting to match each element in a string array:")
For Each team As String In teams
match = Regex.Match(team, pattern)
If match.Success Then
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
End If
Next
Console.WriteLine()

Console.WriteLine("Attempting to match each line of an input string with '$':")


match = Regex.Match(input, pattern, RegexOptions.Multiline)
Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
match = match.NextMatch()
Loop
Console.WriteLine()

pattern = basePattern + "\r?$"


Console.WriteLine("Attempting to match each line of an input string with '\r?$':")
match = Regex.Match(input, pattern, RegexOptions.Multiline)
Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")

match = match.NextMatch()
Loop
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' Attempting to match the entire input string:
'
' Attempting to match each element in a string array:
' The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
' The Chicago Cubs played in the National League in 1903-present.
' The Detroit Tigers played in the American League in 1901-present.
' The New York Giants played in the National League in 1885-1957.
' The Washington Senators played in the American League in 1901-1960.
'
' Attempting to match each line of an input string with '$':
'
' Attempting to match each line of an input string with '\r?$':
' The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.
' The Chicago Cubs played in the National League in 1903-present.
' The Detroit Tigers played in the American League in 1901-present.
' The New York Giants played in the National League in 1885-1957.
' The Washington Senators played in the American League in 1901-1960.

Principio de cadena solamente: \A


El delimitador \A especifica que debe producirse una coincidencia al principio de la cadena de entrada. Es
idéntico al delimitador ^ , salvo en que \A omite la opción RegexOptions.Multiline . Por consiguiente, solo
puede coincidir con el principio de la primera línea en una cadena de entrada de varias líneas.
El ejemplo siguiente es similar a los ejemplos de los delimitadores ^ y $ . Usa el delimitador \A en una
expresión regular que extrae información sobre los años durante los que existieron algunos equipos de béisbol
profesionales. La cadena de entrada incluye cinco líneas. La llamada al método Regex.Matches(String, String,
RegexOptions) encuentra solo la primera subcadena que coincide con el patrón de la expresión regular en la
cadena de entrada. Como muestra el ejemplo, la opción Multiline no tiene ningún efecto.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957\n" +
"Chicago Cubs, National League, 1903-present\n" +
"Detroit Tigers, American League, 1901-present\n" +
"New York Giants, National League, 1885-1957\n" +
"Washington Senators, American League, 1901-1960\n";

string pattern = @"\A((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+";

Match match = Regex.Match(input, pattern, RegexOptions.Multiline);


while (match.Success)
{
Console.Write("The {0} played in the {1} in",
match.Groups[1].Value, match.Groups[4].Value);
foreach (Capture capture in match.Groups[5].Captures)
Console.Write(capture.Value);

Console.WriteLine(".");
match = match.NextMatch();
}
Console.WriteLine();
}
}
// The example displays the following output:
// The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957" + vbCrLf +
"Chicago Cubs, National League, 1903-present" + vbCrLf +
"Detroit Tigers, American League, 1901-present" + vbCrLf +
"New York Giants, National League, 1885-1957" + vbCrLf +
"Washington Senators, American League, 1901-1960" + vbCrLf

Dim pattern As String = "\A((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+"

Dim match As Match = Regex.Match(input, pattern, RegexOptions.Multiline)


Do While match.Success
Console.Write("The {0} played in the {1} in",
match.Groups(1).Value, match.Groups(4).Value)
For Each capture As Capture In match.Groups(5).Captures
Console.Write(capture.Value)
Next
Console.WriteLine(".")
match = match.NextMatch()
Loop
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' The Brooklyn Dodgers played in the National League in 1911, 1912, 1932-1957.

Final de cadena o antes de nueva línea al final: \Z


El delimitador \Z especifica que se debe producir una coincidencia al final de la cadena de entrada o antes de
\n al final de la cadena de entrada. Es idéntico al delimitador $ , salvo en que \Z omite la opción
RegexOptions.Multiline . Por consiguiente, en una cadena de varias líneas, solo puede coincidir con el final de la
última línea o la última línea antes de \n .
Observe que \Z coincide con \n , pero no coincide con \r\n (la combinación de caracteres de retorno de carro
y nueva línea, o CR/LF ). Para buscar CR/LF, incluya \r?\Z en el patrón de expresión regular.
En el ejemplo siguiente, se usa el delimitador \Z en una expresión regular que es similar al ejemplo de la sección
Principio de cadena o línea , que extrae información sobre los años durante los que existieron algunos equipos del
béisbol profesionales. La subexpresión \r?\Z de la expresión regular
^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\Z coincide con el final de una cadena, y
también coincide con una cadena que termina por \n o \r\n . Como resultado, cada elemento de la matriz
coincide con el patrón de la expresión regular.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957",
"Chicago Cubs, National League, 1903-present" + Environment.NewLine,
"Detroit Tigers, American League, 1901-present" + Regex.Unescape(@"\n"),
"New York Giants, National League, 1885-1957",
"Washington Senators, American League, 1901-1960" + Environment.NewLine};
string pattern = @"^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\Z";

foreach (string input in inputs)


{
Console.WriteLine(Regex.Escape(input));
Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine(" Match succeeded.");
else
Console.WriteLine(" Match failed.");
}
}
}
// The example displays the following output:
// Brooklyn\ Dodgers,\ National\ League,\ 1911,\ 1912,\ 1932-1957
// Match succeeded.
// Chicago\ Cubs,\ National\ League,\ 1903-present\r\n
// Match succeeded.
// Detroit\ Tigers,\ American\ League,\ 1901-present\n
// Match succeeded.
// New\ York\ Giants,\ National\ League,\ 1885-1957
// Match succeeded.
// Washington\ Senators,\ American\ League,\ 1901-1960\r\n
// Match succeeded.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = {"Brooklyn Dodgers, National League, 1911, 1912, 1932-1957",
"Chicago Cubs, National League, 1903-present" + vbCrLf,
"Detroit Tigers, American League, 1901-present" + vbLf,
"New York Giants, National League, 1885-1957",
"Washington Senators, American League, 1901-1960" + vbCrLf}
Dim pattern As String = "^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\Z"

For Each input As String In inputs


Console.WriteLine(Regex.Escape(input))
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine(" Match succeeded.")
Else
Console.WriteLine(" Match failed.")
End If
Next
End Sub
End Module
' The example displays the following output:
' Brooklyn\ Dodgers,\ National\ League,\ 1911,\ 1912,\ 1932-1957
' Match succeeded.
' Chicago\ Cubs,\ National\ League,\ 1903-present\r\n
' Match succeeded.
' Detroit\ Tigers,\ American\ League,\ 1901-present\n
' Match succeeded.
' New\ York\ Giants,\ National\ League,\ 1885-1957
' Match succeeded.
' Washington\ Senators,\ American\ League,\ 1901-1960\r\n
' Match succeeded.

Final de cadena solamente: \z


El delimitador \z especifica que debe producirse una coincidencia al final de la cadena de entrada. Al igual que el
elemento del lenguaje $ , \z omite la opción RegexOptions.Multiline . A diferencia del elemento del lenguaje
\Z , \z no coincide con un carácter \n al final de una cadena. Por consiguiente, solo puede coincidir con la
última línea de la cadena de entrada.
En el ejemplo siguiente, se usa el delimitador \z en una expresión regular que por lo demás es idéntica al
ejemplo de la sección anterior, que extrae información sobre los años durante los que existieron algunos equipos
del béisbol profesionales. En el ejemplo, se intenta buscar coincidencias con cada uno de los cinco elementos de
una matriz de cadenas con el patrón de expresión regular
^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\z . Dos de las cadenas finalizan con caracteres
de retorno de carro y salto de línea, una finaliza con un carácter de salto de línea, y dos no finalizan con un
carácter de retorno de carro ni con un carácter de salto de línea. Como muestra la salida, solo coinciden con el
patrón las cadenas sin un carácter de retorno de carro ni de salto de línea.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "Brooklyn Dodgers, National League, 1911, 1912, 1932-1957",
"Chicago Cubs, National League, 1903-present" + Environment.NewLine,
"Detroit Tigers, American League, 1901-present\n",
"New York Giants, National League, 1885-1957",
"Washington Senators, American League, 1901-1960" + Environment.NewLine };
string pattern = @"^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\z";

foreach (string input in inputs)


{
Console.WriteLine(Regex.Escape(input));
Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine(" Match succeeded.");
else
Console.WriteLine(" Match failed.");
}
}
}
// The example displays the following output:
// Brooklyn\ Dodgers,\ National\ League,\ 1911,\ 1912,\ 1932-1957
// Match succeeded.
// Chicago\ Cubs,\ National\ League,\ 1903-present\r\n
// Match failed.
// Detroit\ Tigers,\ American\ League,\ 1901-present\n
// Match failed.
// New\ York\ Giants,\ National\ League,\ 1885-1957
// Match succeeded.
// Washington\ Senators,\ American\ League,\ 1901-1960\r\n
// Match failed.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = {"Brooklyn Dodgers, National League, 1911, 1912, 1932-1957",
"Chicago Cubs, National League, 1903-present" + vbCrLf,
"Detroit Tigers, American League, 1901-present" + vbLf,
"New York Giants, National League, 1885-1957",
"Washington Senators, American League, 1901-1960" + vbCrLf}
Dim pattern As String = "^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\z"

For Each input As String In inputs


Console.WriteLine(Regex.Escape(input))
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine(" Match succeeded.")
Else
Console.WriteLine(" Match failed.")
End If
Next
End Sub
End Module
' The example displays the following output:
' Brooklyn\ Dodgers,\ National\ League,\ 1911,\ 1912,\ 1932-1957
' Match succeeded.
' Chicago\ Cubs,\ National\ League,\ 1903-present\r\n
' Match failed.
' Detroit\ Tigers,\ American\ League,\ 1901-present\n
' Match failed.
' New\ York\ Giants,\ National\ League,\ 1885-1957
' Match succeeded.
' Washington\ Senators,\ American\ League,\ 1901-1960\r\n
' Match failed.

Coincidencias contiguas: \G
El delimitador \G especifica que debe producirse una coincidencia en el punto en el que finalizó la coincidencia
anterior. El uso de este delimitador con el método Regex.Matches o Match.NextMatch permite asegurarse de que
todas las coincidencias son contiguas.
En el ejemplo siguiente se usa una expresión regular para extraer los nombres de especies de roedores de una
cadena delimitada por comas.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "capybara,squirrel,chipmunk,porcupine,gopher," +
"beaver,groundhog,hamster,guinea pig,gerbil," +
"chinchilla,prairie dog,mouse,rat";
string pattern = @"\G(\w+\s?\w*),?";
Match match = Regex.Match(input, pattern);
while (match.Success)
{
Console.WriteLine(match.Groups[1].Value);
match = match.NextMatch();
}
}
}
// The example displays the following output:
// capybara
// squirrel
// chipmunk
// porcupine
// gopher
// beaver
// groundhog
// hamster
// guinea pig
// gerbil
// chinchilla
// prairie dog
// mouse
// rat

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "capybara,squirrel,chipmunk,porcupine,gopher," +
"beaver,groundhog,hamster,guinea pig,gerbil," +
"chinchilla,prairie dog,mouse,rat"
Dim pattern As String = "\G(\w+\s?\w*),?"
Dim match As Match = Regex.Match(input, pattern)
Do While match.Success
Console.WriteLine(match.Groups(1).Value)
match = match.NextMatch()
Loop
End Sub
End Module
' The example displays the following output:
' capybara
' squirrel
' chipmunk
' porcupine
' gopher
' beaver
' groundhog
' hamster
' guinea pig
' gerbil
' chinchilla
' prairie dog
' mouse
' rat
La expresión regular \G(\w+\s?\w*),? se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\G Comienza donde finalizó la última coincidencia.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

\s? Coincide con cero o un espacio.

\w* Buscar una coincidencia con cero o más caracteres alfabéticos.

(\w+\s?\w*) Coincide con uno o varios caracteres que se usan para formar
palabras seguidos de cero o un espacio, seguidos de cero o
más caracteres que se usan para formar palabras. Este es el
primer grupo de captura.

,? Coincide con cero o un carácter de coma literal.

Límite de palabras: \b
El delimitador \b especifica que la coincidencia se debe producir en un límite entre un carácter que se usa para
formar palabras (el elemento del lenguaje \w ) y un carácter que no se usa para formar palabras (el elemento del
lenguaje \W ). Los caracteres que se usan para formar palabras son los caracteres alfanuméricos y de subrayado;
un carácter que no se usa para formar palabras es cualquier carácter que no es alfanumérico ni de subrayado.
(Para más información, vea Clases de carácter). La coincidencia también se puede producir en un límite de
palabras al principio o al final de la cadena.
El delimitador \b se usa con frecuencia para asegurarse de que una subexpresión coincide con una palabra
completa en lugar de solo con el principio o el final de una palabra. La expresión regular \bare\w*\b del ejemplo
siguiente muestra este uso. Coincide con cualquier palabra que comience por la subcadena "are". El resultado del
ejemplo también muestra que \b coincide tanto con el principio como con el final de la cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "area bare arena mare";
string pattern = @"\bare\w*\b";
Console.WriteLine("Words that begin with 'are':");
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index);
}
}
// The example displays the following output:
// Words that begin with 'are':
// 'area' found at position 0
// 'arena' found at position 10
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "area bare arena mare"
Dim pattern As String = "\bare\w*\b"
Console.WriteLine("Words that begin with 'are':")
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Words that begin with 'are':
' 'area' found at position 0
' 'arena' found at position 10

El patrón de la expresión regular se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

are Coincide con la subcadena "are".

\w* Buscar una coincidencia con cero o más caracteres alfabéticos.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Fuera de un límite de palabras: \B


El delimitador \B especifica que la coincidencia no se debe producir en un límite de palabras. Es lo contrario del
delimitador \b .
En el ejemplo siguiente, se usa el delimitador \B para buscar apariciones de la subcadena "qu" en una palabra. El
patrón de expresión regular \Bqu\w+ coincide con una subcadena que comienza por "qu" que no está al principio
de una palabra y que continúa hasta el final de la palabra.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "equity queen equip acquaint quiet";
string pattern = @"\Bqu\w+";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index);
}
}
// The example displays the following output:
// 'quity' found at position 1
// 'quip' found at position 14
// 'quaint' found at position 21
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "equity queen equip acquaint quiet"
Dim pattern As String = "\Bqu\w+"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' 'quity' found at position 1
' 'quip' found at position 14
' 'quaint' found at position 21

El patrón de la expresión regular se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\B La búsqueda de coincidencias no comienza en un límite de


palabras.

qu Coincide con la subcadena "qu".

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

Vea también
Lenguaje de expresiones regulares: referencia rápida
Opciones de expresiones regulares
Construcciones de agrupamiento en expresiones
regulares
22/01/2020 • 66 minutes to read • Edit Online

Las construcciones de agrupamiento definen las subexpresiones de una expresión regular y capturan las
subcadenas de una cadena de entrada. Puede utilizar construcciones de agrupamiento para hacer lo siguiente:
Buscar una subexpresión que se repite en la cadena de entrada.
Aplicar un cuantificador a una subexpresión que tiene varios elementos del lenguaje de expresiones
regulares. Para más información sobre los cuantificadores, vea Quantifiers.
Incluir una subexpresión en la cadena devuelta por los métodos Regex.Replace y Match.Result .
Recuperar subexpresiones individuales de la propiedad Match.Groups y procesarlas por separado del
texto coincidente en su conjunto.
En la tabla siguiente se enumeran las construcciones de agrupamiento admitidas por el motor de expresiones
regulares de .NET y se indica si son de captura o sin captura.

CONSTRUCCIÓN DE AGRUPAMIENTO DE CAPTURA O SIN CAPTURA

Subexpresiones coincidentes Capturando

Subexpresiones coincidentes con nombre Capturando

Definiciones de grupos de compensación Capturando

Grupos sin captura Sin captura

Opciones de grupo Sin captura

Aserciones de búsqueda anticipada positiva de ancho cero Sin captura

Aserciones de búsqueda anticipada negativa de ancho cero Sin captura

Aserciones de búsqueda tardía positiva de ancho cero Sin captura

Aserciones de búsqueda tardía negativa de ancho cero Sin captura

Subexpresiones sin retroceso Sin captura

Para obtener información sobre los grupos y el modelo de objetos de expresiones regulares, vea
Construcciones de agrupamiento y objetos de las expresiones regulares.

Subexpresiones coincidentes
La construcción de agrupación siguiente captura una subexpresión coincidente:
( subexpresión )
donde subexpresión es cualquier patrón de expresión regular válido. Las capturas que usan paréntesis se
numeran automáticamente de izquierda a derecha según el orden de los paréntesis de apertura de la
expresión regular, empezando desde uno. La captura con el número cero es el texto coincidente con el patrón
de la expresión regular completa.

NOTE
De manera predeterminada, el elemento de lenguaje ( subexpresión ) captura la subexpresión coincidente. No
obstante, la subexpresión coincidente no se captura si el parámetro RegexOptions del método de coincidencia de
patrones de una expresión regular incluye la marca RegexOptions.ExplicitCapture o si se aplica la opción n a esta
subexpresión (vea Opciones de grupo más adelante en este tema).

Existen cuatro formas de tener acceso a los grupos capturados:


Usando la construcción de referencia inversa dentro de la expresión regular. Para hacer referencia a la
subexpresión coincidente desde la misma expresión regular, se usa la sintaxis \ número, donde
número es el número ordinal de la subexpresión capturada.
Usando la construcción de referencia inversa con nombre dentro de la expresión regular. Para hacer
referencia a la subexpresión coincidente desde la misma expresión regular, se usa la sintaxis \k<
nombre > , donde nombre es el nombre de un grupo de captura, o \k< número > , donde número es
el número ordinal de un grupo de captura. Un grupo de captura tiene un nombre predeterminado que
es idéntico a su número ordinal. Para obtener más información, vea Subexpresiones coincidentes con
nombre más adelante en este tema.
Usando la secuencia de reemplazo $ número en una llamada al método Regex.Replace o Match.Result
, donde número es el número ordinal de la subexpresión capturada.
Mediante programación, usando el objeto GroupCollection devuelto por la propiedad Match.Groups .
El miembro en la posición cero de la colección representa la coincidencia de la expresión regular
completa. Cada miembro subsiguiente representa una subexpresión coincidente. Para más
información, vea la sección Grouping Constructs and Regular Expression Objects .
En el ejemplo siguiente se muestra una expresión regular que identifica las palabras duplicadas en el texto.
Los dos grupos de captura del patrón de la expresión regular representan las dos instancias de la palabra
duplicada. La segunda instancia se captura para notificar su posición inicial en la cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(\w+)\s(\1)";
string input = "He said that that was the the correct answer.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.",
match.Groups[1].Value, match.Groups[1].Index, match.Groups[2].Index);
}
}
// The example displays the following output:
// Duplicate 'that' found at positions 8 and 13.
// Duplicate 'the' found at positions 22 and 26.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(\w+)\s(\1)\W"
Dim input As String = "He said that that was the the correct answer."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.", _
match.Groups(1).Value, match.Groups(1).Index, match.Groups(2).Index)
Next
End Sub
End Module
' The example displays the following output:
' Duplicate 'that' found at positions 8 and 13.
' Duplicate 'the' found at positions 22 and 26.

El patrón de la expresión regular es el siguiente:


(\w+)\s(\1)\W

En la siguiente tabla se muestra cómo se interpreta el patrón de expresión regular.

MODELO DESCRIPCIÓN

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este es el primer grupo de captura.

\s Coincide con un carácter de espacio en blanco.

(\1) Coincide con la cadena del primer grupo capturado. Este es


el segundo grupo de captura. El ejemplo lo asigna a un
grupo capturado de forma que la posición inicial de la
palabra duplicada se pueda recuperar de la propiedad
Match.Index .

\W Coincide con un carácter que no se usa para formar


palabras, como los espacios en blanco y los signos de
puntuación. Esto evita que el patrón de la expresión regular
coincida con una palabra que comience por la palabra del
primer grupo capturado.

Subexpresiones coincidentes con nombre


La construcción de agrupamiento siguiente captura una subexpresión coincidente y permite tener acceso a
ella por nombre o por número:
(?<name>subexpression)

O bien
(?'name'subexpression)

donde nombre es un nombre de grupo válido, y subexpresión es cualquier patrón de expresión regular válido.
nombre no debe contener ningún carácter de puntuación y no puede comenzar por un número.
NOTE
Si el parámetro RegexOptions del método de coincidencia de patrones de una expresión regular incluye la marca
RegexOptions.ExplicitCapture o si se aplica la opción n a esta subexpresión (vea Opciones de grupo más adelante en
este tema), la única forma de capturar una subexpresión es asignar nombres explícitamente a los grupos de captura.

Puede tener acceso a los grupos capturados con nombre de las maneras siguientes:
Usando la construcción de referencia inversa con nombre dentro de la expresión regular. Para hacer
referencia a la subexpresión coincidente desde la misma expresión regular, se usa la sintaxis \k<
nombre > , donde nombre es el nombre de la subexpresión capturada.
Usando la construcción de referencia inversa dentro de la expresión regular. Para hacer referencia a la
subexpresión coincidente desde la misma expresión regular, se usa la sintaxis \ número, donde
número es el número ordinal de la subexpresión capturada. Las subexpresiones coincidentes con
nombre se numeran consecutivamente de izquierda a derecha después de las subexpresiones
coincidentes.
Usando la secuencia de reemplazo ${ nombre } en una llamada al método Regex.Replace o
Match.Result , donde nombre es el nombre de la subexpresión capturada.
Usando la secuencia de reemplazo $ número en una llamada al método Regex.Replace o Match.Result
, donde número es el número ordinal de la subexpresión capturada.
Mediante programación, usando el objeto GroupCollection devuelto por la propiedad Match.Groups .
El miembro en la posición cero de la colección representa la coincidencia de la expresión regular
completa. Cada miembro subsiguiente representa una subexpresión coincidente. Los grupos
capturados con nombre se almacenan en la colección después de los grupos capturados numerados.
Mediante programación, proporcionando el nombre de la subexpresión al indizador del objeto
GroupCollection (en C#) o a su propiedad Item[String] (en Visual Basic).
Un patrón de expresión regular simple muestra cómo se puede hacer referencia a los grupos numerados (sin
nombre) y con nombre mediante programación o utilizando la sintaxis del lenguaje de expresiones regulares.
La expresión regular ((?<One>abc)\d+)?(?<Two>xyz)(.*) produce los siguientes grupos de captura por número
y por nombre. El primer grupo de captura (el número 0) siempre hace referencia al patrón completo.

NÚMERO NOMBRE MODELO

0 0 (nombre predeterminado) ((?<One>abc)\d+)?(?<Two>xyz)


(.*)

1 1 (nombre predeterminado) ((?<One>abc)\d+)

2 2 (nombre predeterminado) (.*)

3 Uno (?<One>abc)

4 Dos (?<Two>xyz)

En el ejemplo siguiente se muestra una expresión regular que identifica las palabras duplicadas y la palabra
que sigue inmediatamente a cada palabra duplicada. El patrón de la expresión regular define dos
subexpresiones con nombre: duplicateWord , que representa la palabra duplicada; y nextWord , que representa
la palabra que sigue a la palabra duplicada.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)";
string input = "He said that that was the the correct answer.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.",
match.Groups["duplicateWord"].Value, match.Groups["duplicateWord"].Index,
match.Groups["nextWord"].Value);
}
}
// The example displays the following output:
// A duplicate 'that' at position 8 is followed by 'was'.
// A duplicate 'the' at position 22 is followed by 'correct'.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)"
Dim input As String = "He said that that was the the correct answer."
Console.WriteLine(Regex.Matches(input, pattern, RegexOptions.IgnoreCase).Count)
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.", _
match.Groups("duplicateWord").Value, match.Groups("duplicateWord").Index, _
match.Groups("nextWord").Value)
Next
End Sub
End Module
' The example displays the following output:
' A duplicate 'that' at position 8 is followed by 'was'.
' A duplicate 'the' at position 22 is followed by 'correct'.

El patrón de la expresión regular es el siguiente:


(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)

La tabla siguiente muestra cómo se interpreta la expresión regular.

MODELO DESCRIPCIÓN

(?<duplicateWord>\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este grupo de captura se denomina duplicateWord .

\s Coincide con un carácter de espacio en blanco.

\k<duplicateWord> Coincide con la cadena del grupo capturado denominada


duplicateWord .

\W Coincide con un carácter que no se usa para formar


palabras, como los espacios en blanco y los signos de
puntuación. Esto evita que el patrón de la expresión regular
coincida con una palabra que comience por la palabra del
primer grupo capturado.
MODELO DESCRIPCIÓN

(?<nextWord>\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este grupo de captura se denomina nextWord .

Tenga en cuenta que un nombre de grupo se puede repetir en una expresión regular. Por ejemplo, es posible
que más de un grupo se llame digit , como muestra el ejemplo siguiente. En el caso de nombres duplicados,
el valor del objeto Group viene determinado por la última captura correcta en la cadena de entrada. Además,
la colección CaptureCollection se rellena con información de cada captura igual que si el nombre de grupo no
estuviera duplicado.
En el ejemplo siguiente, la expresión regular \D+(?<digit>\d+)\D+(?<digit>\d+)? incluye dos apariciones de
un grupo llamado digit . El primer grupo llamado digit captura uno o más caracteres de dígito. El segundo
grupo llamado digit captura cero o una aparición de uno o más caracteres de dígito. Tal y como muestra la
salida del ejemplo, si el segundo grupo de captura coincide correctamente con el texto, el valor de ese texto
define el valor del objeto Group . Si el segundo grupo de captura no coincide con la cadena de entrada, el
valor de la última coincidencia correcta define el valor del objeto Group .

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
String pattern = @"\D+(?<digit>\d+)\D+(?<digit>\d+)?";
String[] inputs = { "abc123def456", "abc123def" };
foreach (var input in inputs) {
Match m = Regex.Match(input, pattern);
if (m.Success) {
Console.WriteLine("Match: {0}", m.Value);
for (int grpCtr = 1; grpCtr < m.Groups.Count; grpCtr++) {
Group grp = m.Groups[grpCtr];
Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value);
for (int capCtr = 0; capCtr < grp.Captures.Count; capCtr++)
Console.WriteLine(" Capture {0}: {1}", capCtr,
grp.Captures[capCtr].Value);
}
}
else {
Console.WriteLine("The match failed.");
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// Match: abc123def456
// Group 1: 456
// Capture 0: 123
// Capture 1: 456
//
// Match: abc123def
// Group 1: 123
// Capture 0: 123
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\D+(?<digit>\d+)\D+(?<digit>\d+)?"
Dim inputs() As String = { "abc123def456", "abc123def" }
For Each input As String In inputs
Dim m As Match = Regex.Match(input, pattern)
If m.Success Then
Console.WriteLine("Match: {0}", m.Value)
For grpCtr As Integer = 1 to m.Groups.Count - 1
Dim grp As Group = m.Groups(grpCtr)
Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value)
For capCtr As Integer = 0 To grp.Captures.Count - 1
Console.WriteLine(" Capture {0}: {1}", capCtr,
grp.Captures(capCtr).Value)
Next
Next
Else
Console.WriteLine("The match failed.")
End If
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Match: abc123def456
' Group 1: 456
' Capture 0: 123
' Capture 1: 456
'
' Match: abc123def
' Group 1: 123
' Capture 0: 123

La tabla siguiente muestra cómo se interpreta la expresión regular.

MODELO DESCRIPCIÓN

\D+ Coincide con uno o más caracteres de dígito no decimal.

(?<digit>\d+) Coincide con uno o más caracteres de dígito decimal.


Asigna la coincidencia al grupo llamado digit .

\D+ Coincide con uno o más caracteres de dígito no decimal.

(?<digit>\d+)? Coincide con ninguna o una aparición de uno o más


caracteres de dígito decimal. Asigna la coincidencia al grupo
llamado digit .

Definiciones de grupos de compensación


Una definición de grupo de compensación elimina la definición de un grupo definido anteriormente y
almacena, en el grupo actual, el intervalo entre el grupo definido anteriormente y el grupo actual. Esta
construcción de agrupamiento tiene el formato siguiente:
(?<name1-name2>subexpression)

O bien
(?'name1-name2' subexpression)

donde nombre1 es el grupo actual (opcional), nombre2 es un grupo definido previamente y subexpresión es
cualquier patrón de expresión regular válido. La definición de grupo de compensación elimina la definición de
nombre2 y almacena el intervalo entre nombre2 y nombre1 en nombre1. Si no se ha definido el grupo
nombre2 , la búsqueda de coincidencias retrocede. Como al eliminar la última definición de nombre2 se
revela la definición anterior de nombre2, esta construcción permite usar la pila de capturas del grupo
nombre2 como contador para realizar el seguimiento de construcciones anidadas como paréntesis o
corchetes de apertura y cierre.
La definición del grupo de compensación utiliza nombre2 como pila. El carácter inicial de cada construcción
anidada se coloca en el grupo y en su colección Group.Captures . Cuando se encuentra una coincidencia con
el carácter de cierre, el carácter de apertura correspondiente se quita del grupo, y la colección Captures
disminuye en una unidad. Después de buscar las coincidencias con los caracteres de apertura y cierre de
todas las construcciones anidadas, nombre2 estará vacío.

NOTE
Después de modificar la expresión regular del ejemplo siguiente para que utilice el carácter de apertura y cierre
adecuado de una construcción anidada, puede utilizarla con la mayoría de las estructuras anidadas, como expresiones
matemáticas o líneas de código de programa que incluyen varias llamadas a métodos anidadas.

En el ejemplo siguiente se usa una definición de grupo de compensación para que coincida con los corchetes
angulares de apertura y de cierre (<>) de una cadena de entrada. En el ejemplo se definen dos grupos con
nombre, Open y Close , que se utilizan como una pila para realizar el seguimiento de los pares de corchetes
angulares coincidentes. Cada corchete angular de apertura capturado se inserta en la colección de captura del
grupo Open , y cada corchete angular de cierre capturado se inserta en la colección de captura del grupo
Close . Mediante la definición del grupo de compensación se comprueba que haya un corchete angular de
cierre para cada corchete angular de apertura. Si no lo hay, el subpatrón final, (?(Open)(?!)) , se evalúa solo
si el grupo Open no está vacío (y, por consiguiente, si no se han cerrado todas las construcciones anidadas).
Si se evalúa el subpatrón final, la coincidencia produce un error, porque el subpatrón (?!) es una aserción de
búsqueda anticipada negativa de ancho cero que siempre produce un error.
using System;
using System.Text.RegularExpressions;

class Example
{
public static void Main()
{
string pattern = "^[^<>]*" +
"(" +
"((?'Open'<)[^<>]*)+" +
"((?'Close-Open'>)[^<>]*)+" +
")*" +
"(?(Open)(?!))$";
string input = "<abc><mno<xyz>>";

Match m = Regex.Match(input, pattern);


if (m.Success == true)
{
Console.WriteLine("Input: \"{0}\" \nMatch: \"{1}\"", input, m);
int grpCtr = 0;
foreach (Group grp in m.Groups)
{
Console.WriteLine(" Group {0}: {1}", grpCtr, grp.Value);
grpCtr++;
int capCtr = 0;
foreach (Capture cap in grp.Captures)
{
Console.WriteLine(" Capture {0}: {1}", capCtr, cap.Value);
capCtr++;
}
}
}
else
{
Console.WriteLine("Match failed.");
}
}
}
// The example displays the following output:
// Input: "<abc><mno<xyz>>"
// Match: "<abc><mno<xyz>>"
// Group 0: <abc><mno<xyz>>
// Capture 0: <abc><mno<xyz>>
// Group 1: <mno<xyz>>
// Capture 0: <abc>
// Capture 1: <mno<xyz>>
// Group 2: <xyz
// Capture 0: <abc
// Capture 1: <mno
// Capture 2: <xyz
// Group 3: >
// Capture 0: >
// Capture 1: >
// Capture 2: >
// Group 4:
// Group 5: mno<xyz>
// Capture 0: abc
// Capture 1: xyz
// Capture 2: mno<xyz>
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^[^<>]*" & _
"(" + "((?'Open'<)[^<>]*)+" & _
"((?'Close-Open'>)[^<>]*)+" + ")*" & _
"(?(Open)(?!))$"
Dim input As String = "<abc><mno<xyz>>"
Dim rgx AS New Regex(pattern)'
Dim m As Match = Regex.Match(input, pattern)
If m.Success Then
Console.WriteLine("Input: ""{0}"" " & vbCrLf & "Match: ""{1}""", _
input, m)
Dim grpCtr As Integer = 0
For Each grp As Group In m.Groups
Console.WriteLine(" Group {0}: {1}", grpCtr, grp.Value)
grpCtr += 1
Dim capCtr As Integer = 0
For Each cap As Capture In grp.Captures
Console.WriteLine(" Capture {0}: {1}", capCtr, cap.Value)
capCtr += 1
Next
Next
Else
Console.WriteLine("Match failed.")
End If
End Sub
End Module
' The example displays the following output:
' Input: "<abc><mno<xyz>>"
' Match: "<abc><mno<xyz>>"
' Group 0: <abc><mno<xyz>>
' Capture 0: <abc><mno<xyz>>
' Group 1: <mno<xyz>>
' Capture 0: <abc>
' Capture 1: <mno<xyz>>
' Group 2: <xyz
' Capture 0: <abc
' Capture 1: <mno
' Capture 2: <xyz
' Group 3: >
' Capture 0: >
' Capture 1: >
' Capture 2: >
' Group 4:
' Group 5: mno<xyz>
' Capture 0: abc
' Capture 1: xyz
' Capture 2: mno<xyz>

El patrón de la expresión regular es:


^[^<>]*(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)*(?(Open)(?!))$

La expresión regular se interpreta como sigue:

MODELO DESCRIPCIÓN

^ Comienza al principio de la cadena.

[^<>]* Coincide con cero o más caracteres que no son corchetes


angulares de apertura o cierre.
MODELO DESCRIPCIÓN

(?'Open'<) Coincide con un corchete angular de apertura y se lo


asigna a un grupo denominado Open .

[^<>]* Coincide con cero o más caracteres que no son corchetes


angulares de apertura o cierre.

((?'Open'<)[^<>]*)+ Coincide con una o más apariciones de un corchete angular


de apertura seguido de cero o más caracteres que no son
corchetes angulares de apertura o cierre. Este es el
segundo grupo de captura.

(?'Close-Open'>) Coincide con un corchete angular de cierre, asigna la


subcadena entre el grupo Open y el grupo actual al grupo
Close y elimina la definición del grupo Open .

[^<>]* Coincide con cero o más apariciones de cualquier carácter


que no sea un corchete angular de apertura ni de cierre.

((?'Close-Open'>)[^<>]*)+ Coincide con una o más apariciones de un corchete angular


de cierre, seguido de cero o más apariciones de cualquier
carácter que no sea un corchete angular de apertura ni de
cierre. Al buscar una coincidencia con el corchete angular
de cierre, asigna la subcadena entre el grupo Open y el
grupo actual al grupo Close , y elimina la definición del
grupo Open . Éste es el tercer grupo de captura.

(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)* Coincide con cero o más apariciones del patrón siguiente:


una o varias apariciones de un corchete angular de
apertura, seguidas de cero o más caracteres que no sean
corchetes angulares, seguidas de una o más apariciones de
un corchete angular de cierre, seguidas de cero o más
apariciones de caracteres que no sean corchetes angulares.
Al buscar una coincidencia con el corchete angular de
cierre, borra la definición del grupo Open y asigna la
subcadena entre el grupo Open y el grupo actual al grupo
Close . Este es el primer grupo de captura.

(?(Open)(?!)) Si existe el grupo Open , abandona la coincidencia si se


encuentra una cadena vacía, pero no avanza la posición del
motor de expresiones regulares en la cadena. Esta es una
aserción de búsqueda anticipada negativa de ancho cero.
Dado que siempre existe implícitamente una cadena vacía
en una cadena de entrada, esta coincidencia siempre
produce un error. Un error en esta coincidencia indica que
no hay el mismo número de corchetes angulares de
apertura y de cierre.

$ Coincide con el final de la cadena de entrada.

La subexpresión final, (?(Open)(?!)) , indica si las construcciones de anidamiento de la cadena de entrada


están compensadas correctamente (por ejemplo, si cada corchete angular de apertura coincide con un
corchete angular de cierre). Utiliza la coincidencia condicional basada en un grupo capturado válido; para más
información, vea Construcciones de alternancia. Si se define el grupo Open , el motor de expresiones
regulares intenta buscar la subexpresión (?!) en la cadena de entrada. El grupo Open solo se debería definir
si las construcciones de anidamiento están descompensadas. Por consiguiente, el patrón que se va a
comparar en la cadena de entrada debe ser uno que siempre produzca un error en la coincidencia. En este
caso, (?!) es una aserción de búsqueda anticipada negativa de ancho cero que siempre produce un error,
porque siempre existe implícitamente una cadena vacía en la posición siguiente de la cadena de entrada.
En el ejemplo, el motor de expresiones regulares evalúa la cadena de entrada "<abc><mno<xyz>>" como se
muestra en la tabla siguiente.

PASO MODELO RESULTADO

1 ^ Comienza la búsqueda de
coincidencias al principio de la cadena
de entrada

2 [^<>]* Busca caracteres que no sean


corchetes angulares antes del
corchete angular de apertura; no
encuentra ninguna coincidencia.

3 (((?'Open'<) Encuentra el corchete angular de


apertura de "<abc" y se lo asigna al
grupo Open .

4 [^<>]* Encuentra "abc".

5 )+ "<abc" es el valor del segundo grupo


capturado.

El carácter siguiente de la cadena de


entrada no es un corchete angular de
apertura, por lo que el motor de
expresiones regulares no retrocede al
subpatrón (?'Open'<)[^<>]*) .

6 ((?'Close-Open'>) Encuentra el corchete angular de


cierre de "<abc>", asigna "abc", que
es la subcadena entre el grupo Open
y el corchete angular de cierre, al
grupo Close , y elimina el valor
actual ("<") del grupo Open ,
dejándolo vacío.

7 [^<>]* Busca caracteres que no sean


corchetes angulares después del
corchete angular de cierre; no
encuentra ninguna coincidencia.

8 )+ El valor del tercer grupo capturado es


">".

El carácter siguiente de la cadena de


entrada no es un corchete angular de
cierre, por lo que el motor de
expresiones regulares no retrocede al
subpatrón
((?'Close-Open'>)[^<>]*) .
PASO MODELO RESULTADO

9 )* El valor del primer grupo capturado es


"<abc>".

El carácter siguiente de la cadena de


entrada es un corchete angular de
apertura, por lo que el motor de
expresiones regulares retrocede al
subpatrón (((?'Open'<) .

10 (((?'Open'<) Encuentra el corchete angular de


apertura de "<mno" y se lo asigna al
grupo Open . Su colección
Group.Captures ahora tiene un solo
valor, "<".

11 [^<>]* Encuentra "mno".

12 )+ "<mno" es el valor del segundo grupo


capturado.

El carácter siguiente de la cadena de


entrada es un corchete angular de
apertura, por lo que el motor de
expresiones regulares retrocede al
subpatrón (?'Open'<)[^<>]*) .

13 (((?'Open'<) Encuentra el corchete angular de


apertura de "<xyz>" y se lo asigna al
grupo Open . La colección
Group.Captures del grupo Open
ahora incluye dos capturas: el
corchete angular de apertura de "
<mno" y el corchete angular de
apertura de "<xyz>".

14 [^<>]* Encuentra "xyz".

15 )+ "<xyz" es el valor del segundo grupo


capturado.

El carácter siguiente de la cadena de


entrada no es un corchete angular de
apertura, por lo que el motor de
expresiones regulares no retrocede al
subpatrón (?'Open'<)[^<>]*) .
PASO MODELO RESULTADO

16 ((?'Close-Open'>) Coincide con el corchete angular de


cierre de "<xyz>". "xyz", asigna la
subcadena entre el grupo Open y el
corchete angular de cierre al grupo
Close , y elimina el valor actual del
grupo Open . El valor de la captura
anterior (el corchete angular de
apertura de "<mno") se convierte en
el valor actual del grupo Open . La
colección Captures del grupo Open
ahora incluye una única captura, el
corchete angular de apertura de "
<xyz>".

17 [^<>]* Busca caracteres que no sean


corchetes angulares; no encuentra
ninguna coincidencia.

18 )+ El valor del tercer grupo capturado es


">".

El carácter siguiente de la cadena de


entrada es un corchete angular de
cierre, por lo que el motor de
expresiones regulares retrocede al
subpatrón
((?'Close-Open'>)[^<>]*) .

19 ((?'Close-Open'>) Encuentra el último corchete angular


de cierre de "xyz>>", asigna
"mno<xyz>" (la subcadena entre el
grupo Open y el corchete angular de
cierre) al grupo Close y elimina el
valor actual del grupo Open . El
grupo Open está ahora vacío.

20 [^<>]* Busca caracteres que no sean


corchetes angulares; no encuentra
ninguna coincidencia.

21 )+ El valor del tercer grupo capturado es


">".

El carácter siguiente de la cadena de


entrada no es un corchete angular de
cierre, por lo que el motor de
expresiones regulares no retrocede al
subpatrón
((?'Close-Open'>)[^<>]*) .
PASO MODELO RESULTADO

22 )* El valor del primer grupo capturado es


"<mno<xyz>>".

El carácter siguiente de la cadena de


entrada no es un corchete angular de
apertura, por lo que el motor de
expresiones regulares no retrocede al
subpatrón (((?'Open'<) .

23 (?(Open)(?!)) El grupo Open no está definido, por


lo que no se intenta encontrar
ninguna coincidencia.

24 $ Encuentra el final de la cadena de


entrada.

Grupos sin captura


La construcción de agrupamiento siguiente no captura la subcadena con la que coincide una subexpresión:
(?:subexpression)

donde subexpresión es cualquier patrón de expresión regular válido. La construcción de grupo sin captura se
utiliza normalmente cuando un cuantificador se aplica a un grupo, pero las subcadenas capturadas por el
grupo no tienen ningún interés.

NOTE
Si una expresión regular incluye construcciones de agrupamiento anidadas, no se aplica una construcción de grupo sin
captura exterior a las construcciones de grupo anidadas interiores.

En el ejemplo siguiente se muestra una expresión regular que incluye grupos sin captura. Observe que la
salida no incluye ningún grupo capturado.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(?:\b(?:\w+)\W*)+\.";
string input = "This is a short sentence.";
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: {0}", match.Value);
for (int ctr = 1; ctr < match.Groups.Count; ctr++)
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups[ctr].Value);
}
}
// The example displays the following output:
// Match: This is a short sentence.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?:\b(?:\w+)\W*)+\."
Dim input As String = "This is a short sentence."
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: {0}", match.Value)
For ctr As Integer = 1 To match.Groups.Count - 1
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups(ctr).Value)
Next
End Sub
End Module
' The example displays the following output:
' Match: This is a short sentence.

La expresión regular (?:\b(?:\w+)\W*)+\. coincide con una frase que termina en un punto. Dado que la
expresión regular se centra en frases y no en palabras individuales, las construcciones de agrupamiento se
usan exclusivamente como cuantificadores. El patrón de la expresión regular se interpreta como se muestra
en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

(?:\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


No asigna el texto coincidente a un grupo capturado.

\W* Coincide con cero o más caracteres que no se usan para


formar palabras.

(?:\b(?:\w+)\W*)+ Coincide una o varias veces con el patrón de uno o varios


caracteres que se usan para formar palabras comenzando
por un límite de palabras, seguido de cero o más caracteres
que no se usan para formar palabras. No asigna el texto
coincidente a un grupo capturado.

\. Coincide con un punto.

Opciones de grupo
La siguiente construcción de agrupamiento aplica o deshabilita las opciones especificadas dentro de una
subexpresión:
(?imnsx-imnsx: subexpresión )

donde subexpresión es cualquier patrón de expresión regular válido. Por ejemplo, (?i-s:) activa la opción
que no hace distinción entre mayúsculas y minúsculas y deshabilita el modo de una sola línea. Para obtener
más información sobre las opciones insertadas que puede especificar, vea Opciones de expresiones regulares.
NOTE
Puede especificar opciones que se apliquen a una expresión regular completa en lugar de a una subexpresión usando
un constructor de la clase System.Text.RegularExpressions.Regex o un método estático. También puede especificar
opciones insertadas que se aplican después de un punto concreto en una expresión regular usando la construcción de
lenguaje (?imnsx-imnsx) .

La construcción de opciones de grupo no es un grupo de captura. Es decir, aunque cualquier parte de una
cadena capturada por subexpresión se incluye en la coincidencia, no se incluye en un grupo capturado ni se
usa para rellenar el objeto GroupCollection .
Por ejemplo, la expresión regular \b(?ix: d \w+)\s del ejemplo siguiente utiliza opciones insertadas en una
construcción de agrupamiento para habilitar la coincidencia sin distinción entre mayúsculas y minúsculas y
omitir el espacio en blanco del patrón para identificar todas las palabras que comienzan por la letra "d". La
expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

(?ix: d \w+) Usando una coincidencia sin distinción entre mayúsculas y


minúsculas y omitiendo los espacios en blanco en este
patrón, busca una "d" seguida de uno o varios caracteres
que se usan para formar palabras.

\s Coincide con un carácter de espacio en blanco.

string pattern = @"\b(?ix: d \w+)\s";


string input = "Dogs are decidedly good pets.";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index);
// The example displays the following output:
// 'Dogs // found at index 0.
// 'decidedly // found at index 9.

Dim pattern As String = "\b(?ix: d \w+)\s"


Dim input As String = "Dogs are decidedly good pets."

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Dogs ' found at index 0.
' 'decidedly ' found at index 9.

Aserciones de búsqueda anticipada positiva de ancho cero


La construcción de agrupamiento siguiente define una aserción de búsqueda anticipada positiva de ancho
cero:
(?= subexpresión )

donde subexpresión es cualquier patrón de expresión regular. Para que se produzca una coincidencia, la
cadena de entrada debe coincidir con el patrón de expresión regular de subexpresión, aunque la subcadena
coincidente no se incluya en el resultado de la coincidencia. Una aserción de búsqueda anticipada positiva de
ancho cero no retrocede.
Normalmente, una aserción de búsqueda anticipada positiva de ancho cero se encuentra al final de un patrón
de expresión regular. Define una subcadena que se debe encontrar al final de una cadena para que se
produzca una coincidencia, pero que no debe incluirse en la coincidencia. También resulta útil para evitar un
retroceso excesivo. Puede usar una aserción de búsqueda anticipada positiva de ancho cero para asegurarse
de que un grupo capturado determinado comienza por un texto que coincide con un subconjunto del patrón
definido para dicho grupo capturado. Por ejemplo, si un grupo de captura coincide con caracteres
consecutivos que se usan para formar palabras, puede usar una aserción de búsqueda anticipada positiva de
ancho cero para requerir que el primero de los caracteres sea alfabético y esté en mayúsculas.
En el ejemplo siguiente se usa una aserción de búsqueda anticipada positiva de ancho cero para buscar la
palabra que precede al verbo "is" en la cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b\w+(?=\sis\b)";
string[] inputs = { "The dog is a Malamute.",
"The island has beautiful birds.",
"The pitch missed home plate.",
"Sunday is a weekend day." };

foreach (string input in inputs)


{
Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine("'{0}' precedes 'is'.", match.Value);
else
Console.WriteLine("'{0}' does not match the pattern.", input);
}
}
}
// The example displays the following output:
// 'dog' precedes 'is'.
// 'The island has beautiful birds.' does not match the pattern.
// 'The pitch missed home plate.' does not match the pattern.
// 'Sunday' precedes 'is'.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b\w+(?=\sis\b)"
Dim inputs() As String = { "The dog is a Malamute.", _
"The island has beautiful birds.", _
"The pitch missed home plate.", _
"Sunday is a weekend day." }

For Each input As String In inputs


Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine("'{0}' precedes 'is'.", match.Value)
Else
Console.WriteLine("'{0}' does not match the pattern.", input)
End If
Next
End Sub
End Module
' The example displays the following output:
' 'dog' precedes 'is'.
' 'The island has beautiful birds.' does not match the pattern.
' 'The pitch missed home plate.' does not match the pattern.
' 'Sunday' precedes 'is'.

La expresión regular \b\w+(?=\sis\b) se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

(?=\sis\b) Determina si los caracteres que se usan para formar


palabras van seguidos de un carácter de espacio en blanco
y la cadena "is", seguida de un límite de palabras. En ese
caso, la coincidencia es correcta.

Aserciones de búsqueda anticipada negativa de ancho cero


La construcción de agrupamiento siguiente define una aserción de búsqueda anticipada negativa de ancho
cero:
(?! subexpresión )

donde subexpresión es cualquier patrón de expresión regular. Para que se produzca la coincidencia, la cadena
de entrada no debe coincidir con el patrón de expresión regular de subexpresión, aunque la cadena
coincidente no se incluya en el resultado de la coincidencia.
Una aserción de búsqueda anticipada negativa de ancho cero se utiliza normalmente al principio o al final de
una expresión regular. Al principio de una expresión regular, puede definir un patrón concreto que no se
debería buscar cuando el principio de la expresión regular define un patrón similar pero más general que se
desea buscar. En este caso, se usa a menudo para limitar el retroceso. Al final de una expresión regular, puede
definir una subexpresión que no se puede producir al final de una coincidencia.
En el ejemplo siguiente se define una expresión regular que utiliza una aserción de búsqueda anticipada
negativa de ancho cero al principio de la expresión regular para buscar palabras que no comienzan por "un".
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(?!un)\w+\b";
string input = "unite one unethical ethics use untie ultimate";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// one
// ethics
// use
// ultimate

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(?!un)\w+\b"
Dim input As String = "unite one unethical ethics use untie ultimate"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' one
' ethics
' use
' ultimate

La expresión regular \b(?!un)\w+\b se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

(?!un) Determina si los dos caracteres siguientes son "un". Si no lo


son, es posible una coincidencia.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

En el ejemplo siguiente se define una expresión regular que utiliza una aserción de búsqueda anticipada
negativa de ancho cero al final de la expresión regular para buscar palabras que no terminan por un carácter
de puntuación.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b\w+\b(?!\p{P})";
string input = "Disconnected, disjointed thoughts in a sentence fragment.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// disjointed
// thoughts
// in
// a
// sentence

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b\w+\b(?!\p{P})"
Dim input As String = "Disconnected, disjointed thoughts in a sentence fragment."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' disjointed
' thoughts
' in
' a
' sentence

La expresión regular \b\w+\b(?!\p{P}) se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

\p{P}) Si el carácter siguiente no es un signo de puntuación (como


un punto o una coma), la coincidencia se realiza.

Aserciones de búsqueda tardía positiva de ancho cero


La construcción de agrupamiento siguiente define una aserción de búsqueda tardía positiva de ancho cero:
(?<= subexpresión )

donde subexpresión es cualquier patrón de expresión regular. Para que se produzca una coincidencia,
subexpresión debe encontrarse en la cadena de entrada a la izquierda de la posición actual, aunque
subexpression no esté incluida en el resultado de la coincidencia. Una aserción de búsqueda tardía positiva
de ancho cero no retrocede.
Las aserciones de búsqueda tardía positiva de ancho cero se usan normalmente al principio de las
expresiones regulares. El patrón que definen es una condición previa de una coincidencia, aunque no forma
parte del resultado de la coincidencia.
Por ejemplo, el ejemplo siguiente coincide con los dos últimos dígitos del año para el siglo XXI (es decir,
requiere que los dígitos "20" precedan a la cadena coincidente).

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "2010 1999 1861 2140 2009";
string pattern = @"(?<=\b20)\d{2}\b";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// 10
// 09

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "2010 1999 1861 2140 2009"
Dim pattern As String = "(?<=\b20)\d{2}\b"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' 10
' 09

El patrón de la expresión regular (?<=\b20)\d{2}\b se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\d{2} Coincide con dos dígitos decimales.

(?<=\b20) Continúa la búsqueda si los dos dígitos decimales van


precedidos de los dos dígitos decimales "20" en un límite
de palabra.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Las aserciones de búsqueda tardía positiva de ancho cero también se usan para limitar el retroceso cuando el
último carácter o caracteres de un grupo capturado debe ser un subconjunto de los caracteres que coincide
con el patrón de la expresión regular de dicho grupo. Por ejemplo, si un grupo captura todos los caracteres
que se usan para formar palabras consecutivos, puede usar una aserción de búsqueda tardía positiva de
ancho cero para requerir que el último carácter sea alfabético.

Aserciones de búsqueda tardía negativa de ancho cero


La construcción de agrupamiento siguiente define una aserción de búsqueda tardía negativa de ancho cero:
(?<! subexpresión )

donde subexpresión es cualquier patrón de expresión regular. Para que se produzca una coincidencia,
subexpresión no debe encontrarse en la cadena de entrada a la izquierda de la posición actual. Sin embargo,
cualquier subcadena que no coincida con subexpression no se incluye en el resultado de la coincidencia.
Las aserciones de búsqueda tardía negativa de ancho cero se usan normalmente al principio de las
expresiones regulares. El patrón que definen impide una coincidencia en la cadena que sigue. También se
usan para limitar el retroceso cuando el último carácter o caracteres de un grupo capturado no debe ser uno
o varios de los caracteres que coinciden con el patrón de expresión regular de dicho grupo. Por ejemplo, si un
grupo captura todos los caracteres que se usan para formar palabras consecutivos, se puede usar una
aserción de búsqueda tardía positiva de ancho cero para requerir que el último carácter no sea de subrayado
(_ ).
El ejemplo siguiente busca la fecha de cualquier día de la semana que no sea fin de semana (es decir, que no
sea ni sábado ni domingo).

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] dates = { "Monday February 1, 2010",
"Wednesday February 3, 2010",
"Saturday February 6, 2010",
"Sunday February 7, 2010",
"Monday, February 8, 2010" };
string pattern = @"(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b";

foreach (string dateValue in dates)


{
Match match = Regex.Match(dateValue, pattern);
if (match.Success)
Console.WriteLine(match.Value);
}
}
}
// The example displays the following output:
// February 1, 2010
// February 3, 2010
// February 8, 2010
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim dates() As String = { "Monday February 1, 2010", _
"Wednesday February 3, 2010", _
"Saturday February 6, 2010", _
"Sunday February 7, 2010", _
"Monday, February 8, 2010" }
Dim pattern As String = "(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b"

For Each dateValue As String In dates


Dim match As Match = Regex.Match(dateValue, pattern)
If match.Success Then
Console.WriteLine(match.Value)
End If
Next
End Sub
End Module
' The example displays the following output:
' February 1, 2010
' February 3, 2010
' February 8, 2010

El patrón de la expresión regular (?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b se interpreta como se


muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

\w+ Coincide con uno o varios caracteres que se usan para


formar palabras seguidos de un carácter de espacio en
blanco.

\d{1,2}, Coincide con uno o dos dígitos decimales seguidos de un


carácter de espacio en blanco y una coma.

\d{4}\b Coincide con cuatro dígitos decimales seguidos de un límite


de palabras.

(?<!(Saturday|Sunday) ) Si la coincidencia va precedida por algo distinto de las


cadenas "Saturday" o "Sunday" seguidas de un espacio, la
coincidencia es correcta.

Subexpresiones sin retroceso


La construcción de agrupamiento siguiente representa una subexpresión sin retroceso (también conocida
como subexpresión "expansiva"):
(?> subexpresión )

donde subexpresión es cualquier patrón de expresión regular.


Comúnmente, si una expresión regular incluye un patrón de coincidencia opcional o alternativo y no se
produce una coincidencia, el motor de expresiones regulares puede crear una bifurcación en varias
direcciones para buscar coincidencias de una cadena de entrada con un patrón. Si no se encuentra una
coincidencia cuando toma la primera bifurcación, el motor de expresiones regulares puede regresar o
retroceder al punto donde tomó la primera bifurcación e intentar la coincidencia usando la segunda
bifurcación. Este proceso puede continuar hasta que se hayan probado todas las bifurcaciones.
El grupo (?> subexpresión ) deshabilita el retroceso. El motor de expresiones regulares buscará
coincidencias con tantos caracteres de la cadena de entrada como pueda. Cuando ya no sean posibles más
coincidencias, no retrocederá para intentar coincidencias con patrones alternativos. (Es decir, la subexpresión
solo busca cadenas que coincidan exclusivamente con la subexpresión; no intenta buscar una cadena
basándose en la subexpresión y en cualquier subexpresión que la siga).
Se recomienda usar esta opción si se sabe que el retroceso no tendrá éxito. Si se evita que el motor de
expresiones regulares realice búsquedas innecesarias, se mejora el rendimiento.
En el ejemplo siguiente se muestra cómo una subexpresión sin retroceso modifica los resultados de una
coincidencia de patrones. La expresión regular con retroceso coincide correctamente con una serie de
caracteres repetidos seguidos de una o varias apariciones del mismo carácter en un límite de palabras, pero la
expresión regular sin retroceso no lo hace.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "cccd.", "aaad", "aaaa" };
string back = @"(\w)\1+.\b";
string noback = @"(?>(\w)\1+).\b";

foreach (string input in inputs)


{
Match match1 = Regex.Match(input, back);
Match match2 = Regex.Match(input, noback);
Console.WriteLine("{0}: ", input);

Console.Write(" Backtracking : ");


if (match1.Success)
Console.WriteLine(match1.Value);
else
Console.WriteLine("No match");

Console.Write(" Nonbacktracking: ");


if (match2.Success)
Console.WriteLine(match2.Value);
else
Console.WriteLine("No match");
}
}
}
// The example displays the following output:
// cccd.:
// Backtracking : cccd
// Nonbacktracking: cccd
// aaad:
// Backtracking : aaad
// Nonbacktracking: aaad
// aaaa:
// Backtracking : aaaa
// Nonbacktracking: No match
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "cccd.", "aaad", "aaaa" }
Dim back As String = "(\w)\1+.\b"
Dim noback As String = "(?>(\w)\1+).\b"

For Each input As String In inputs


Dim match1 As Match = Regex.Match(input, back)
Dim match2 As Match = Regex.Match(input, noback)
Console.WriteLine("{0}: ", input)

Console.Write(" Backtracking : ")


If match1.Success Then
Console.WriteLine(match1.Value)
Else
Console.WriteLine("No match")
End If

Console.Write(" Nonbacktracking: ")


If match2.Success Then
Console.WriteLine(match2.Value)
Else
Console.WriteLine("No match")
End If
Next
End Sub
End Module
' The example displays the following output:
' cccd.:
' Backtracking : cccd
' Nonbacktracking: cccd
' aaad:
' Backtracking : aaad
' Nonbacktracking: aaad
' aaaa:
' Backtracking : aaaa
' Nonbacktracking: No match

La expresión regular sin retroceso (?>(\w)\1+).\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

(\w) Coincide con un único carácter que se usa para formar


palabras y se lo asigna al primer grupo de captura.

\1+ Coincide con el valor de la primera subcadena capturada


una o varias veces.

. Coincide con cualquier carácter.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

(?>(\w)\1+) Coincide con una o varias apariciones de un carácter que se


usa para formar palabras duplicado, pero no retrocede para
buscar el último carácter de un límite de palabras.

Construcciones de agrupamiento y objetos de las expresiones


regulares
Las subcadenas con las que coincide un grupo de captura de una expresión regular se representan mediante
objetos System.Text.RegularExpressions.Group , que se pueden recuperar del objeto
System.Text.RegularExpressions.GroupCollection que devuelve la propiedad Match.Groups . El objeto
GroupCollection se rellena como sigue:
El primer objeto Group de la colección (el objeto con el índice cero) representa la coincidencia
completa.
El siguiente conjunto de objetos Group representa los grupos de captura sin nombre (numerados).
Aparecen en el orden en el que se definen en la expresión regular, de izquierda a derecha. Los valores
de índice de estos grupos van de 1 al número de grupos de captura sin nombre de la colección. (El
índice de un grupo determinado es equivalente a su referencia inversa numerada. Para más
información sobre las referencias inversas, vea Construcciones de referencia inversa)).
El conjunto final de objetos Group representa los grupos de captura con nombre. Aparecen en el orden
en el que se definen en la expresión regular, de izquierda a derecha. El valor de índice del primer grupo
de captura con nombre es una unidad mayor que el índice del último grupo de captura sin nombre. Si
no hay ningún grupo de captura sin nombre en la expresión regular, el valor de índice del primer grupo
de captura con nombre es uno.
Si se aplica un cuantificador a un grupo de captura, las propiedades Group , Capture.Valuee Capture.Indexdel
objeto Capture.Length correspondiente reflejarán la última subcadena capturada por un grupo de captura. Se
puede recuperar un conjunto completo de subcadenas capturadas por grupos que tienen cuantificadores
desde el objeto CaptureCollection devuelto por la propiedad Group.Captures .
El ejemplo siguiente aclara la relación entre los objetos Group y Capture .
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(\b(\w+)\W+)+";
string input = "This is a short sentence.";
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: '{0}'", match.Value);
for (int ctr = 1; ctr < match.Groups.Count; ctr++)
{
Console.WriteLine(" Group {0}: '{1}'", ctr, match.Groups[ctr].Value);
int capCtr = 0;
foreach (Capture capture in match.Groups[ctr].Captures)
{
Console.WriteLine(" Capture {0}: '{1}'", capCtr, capture.Value);
capCtr++;
}
}
}
}
// The example displays the following output:
// Match: 'This is a short sentence.'
// Group 1: 'sentence.'
// Capture 0: 'This '
// Capture 1: 'is '
// Capture 2: 'a '
// Capture 3: 'short '
// Capture 4: 'sentence.'
// Group 2: 'sentence'
// Capture 0: 'This'
// Capture 1: 'is'
// Capture 2: 'a'
// Capture 3: 'short'
// Capture 4: 'sentence'
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(\b(\w+)\W+)+"
Dim input As String = "This is a short sentence."
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: '{0}'", match.Value)
For ctr As Integer = 1 To match.Groups.Count - 1
Console.WriteLine(" Group {0}: '{1}'", ctr, match.Groups(ctr).Value)
Dim capCtr As Integer = 0
For Each capture As Capture In match.Groups(ctr).Captures
Console.WriteLine(" Capture {0}: '{1}'", capCtr, capture.Value)
capCtr += 1
Next
Next
End Sub
End Module
' The example displays the following output:
' Match: 'This is a short sentence.'
' Group 1: 'sentence.'
' Capture 0: 'This '
' Capture 1: 'is '
' Capture 2: 'a '
' Capture 3: 'short '
' Capture 4: 'sentence.'
' Group 2: 'sentence'
' Capture 0: 'This'
' Capture 1: 'is'
' Capture 2: 'a'
' Capture 3: 'short'
' Capture 4: 'sentence'

El patrón de expresión regular (\b(\w+)\W+)+ extrae palabras individuales de una cadena. Se define como se
muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Juntos, estos caracteres forman una palabra. Este es el
segundo grupo de captura.

\W+ Coincide con uno o varios caracteres que no se usan para


formar palabras.

(\b(\w+)\W+) Coincide una o varias veces con el patrón de uno o varios


caracteres que se usan para formar palabras seguidos de
uno o varios caracteres que no se usan para formar
palabras. Este es el primer grupo de captura.

El segundo grupo de captura coincide con cada palabra de la frase. El primer grupo de captura coincide con
cada palabra, junto con la puntuación y el espacio en blanco que siguen a la palabra. El objeto Group cuyo
índice es 2 proporciona información sobre el texto coincidente con el segundo grupo de captura. El conjunto
de palabras completo capturado por el grupo de captura está disponible desde el objeto CaptureCollection
devuelto por la propiedad Group.Captures .

Vea también
Lenguaje de expresiones regulares: referencia rápida
Retroceso
cuantificadores en expresiones regulares
04/11/2019 • 35 minutes to read • Edit Online

Los cuantificadores especifican cuántas instancias de un carácter, grupo o clase de caracteres deben estar
presentes en la entrada para que se encuentre una coincidencia. En la tabla siguiente se indican los
cuantificadores compatibles con .NET.

CUANTIFICADOR EXPANSIVO CUANTIFICADOR DIFERIDO DESCRIPCIÓN

* *? Coincide cero o más veces.

+ +? Coincide una o más veces.

? ?? Coincide cero o una vez.

{ n } { n }? Coincide exactamente n veces.

{ n ,} { n ,}? Coincide al menos n veces.

{ n , m } { n , m }? Coincide de n a m veces.

Las cantidades n y m son constantes de tipo entero. Normalmente, los cuantificadores son expansivos, ya que
hacen que el motor de expresiones regulares busque el mayor número posible de repeticiones de patrones
concretos. Si se anexa el carácter ? a un cuantificador se convierte en diferido, ya que hace que el motor de
expresiones regulares busque el menor número posible de repeticiones. Para obtener una descripción completa
de la diferencia entre los cuantificadores expansivos y diferidos, consulte la sección Cuantificadores expansivos
y diferidos más adelante en este tema.

IMPORTANT
El anidamiento de cuantificadores (por ejemplo, como hace el patrón de expresión regular (a*)* ) puede aumentar el
número de comparaciones que debe realizar el motor de expresiones regulares, como una función exponencial del
número de caracteres de la cadena de entrada. Para obtener más información sobre este comportamiento y sus
soluciones alternativas, consulte Retroceso.

Cuantificadores de expresiones regulares


En las secciones siguientes se enumeran los cuantificadores admitidos en expresiones regulares de .NET.

NOTE
Si los caracteres *, +, ?, { y } se encuentran en un patrón de expresión regular, el motor de expresiones regulares los
interpreta como cuantificadores o como parte de construcciones de cuantificador, a menos que se incluyan en una clase
de caracteres. Para interpretarlos como caracteres literales fuera de una clase de caracteres, debe anteponerles una barra
diagonal inversa para indicar su secuencia de escape. Por ejemplo, la cadena \* en un patrón de expresión regular se
interpreta como un carácter de asterisco literal ("*").

Coincidir cero o más veces: *


El cuantificador * coincide con el elemento anterior cero o más veces. Equivale al cuantificador {0,} . * es
un cuantificador expansivo cuyo equivalente diferido es *? .
En el ejemplo siguiente se muestra esta expresión regular. De los nueve dígitos de la cadena de entrada, cinco
coinciden con el patrón y cuatro ( 95 , 929 , 9219 y 9919 ) no coinciden.

string pattern = @"\b91*9*\b";


string input = "99 95 919 929 9119 9219 999 9919 91119";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// '99' found at position 0.
// '919' found at position 6.
// '9119' found at position 14.
// '999' found at position 24.
// '91119' found at position 33.

Dim pattern As String = "\b91*9*\b"


Dim input As String = "99 95 919 929 9119 9219 999 9919 91119"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '99' found at position 0.
' '919' found at position 6.
' '9119' found at position 14.
' '999' found at position 24.
' '91119' found at position 33.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

91* Coincide con un "9" seguido de cero o más caracteres "1".

9* Coincide con cero o más caracteres "9".

\b Finaliza en un límite de palabras.

Coincidir una o más veces: +


El cuantificador + coincide con el elemento anterior una o más veces. Equivale a {1,} . + es un cuantificador
expansivo cuyo equivalente diferido es +? .
Por ejemplo, la expresión regular \ban+\w*?\b intenta coincidir con palabras completas que empiezan por la
letra a seguida de una o más instancias de la letra n . En el ejemplo siguiente se muestra esta expresión
regular. La expresión regular coincide con las palabras an , annual , announcement y antique , y no coincide con
autumn y all .
string pattern = @"\ban+\w*?\b";

string input = "Autumn is a great time for an annual announcement to all antique collectors.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'an' found at position 27.
// 'annual' found at position 30.
// 'announcement' found at position 37.
// 'antique' found at position 57.

Dim pattern As String = "\ban+\w*?\b"

Dim input As String = "Autumn is a great time for an annual announcement to all antique collectors."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'an' found at position 27.
' 'annual' found at position 30.
' 'announcement' found at position 37.
' 'antique' found at position 57.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

an+ Coincide con una "a" seguida de uno o más caracteres "n".

\w*? Coincide con un carácter de palabra cero o más veces, pero


el menor número de veces que sea posible.

\b Finaliza en un límite de palabras.

Coincidir cero o una vez: ?


El cuantificador ? coincide con el elemento anterior cero o una vez. Equivale a {0,1} . ? es un cuantificador
expansivo cuyo equivalente diferido es ?? .
Por ejemplo, la expresión regular \ban?\b intenta coincidir con palabras completas que empiezan por la letra
a seguida de cero o una instancia de la letra n . En otras palabras, intenta coincidir con las palabras a y an .
En el ejemplo siguiente se muestra esta expresión regular.

string pattern = @"\ban?\b";


string input = "An amiable animal with a large snount and an animated nose.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'An' found at position 0.
// 'a' found at position 23.
// 'an' found at position 42.
Dim pattern As String = "\ban?\b"
Dim input As String = "An amiable animal with a large snount and an animated nose."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'An' found at position 0.
' 'a' found at position 23.
' 'an' found at position 42.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

an? Coincide con una "a" seguida de cero o un carácter "n".

\b Finaliza en un límite de palabras.

Coincidir exactamente n veces: {n}


El cuantificador { n } coincide con el elemento anterior exactamente n veces, donde n es un entero. { n } es
un cuantificador expansivo cuyo equivalente diferido es { n }? .
Por ejemplo, la expresión regular \b\d+\,\d{3}\b intenta coincidir con un límite de palabra seguido de uno o
más dígitos decimales, seguidos de tres dígitos decimales, seguidos de un límite de palabra. En el ejemplo
siguiente se muestra esta expresión regular.

string pattern = @"\b\d+\,\d{3}\b";


string input = "Sales totaled 103,524 million in January, " +
"106,971 million in February, but only " +
"943 million in March.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// '103,524' found at position 14.
// '106,971' found at position 45.

Dim pattern As String = "\b\d+\,\d{3}\b"


Dim input As String = "Sales totaled 103,524 million in January, " + _
"106,971 million in February, but only " + _
"943 million in March."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '103,524' found at position 14.
' '106,971' found at position 45.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.


MODELO DESCRIPCIÓN

\d+ Buscar coincidencias con uno o más dígitos decimales.

\, Coincide con un carácter de coma.

\d{3} Coincide con tres dígitos decimales.

\b Finaliza en un límite de palabras.

Coincidir al menos n veces: {n,}


El cuantificador { n ,} coincide con el elemento anterior al menos n, donde n es un entero. { n ,} es un
cuantificador expansivo cuyo equivalente diferido es { n ,}? .
Por ejemplo, la expresión regular \b\d{2,}\b\D+ intenta coincidir con un límite de palabra seguido de por lo
menos dos dígitos, seguidos de un límite de palabra y de un carácter que no sea un dígito. En el ejemplo
siguiente se muestra esta expresión regular. La expresión regular no coincide con la frase "7 days" porque solo
contiene un dígito decimal, pero coincide correctamente con las frases "10 weeks and 300 years" .

string pattern = @"\b\d{2,}\b\D+";


string input = "7 days, 10 weeks, 300 years";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// '10 weeks, ' found at position 8.
// '300 years' found at position 18.

Dim pattern As String = "\b\d{2,}\b\D+"


Dim input As String = "7 days, 10 weeks, 300 years"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '10 weeks, ' found at position 8.
' '300 years' found at position 18.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

\d{2,} Coincide con al menos dos dígitos decimales.

\b Coincide con un límite de palabras.

\D+ Coincide con al menos un carácter de dígito no decimal.

Coincidir de n a m veces: {n,m}


El cuantificador { n , m } coincide con el elemento anterior al menos n veces, pero no más de m veces,
donde n y m son enteros. { n , m } es un cuantificador expansivo cuyo equivalente diferido es { n , m }? .
En el ejemplo siguiente, la expresión regular (00\s){2,4} intenta coincidir con dos ceros seguidos de un
espacio que se repitan de dos a cuatro veces. Observe que la parte final de la cadena de entrada incluye este
patrón cinco veces en lugar del máximo de cuatro. Pero solo la parte inicial de esta subcadena (hasta el espacio
y el quinto par de ceros) coincide con el patrón de la expresión regular.

string pattern = @"(00\s){2,4}";


string input = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// '00 00 ' found at position 8.
// '00 00 00 ' found at position 23.
// '00 00 00 00 ' found at position 35.

Dim pattern As String = "(00\s){2,4}"


Dim input As String = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '00 00 ' found at position 8.
' '00 00 00 ' found at position 23.
' '00 00 00 00 ' found at position 35.

Coincidir cero o más veces (coincidencia diferida): *?


El cuantificador *? coincide con el elemento anterior cero o más veces, pero el menor número de veces
posible. Es el equivalente diferido del cuantificador expansivo * .
En el ejemplo siguiente, la expresión regular \b\w*?oo\w*?\b coincide con todas las palabras que contienen la
cadena oo .

string pattern = @"\b\w*?oo\w*?\b";


string input = "woof root root rob oof woo woe";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'woof' found at position 0.
// 'root' found at position 5.
// 'root' found at position 10.
// 'oof' found at position 19.
// 'woo' found at position 23.

Dim pattern As String = "\b\w*?oo\w*?\b"


Dim input As String = "woof root root rob oof woo woe"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'woof' found at position 0.
' 'root' found at position 5.
' 'root' found at position 10.
' 'oof' found at position 19.
' 'woo' found at position 23.

El patrón de expresión regular se define como se muestra en la tabla siguiente.


MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

\w*? Coincide con cero o más caracteres de palabra, pero con el


menor número de caracteres posible.

oo Coincide con la cadena "oo".

\w*? Coincide con cero o más caracteres de palabra, pero con el


menor número de caracteres posible.

\b Finaliza en un límite de palabras.

Coincidir una o más veces (coincidencia diferida): +?


El cuantificador +? coincide con el elemento anterior una o más veces, pero el menor número de veces
posible. Es el equivalente diferido del cuantificador expansivo + .
Por ejemplo, la expresión regular \b\w+?\b coincide con uno o más caracteres separados por límites de
palabra. En el ejemplo siguiente se muestra esta expresión regular.

string pattern = @"\b\w+?\b";


string input = "Aa Bb Cc Dd Ee Ff";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'Aa' found at position 0.
// 'Bb' found at position 3.
// 'Cc' found at position 6.
// 'Dd' found at position 9.
// 'Ee' found at position 12.
// 'Ff' found at position 15.

Dim pattern As String = "\b\w+?\b"


Dim input As String = "Aa Bb Cc Dd Ee Ff"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Aa' found at position 0.
' 'Bb' found at position 3.
' 'Cc' found at position 6.
' 'Dd' found at position 9.
' 'Ee' found at position 12.
' 'Ff' found at position 15.

Coincidir cero o una vez (coincidencia diferida): ??


El cuantificador ?? coincide con el elemento anterior cero o una vez, pero el menor número de veces posible.
Es el equivalente diferido del cuantificador expansivo ? .
Por ejemplo, la expresión regular ^\s*(System.)??Console.Write(Line)??\(?? intenta coincidir con las cadenas
"Console.Write" o "Console.WriteLine". La cadena también puede incluir "System." antes de "Console", y puede
ir seguida de un paréntesis de apertura. La cadena debe estar al principio de una línea, aunque puede ir
precedida de un espacio en blanco. En el ejemplo siguiente se muestra esta expresión regular.
string pattern = @"^\s*(System.)??Console.Write(Line)??\(??";
string input = "System.Console.WriteLine(\"Hello!\")\n" +
"Console.Write(\"Hello!\")\n" +
"Console.WriteLine(\"Hello!\")\n" +
"Console.ReadLine()\n" +
" Console.WriteLine";
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnorePatternWhitespace |
RegexOptions.IgnoreCase |
RegexOptions.Multiline))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'System.Console.Write' found at position 0.
// 'Console.Write' found at position 36.
// 'Console.Write' found at position 61.
// ' Console.Write' found at position 110.

Dim pattern As String = "^\s*(System.)??Console.Write(Line)??\(??"


Dim input As String = "System.Console.WriteLine(""Hello!"")" + vbCrLf + _
"Console.Write(""Hello!"")" + vbCrLf + _
"Console.WriteLine(""Hello!"")" + vbCrLf + _
"Console.ReadLine()" + vbCrLf + _
" Console.WriteLine"
For Each match As Match In Regex.Matches(input, pattern, _
RegexOptions.IgnorePatternWhitespace Or RegexOptions.IgnoreCase Or
RegexOptions.MultiLine)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'System.Console.Write' found at position 0.
' 'Console.Write' found at position 36.
' 'Console.Write' found at position 61.
' ' Console.Write' found at position 110.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Coincide con el inicio del flujo de entrada.

\s* Busca coincidencias con cero o más caracteres de espacio en


blanco.

(System.)?? Coincide con cero o una repetición de la cadena "System.".

Console.Write Coincide con la cadena "Console.Write".

(Line)?? Coincide con cero o una repetición de la cadena "Line".

\(?? Coincide con cero o con una repetición del paréntesis de


apertura.

Coincidir exactamente n veces (coincidencia diferida): {n}?


El cuantificador { n }? coincide con el elemento anterior exactamente n veces, donde n es un entero. Es el
equivalente diferido del cuantificador expansivo { n } .
En el ejemplo siguiente, la expresión regular \b(\w{3,}?\.){2}?\w{3,}?\b se usa para identificar la dirección de
un sitio web. Observe que coincide con "www.microsoft.com" y con "msdn.microsoft.com", pero no coincide con
"mywebsite" ni con "mycompany.com".

string pattern = @"\b(\w{3,}?\.){2}?\w{3,}?\b";


string input = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'www.microsoft.com' found at position 0.
// 'msdn.microsoft.com' found at position 18.

Dim pattern As String = "\b(\w{3,}?\.){2}?\w{3,}?\b"


Dim input As String = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'www.microsoft.com' found at position 0.
' 'msdn.microsoft.com' found at position 18.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(\w{3,}?\.) Coincide con al menos 3 caracteres de palabra, pero con el


menor número de caracteres posible, seguidos de un
carácter de punto. Este es el primer grupo de captura.

(\w{3,}?\.){2}? Coincide con el patrón del primer grupo dos veces, pero el
menor número de veces posible.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Coincidir al menos n veces (coincidencia diferida): {n,}?


El cuantificador { n ,}? coincide con el elemento anterior al menos n veces, donde n es un entero, pero el
menor número de veces posible. Es el equivalente diferido del cuantificador expansivo { n ,} .
Vea el ejemplo del cuantificador { n }? en la sección anterior para obtener una ilustración. La expresión
regular de ese ejemplo usa el cuantificador { n ,} para coincidir con una cadena que tenga al menos tres
caracteres seguidos de un punto.
Coincidir de n a m veces (coincidencia diferida): {n,m}?
El cuantificador { n , m }? coincide con el elemento anterior de n a m veces, donde n y m son enteros, pero
el menor número de veces posible. Es el equivalente diferido del cuantificador expansivo { n , m } .
En el ejemplo siguiente, la expresión regular \b[A-Z](\w*?\s*?){1,10}[.!?] coincide con las frases que
contengan de una a diez palabras. Coincidencia con todas las frases de la cadena de entrada, excepto con una
frase que contiene 18 palabras.
string pattern = @"\b[A-Z](\w*?\s*?){1,10}[.!?]";
string input = "Hi. I am writing a short note. Its purpose is " +
"to test a regular expression that attempts to find " +
"sentences with ten or fewer words. Most sentences " +
"in this note are short.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);

// The example displays the following output:


// 'Hi.' found at position 0.
// 'I am writing a short note.' found at position 4.
// 'Most sentences in this note are short.' found at position 132.

Dim pattern As String = "\b[A-Z](\w*\s?){1,10}?[.!?]"


Dim input As String = "Hi. I am writing a short note. Its purpose is " + _
"to test a regular expression that attempts to find " + _
"sentences with ten or fewer words. Most sentences " + _
"in this note are short."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Hi.' found at position 0.
' 'I am writing a short note.' found at position 4.
' 'Most sentences in this note are short.' found at position 132.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

[A-Z] Coincide con cualquier letra mayúscula de la A a la Z.

(\w*?\s*?) Coincide con cero o más caracteres de palabra, seguidos de


uno o más caracteres de espacio en blanco, pero el menor
número de veces posible. Este es el primer grupo de
capturas.

{1,10} Coincide con el patrón anterior entre una y diez veces.

[.!?] Coincide con cualquiera de los caracteres de puntuación ".",


"!" o "?".

Cuantificadores expansivos y diferidos


Varios cuantificadores tienen dos versiones:
Una versión expansiva.
Un cuantificador expansivo intenta coincidir con un elemento tantas veces como sea posible.
Una versión no expansiva o diferida.
Un cuantificador no expansivo intenta coincidir con un elemento el menor número de veces que sea
posible. Para convertir un cuantificador expansivo en un cuantificador diferido con tan solo agregar el
signo ? .
Considere una expresión regular simple diseñada para extraer los cuatro últimos dígitos de una cadena de
números, como un número de tarjeta de crédito. La versión de la expresión regular que usa el cuantificador
expansivo * es \b.*([0-9]{4})\b . Pero si una cadena contiene dos números, esta expresión regular coincide
con los cuatro últimos dígitos del segundo número, como se muestra en el ejemplo siguiente.

string greedyPattern = @"\b.*([0-9]{4})\b";


string input1 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input1, greedyPattern))
Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);

// The example displays the following output:


// Account ending in ******1999.

Dim greedyPattern As String = "\b.*([0-9]{4})\b"


Dim input1 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input1, greedypattern)
Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next
' The example displays the following output:
' Account ending in ******1999.

La expresión regular no coincide con el primer número porque el cuantificador * intenta coincidir con el
elemento anterior tantas veces como sea posible en toda la cadena y, por tanto, encuentra una coincidencia al
final de la cadena.
Este no es el comportamiento deseado. En su lugar, puede usar el cuantificador diferido *? para extraer los
dígitos de ambos números, tal como se muestra en el ejemplo siguiente.

string lazyPattern = @"\b.*?([0-9]{4})\b";


string input2 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input2, lazyPattern))
Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);

// The example displays the following output:


// Account ending in ******3333.
// Account ending in ******1999.

Dim lazyPattern As String = "\b.*?([0-9]{4})\b"


Dim input2 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input2, lazypattern)
Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next
' The example displays the following output:
' Account ending in ******3333.
' Account ending in ******1999.

En la mayoría de los casos, las expresiones regulares con cuantificadores expansivos y diferidos devuelven las
mismas coincidencias. Suelen devolver resultados diferentes cuando se usan con el metacarácter comodín ( . ),
que coincide con cualquier carácter.

Cuantificadores y coincidencias vacías


Los cuantificadores * , + y { n , m } y sus equivalentes diferidos nunca se repiten tras una coincidencia
vacía cuando no se ha encontrado el número mínimo de capturas. Esta regla impide que los cuantificadores
entren en bucles infinitos en coincidencias de subexpresiones vacías cuando el número máximo de posibles
capturas de grupo es infinito o cerca de infinito.
Por ejemplo, en el código siguiente se muestra el resultado de una llamada al método Regex.Match con el
patrón de expresión regular (a?)* que coincide cero o más veces con cero o un carácter "a". Observe que el
único grupo de captura realiza una captura de todos los caracteres "a", así como de String.Empty, pero no hay
una segunda coincidencia vacía, ya que la primera coincidencia vacía hace que el cuantificador deje de repetirse.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "(a?)*";
string input = "aaabbb";
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: '{0}' at index {1}",
match.Value, match.Index);
if (match.Groups.Count > 1) {
GroupCollection groups = match.Groups;
for (int grpCtr = 1; grpCtr <= groups.Count - 1; grpCtr++) {
Console.WriteLine(" Group {0}: '{1}' at index {2}",
grpCtr,
groups[grpCtr].Value,
groups[grpCtr].Index);
int captureCtr = 0;
foreach (Capture capture in groups[grpCtr].Captures) {
captureCtr++;
Console.WriteLine(" Capture {0}: '{1}' at index {2}",
captureCtr, capture.Value, capture.Index);
}
}
}
}
}
// The example displays the following output:
// Match: 'aaa' at index 0
// Group 1: '' at index 3
// Capture 1: 'a' at index 0
// Capture 2: 'a' at index 1
// Capture 3: 'a' at index 2
// Capture 4: '' at index 3
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(a?)*"
Dim input As String = "aaabbb"
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: '{0}' at index {1}",
match.Value, match.Index)
If match.Groups.Count > 1 Then
Dim groups As GroupCollection = match.Groups
For grpCtr As Integer = 1 To groups.Count - 1
Console.WriteLine(" Group {0}: '{1}' at index {2}",
grpCtr,
groups(grpCtr).Value,
groups(grpCtr).Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In groups(grpCtr).Captures
captureCtr += 1
Console.WriteLine(" Capture {0}: '{1}' at index {2}",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
End Sub
End Module
' The example displays the following output:
' Match: 'aaa' at index 0
' Group 1: '' at index 3
' Capture 1: 'a' at index 0
' Capture 2: 'a' at index 1
' Capture 3: 'a' at index 2
' Capture 4: '' at index 3

Para ver la diferencia práctica entre un grupo de captura que define un número mínimo y máximo de capturas y
otro que define un número fijo de capturas, tenga en cuenta los patrones de expresiones regulares
(a\1|(?(1)\1)){0,2} y (a\1|(?(1)\1)){2} . Ambas expresiones regulares constan de un único grupo de captura,
que se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

(a\1 Coincide con "a", junto con el valor del primer grupo
capturado...

|(?(1) … o bien, prueba si se ha definido el primer grupo


capturado. (Tenga en cuenta que la construcción (?(1) no
define un grupo de captura).

\1)) Si el primer grupo capturado existe, coincide con su valor. Si


el grupo no existe, el grupo coincidirá con String.Empty.

La primera expresión regular intenta coincidir con este patrón de cero a dos veces; el segundo, exactamente dos
veces. Dado que el primer modelo alcanza el número mínimo de capturas con su primera captura de
String.Empty, nunca se repite para intentar coincidir con a\1 ; el cuantificador {0,2} solo permite las
coincidencias vacías en la última iteración. En cambio, la segunda expresión regular coincide con "a" porque
evalúa a\1 una segunda vez. El número mínimo de iteraciones (dos) obliga al motor a repetirse tras una
coincidencia vacía.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern, input;

pattern = @"(a\1|(?(1)\1)){0,2}";
input = "aaabbb";

Console.WriteLine("Regex pattern: {0}", pattern);


Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: '{0}' at position {1}.",
match.Value, match.Index);
if (match.Groups.Count > 1) {
for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
{
Group group = match.Groups[groupCtr];
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index);
int captureCtr = 0;
foreach (Capture capture in group.Captures) {
captureCtr++;
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index);
}
}
}
Console.WriteLine();

pattern = @"(a\1|(?(1)\1)){2}";
Console.WriteLine("Regex pattern: {0}", pattern);
match = Regex.Match(input, pattern);
Console.WriteLine("Matched '{0}' at position {1}.",
match.Value, match.Index);
if (match.Groups.Count > 1) {
for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
{
Group group = match.Groups[groupCtr];
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index);
int captureCtr = 0;
foreach (Capture capture in group.Captures) {
captureCtr++;
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index);
}
}
}
}
}
// The example displays the following output:
// Regex pattern: (a\1|(?(1)\1)){0,2}
// Match: '' at position 0.
// Group: 1: '' at position 0.
// Capture: 1: '' at position 0.
//
// Regex pattern: (a\1|(?(1)\1)){2}
// Matched 'a' at position 0.
// Group: 1: 'a' at position 0.
// Capture: 1: '' at position 0.
// Capture: 2: 'a' at position 0.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern, input As String

pattern = "(a\1|(?(1)\1)){0,2}"
input = "aaabbb"

Console.WriteLine("Regex pattern: {0}", pattern)


Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: '{0}' at position {1}.",
match.Value, match.Index)
If match.Groups.Count > 1 Then
For groupCtr As Integer = 1 To match.Groups.Count - 1
Dim group As Group = match.Groups(groupCtr)
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
captureCtr += 1
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
Console.WriteLine()

pattern = "(a\1|(?(1)\1)){2}"
Console.WriteLine("Regex pattern: {0}", pattern)
match = Regex.Match(input, pattern)
Console.WriteLine("Matched '{0}' at position {1}.",
match.Value, match.Index)
If match.Groups.Count > 1 Then
For groupCtr As Integer = 1 To match.Groups.Count - 1
Dim group As Group = match.Groups(groupCtr)
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
captureCtr += 1
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
End Sub
End Module
' The example displays the following output:
' Regex pattern: (a\1|(?(1)\1)){0,2}
' Match: '' at position 0.
' Group: 1: '' at position 0.
' Capture: 1: '' at position 0.
'
' Regex pattern: (a\1|(?(1)\1)){2}
' Matched 'a' at position 0.
' Group: 1: 'a' at position 0.
' Capture: 1: '' at position 0.
' Capture: 2: 'a' at position 0.

Vea también
Lenguaje de expresiones regulares: referencia rápida
Retroceso
Construcciones de referencia inversa en expresiones
regulares
20/01/2020 • 16 minutes to read • Edit Online

Las referencias inversas proporcionan una forma cómoda de identificar un carácter o subcadena repetidos dentro
de una cadena. Por ejemplo, si la cadena de entrada contiene varias apariciones de una subcadena arbitraria,
puede buscar una coincidencia con la primera aparición con un grupo de captura y después usar una referencia
inversa para buscar una coincidencia con las siguientes apariciones de la subcadena.

NOTE
Se usa una sintaxis independiente para hacer referencia a los grupos de captura con numeración y con nombre de las
cadenas de reemplazo. Para obtener más información, consulte Substituciones.

.NET define elementos del lenguaje independientes para hacer referencia a los grupos de captura con
numeración y con nombre. Para más información sobre los grupos de captura con nombre, vea Construcciones
de agrupamiento.

Referencias inversas con numeración


Una referencia inversa con numeración usa la siguiente sintaxis:
\ número
donde número es la posición ordinal del grupo de captura en la expresión regular. Por ejemplo, \4 coincide con
el contenido del cuarto grupo de captura. Si número no está definido en el patrón de expresión regular, se
produce un error de análisis y el motor de expresiones regulares produce una clase ArgumentException. Por
ejemplo, la expresión regular \b(\w+)\s\1 es válida, porque (\w+) es el primer y único grupo de captura de la
expresión. Por otro lado, \b(\w+)\s\2 no es válida y produce una excepción de argumento porque no hay ningún
grupo de captura con numeración \2 . Además, si número identifica un grupo de captura en una posición ordinal
determinada, pero a ese grupo de captura se le ha asignado un nombre numérico que no sea su posición ordinal,
el analizador de expresiones regulares también produce una excepción ArgumentException.
Tenga en cuenta la ambigüedad entre los códigos de escape octales (como \16 ) y las referencias inversas \
número que usan la misma notación. Esta ambigüedad se resuelve de la siguiente forma:
Las expresiones \1 a \9 siempre se interpretan como referencias inversas y no como códigos octales.
Si el primer dígito de una expresión con varios dígitos es 8 o 9 (como \80 o \91 ), la expresión se
interpreta como un literal.
Las expresiones a partir de \10 y superiores se consideran referencias inversas si hay una referencia
inversa que se corresponda con ese número; en caso contrario, se interpretan como códigos octales.
Si una expresión regular contiene una referencia inversa a un número de grupo sin definir, se produce un
error de análisis y el motor de expresiones regulares produce una clase ArgumentException.
Si la ambigüedad constituye un problema, puede usar la notación \k< nombre > , que es inequívoca y no se
puede confundir con códigos de caracteres octales. De forma similar, los códigos hexadecimales como \xdd son
inequívocos y no se pueden confundir con las referencias inversas.
En el ejemplo siguiente, se buscan caracteres de palabra duplicados en una cadena. Define una expresión regular,
(\w)\1 , que consta de los siguientes elementos.

ELEMENTO DESCRIPCIÓN

(\w) Coincide con un carácter que se usa para formar palabras y


se lo asigna al primer grupo de captura.

\1 Coincide con el siguiente carácter que sea igual que el valor


del primer grupo de captura.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(\w)\1";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(\w)\1"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.

Referencias inversas con nombre


Una referencia inversa con nombre se define mediante la sintaxis siguiente:
\k< nombre >

O bien
\k' nombre '
donde nombre es el nombre de un grupo de captura definido en el patrón de expresión regular. Si nombre no
está definido en el patrón de expresión regular, se produce un error de análisis y el motor de expresiones
regulares produce una clase ArgumentException.
En el ejemplo siguiente, se buscan caracteres de palabra duplicados en una cadena. Define una expresión regular,
(?<char>\w)\k<char> , que consta de los siguientes elementos.

ELEMENTO DESCRIPCIÓN

(?<char>\w) Coincide con un carácter que se usa para formar palabras y


se lo asigna a un grupo de captura denominado char .

\k<char> Coincide con el siguiente carácter que sea igual que el valor
del grupo de captura char .

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(?<char>\w)\k<char>";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?<char>\w)\k<char>"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.

Referencias inversas numéricas con nombre


En una referencia inversa con \k , nombre también puede ser la representación de cadena de un número. Por
ejemplo, en el ejemplo siguiente, se usa la expresión regular (?<2>\w)\k<2> para buscar caracteres de palabra
duplicados en una cadena. En este caso, el ejemplo define un grupo de captura que se denomina explícitamente
"2" y la referencia inversa se denomina también "2".

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(?<2>\w)\k<2>";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?<2>\w)\k<2>"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.

Si nombre es la representación de cadena de un número y ningún grupo de captura tiene ese nombre, \k<
nombre > es igual que la referencia inversa \ número, donde número es la posición ordinal de la captura. En el
ejemplo siguiente, hay un único grupo de captura denominado char . La construcción de referencia inversa hace
referencia a él como \k<1> . Como muestra la salida del ejemplo, la llamada a Regex.IsMatch se realiza
correctamente porque char es el primer grupo de captura.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
Console.WriteLine(Regex.IsMatch("aa", @"(?<char>\w)\k<1>"));
// Displays "True".
}
}
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Console.WriteLine(Regex.IsMatch("aa", "(?<char>\w)\k<1>"))
' Displays "True".
End Sub
End Module

En cambio, si nombre es la representación de cadena de un número y al grupo de captura de esa posición se le


ha asignado explícitamente un nombre numérico, el analizador de expresiones regulares no puede identificar el
grupo de captura por su posición ordinal. En su lugar, produce una excepción ArgumentException. El único grupo
de captura del siguiente ejemplo se denomina "2". Dado que la construcción \k se usa para definir una
referencia inversa denominada "1", el analizador de expresiones regulares no puede identificar el primer grupo
de captura y produce una excepción.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
Console.WriteLine(Regex.IsMatch("aa", @"(?<2>\w)\k<1>"));
// Throws an ArgumentException.
}
}

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Console.WriteLine(Regex.IsMatch("aa", "(?<2>\w)\k<1>"))
' Throws an ArgumentException.
End Sub
End Module

Con qué coinciden las referencias inversas


Una referencia inversa constituye la definición más reciente de un grupo (la definición más inmediatamente a la
izquierda, al coincidir de izquierda a derecha). Cuando un grupo realiza varias capturas, una referencia inversa se
refiere a la captura más reciente.
En el ejemplo siguiente, se incluye un patrón de expresión regular, (?<1>a)(?<1>\1b)* , que redefine el grupo con
nombre \1. En la tabla siguiente, se describe cada patrón de la expresión regular.

MODELO DESCRIPCIÓN

(?<1>a) Coincide con el carácter "a" y asigna el resultado al grupo de


captura denominado 1 .
MODELO DESCRIPCIÓN

(?<1>\1b)* Coincide con ninguna o más apariciones del grupo


denominado 1 junto con una "b" y asigna el resultado al
grupo de captura denominado 1 .

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"(?<1>a)(?<1>\1b)*";
string input = "aababb";
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine("Match: " + match.Value);
foreach (Group group in match.Groups)
Console.WriteLine(" Group: " + group.Value);
}
}
}
// The example displays the following output:
// Group: aababb
// Group: abb

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?<1>a)(?<1>\1b)*"
Dim input As String = "aababb"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Match: " + match.Value)
For Each group As Group In match.Groups
Console.WriteLIne(" Group: " + group.Value)
Next
Next
End Sub
End Module
' The example display the following output:
' Group: aababb
' Group: abb

Al comparar la expresión regular con la cadena de entrada ("aababb"), el motor de expresiones regulares realiza
las siguientes operaciones:
1. Comienza al principio de la cadena y hace que "a" coincida correctamente con la expresión (?<1>a) .
Ahora, el valor del grupo 1 es "a".
2. Se desplaza hasta el segundo carácter y hace que la cadena "ab" coincida correctamente con la expresión
\1b , o "ab". Después, asigna el resultado "ab" a \1 .

3. Se desplaza hasta el cuarto carácter. La expresión (?<1>\1b)* puede coincidir cero o más veces, así que la
cadena "abb" coincide correctamente con la expresión \1b . Vuelve a asignar el resultado, "abb", a \1 .

En este ejemplo, * es un cuantificador de bucle: se evalúa repetidas veces hasta que el motor de expresiones
regulares no puede coincidir con el patrón que define. Los cuantificadores de bucle no borran las definiciones de
grupo.
Si un grupo no ha capturado ninguna subcadena, no se define una referencia inversa a ese grupo y no coincide
nunca. Así lo ilustra el patrón de expresión regular \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b que se define de la
siguiente forma:

MODELO DESCRIPCIÓN

\b Comienza la búsqueda de coincidencias en un límite de


palabras.

(\p{Lu}{2}) Coincide con dos letras mayúsculas. Este es el primer grupo


de captura.

(\d{2})? Coincide con una o ninguna aparición de dos dígitos


decimales. Este es el segundo grupo de captura.

(\p{Lu}{2}) Coincide con dos letras mayúsculas. Éste es el tercer grupo de


captura.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Una cadena de entrada puede coincidir con esta expresión regular aunque no estén presentes los dos dígitos
decimales que define el segundo grupo de captura. En el ejemplo siguiente, se muestra que, aunque la
coincidencia es correcta, hay un grupo de captura vacío entre dos grupos de captura correctos.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b";
string[] inputs = { "AA22ZZ", "AABB" };
foreach (string input in inputs)
{
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine("Match in {0}: {1}", input, match.Value);
if (match.Groups.Count > 1)
{
for (int ctr = 1; ctr <= match.Groups.Count - 1; ctr++)
{
if (match.Groups[ctr].Success)
Console.WriteLine("Group {0}: {1}",
ctr, match.Groups[ctr].Value);
else
Console.WriteLine("Group {0}: <no match>", ctr);
}
}
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// Match in AA22ZZ: AA22ZZ
// Group 1: AA
// Group 2: 22
// Group 3: ZZ
//
// Match in AABB: AABB
// Group 1: AA
// Group 2: <no match>
// Group 3: BB
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b"
Dim inputs() As String = { "AA22ZZ", "AABB" }
For Each input As String In inputs
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine("Match in {0}: {1}", input, match.Value)
If match.Groups.Count > 1 Then
For ctr As Integer = 1 To match.Groups.Count - 1
If match.Groups(ctr).Success Then
Console.WriteLine("Group {0}: {1}", _
ctr, match.Groups(ctr).Value)
Else
Console.WriteLine("Group {0}: <no match>", ctr)
End If
Next
End If
End If
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Match in AA22ZZ: AA22ZZ
' Group 1: AA
' Group 2: 22
' Group 3: ZZ
'
' Match in AABB: AABB
' Group 1: AA
' Group 2: <no match>
' Group 3: BB

Vea también
Lenguaje de expresiones regulares: referencia rápida
Construcciones de alternancia en expresiones
regulares
20/01/2020 • 14 minutes to read • Edit Online

Las construcciones de alternancia modifican una expresión regular para habilitar la coincidencia condicional o
“either/or”. .NET admite tres construcciones de alternancia:
Coincidencia de patrones con |
Coincidencia condicional con (?(expresión)sí|no)
Coincidencia condicional basada en un grupo capturado válido

Coincidencia de patrones con |


Puede usar el carácter de barra vertical ( | ) para hacer coincidir un elemento de una serie de patrones, donde el
carácter | separa cada patrón.
Como sucede con la clase de caracteres positivos, el carácter | puede utilizarse para hacer coincidir un elemento
de una serie de caracteres individuales. En el ejemplo siguiente se utiliza una clase de caracteres positivos y un
patrón either/or que coincide con el carácter | para buscar apariciones de las palabras "gray" o "grey" en una
cadena. En este caso, el carácter | produce una expresión regular que es más detallada.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
// Regular expression using character class.
string pattern1 = @"\bgr[ae]y\b";
// Regular expression using either/or.
string pattern2 = @"\bgr(a|e)y\b";

string input = "The gray wolf blended in among the grey rocks.";
foreach (Match match in Regex.Matches(input, pattern1))
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index);
Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern2))
Console.WriteLine("'{0}' found at position {1}",
match.Value, match.Index);
}
}
// The example displays the following output:
// 'gray' found at position 4
// 'grey' found at position 35
//
// 'gray' found at position 4
// 'grey' found at position 35
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
' Regular expression using character class.
Dim pattern1 As String = "\bgr[ae]y\b"
' Regular expression using either/or.
Dim pattern2 As String = "\bgr(a|e)y\b"

Dim input As String = "The gray wolf blended in among the grey rocks."
For Each match As Match In Regex.Matches(input, pattern1)
Console.WriteLine("'{0}' found at position {1}", _
match.Value, match.Index)
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern2)
Console.WriteLine("'{0}' found at position {1}", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' 'gray' found at position 4
' 'grey' found at position 35
'
' 'gray' found at position 4
' 'grey' found at position 35

La expresión regular que usa el carácter | , \bgr(a|e)y\b , se interpreta como se muestra en la tabla siguiente:

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

gr Coincide con los caracteres "gr".

(a|e) Coincide con una "a" o una "e".

y\b Coincide con una "y" en un límite de palabras.

El carácter | también se puede usar para realizar una coincidencia either/or con varios caracteres o
subexpresiones, que pueden incluir cualquier combinación de literales de carácter y elementos de lenguaje de
expresión regular. (La clase de caracteres no proporciona esta funcionalidad). En el ejemplo siguiente, se usa el
carácter | para extraer un número de la seguridad social (SSN ) de EE. UU., de nueve dígitos y en formato
ddd-dd-dddd, o un número de identificación de empleador (EIN ), de nueve dígitos y en formato dd-ddddddd.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b";
string input = "01-9999999 020-333333 777-88-9999";
Console.WriteLine("Matches for {0}:", pattern);
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);
}
}
// The example displays the following output:
// Matches for \b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b:
// 01-9999999 at position 0
// 777-88-9999 at position 22

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b"
Dim input As String = "01-9999999 020-333333 777-88-9999"
Console.WriteLine("Matches for {0}:", pattern)
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Matches for \b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b:
' 01-9999999 at position 0
' 777-88-9999 at position 22

La expresión regular \b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b se interpreta como se muestra en la tabla siguiente:

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(\d{2}-\d{7}|\d{3}-\d{2}-\d{4}) Coincide con cualquiera de las siguientes opciones: dos


dígitos decimales seguidos de un guión seguido de siete
dígitos decimales; o tres dígitos decimales, un guión, dos
dígitos decimales, otro guión y cuatro dígitos decimales.

\d Finalizar la búsqueda de coincidencias en un límite de


palabras.

Coincidencia condicional con una expresión


Este elemento del lenguaje intenta coincidir con uno de dos patrones en función de si puede coincidir con un
patrón inicial. Su sintaxis es:
(?( expresión ) sí | no )

donde expresión es el patrón inicial de coincidencia, sí es el patrón de coincidencia si se encuentra una


coincidencia para expresión y no es el patrón opcional de coincidencia si no se encuentra ninguna coincidencia
para expresión . El motor de expresiones regulares trata a la expresión como una aserción de ancho cero; es decir,
el motor de expresiones regulares no avanza en el flujo de entrada después de evaluar la expresión. Por tanto,
esta construcción es equivalente a la siguiente:
(?(?= expresión ) sí | no )

donde (?= expresión ) es una construcción de aserción de ancho cero. Para más información, consulte la
sección sobre Construcciones de agrupamiento en expresiones regulares. Como el motor de expresiones
regulares interpreta la expresión como un delimitador (una aserción de ancho cero), la expresión debe ser una
aserción de ancho cero (para más información, consulte Delimitadores en expresiones regulares) o una
subexpresión que también esté incluida en sí. De lo contrario, no se pueden encontrar coincidencias para el
patrón sí .

NOTE
Si expresión es un grupo de captura con nombre o con numeración, la construcción de alternancia se interpreta como una
prueba de captura; para obtener más información, consulte la sección siguiente, Coincidencia condicional basada en un
grupo capturado válido. En otras palabras, el motor de expresiones regulares no intenta coincidir con la subcadena
capturada, sino que, en vez de eso, comprueba la presencia o la ausencia del grupo.

El siguiente ejemplo es una variación del que aparece en la sección Coincidencia de patrones either/or con |. En él
se usa la coincidencia condicional para determinar si los tres primeros caracteres después de un límite de palabra
son dos dígitos seguidos por un guión. Si es así, intenta buscar un número de identificación de empleador (EIN )
de EE. UU. Si no, intenta buscar un número de la seguridad social (SSN ) de EE.UU.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(?(\d{2}-)\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b";
string input = "01-9999999 020-333333 777-88-9999";
Console.WriteLine("Matches for {0}:", pattern);
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);
}
}
// The example displays the following output:
// Matches for \b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b:
// 01-9999999 at position 0
// 777-88-9999 at position 22
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(?(\d{2}-)\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b"
Dim input As String = "01-9999999 020-333333 777-88-9999"
Console.WriteLine("Matches for {0}:", pattern)
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Matches for \b(?(\d{2}-)\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b:
' 01-9999999 at position 0
' 777-88-9999 at position 22

El patrón de la expresión regular \b(?(\d{2}-)\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b se interpreta como se muestra en


la tabla siguiente:

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(?(\d{2}-) Determina si los tres caracteres siguientes están compuestos


de dos dígitos seguidos de un guión.

\d{2}-\d{7} Si el patrón anterior coincide, coincide con dos dígitos


seguidos de un guión seguido de siete dígitos.

\d{3}-\d{2}-\d{4} Si el patrón anterior no coincide, coincide con tres dígitos


decimales, un guión, dos dígitos decimales, otro guión y
cuatro dígitos decimales.

\b Coincide con un límite de palabras.

Coincidencia condicional basada en un grupo capturado válido


Este elemento del lenguaje intenta coincidir con uno de dos patrones en función de si coincidió con un grupo de
captura especificado. Su sintaxis es:
(?( nombre ) sí | no )

o
(?( número ) sí | no )

donde nombre es el nombre y número es el número de un grupo de captura, sí es la expresión que debe coincidir
si nombre o número tienen una coincidencia, y no es la expresión opcional que debe coincidir si no la tienen.
Si nombre no se corresponde con el nombre de un grupo de captura que se usa en el patrón de expresión
regular, la construcción de alternancia se interpreta como una prueba de expresión, tal como se explica en la
sección anterior. Normalmente, esto significa que expresión se evalúa como false . Si número no se corresponde
con un grupo de captura numerado que se usa en el patrón de expresión regular, el motor de expresiones
regulares genera una excepción ArgumentException.
El siguiente ejemplo es una variación del que aparece en la sección Coincidencia de patrones either/or con |. En él
se usa un grupo de captura denominado n2 que consta de dos dígitos seguidos por un guión. La construcción
de alternancia prueba si este grupo de captura ha coincidido en la cadena de entrada. En caso afirmativo, la
construcción de alternancia intenta hacer coincidir los últimos siete dígitos de un número de identificación de
empleador de identificación de empleador (EIN ) de EE. UU. En caso negativo, intenta coincidir con un número de
la seguridad social (SSN ) de EE.UU.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(?<n2>\d{2}-)?(?(n2)\d{7}|\d{3}-\d{2}-\d{4})\b";
string input = "01-9999999 020-333333 777-88-9999";
Console.WriteLine("Matches for {0}:", pattern);
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);
}
}
// The example displays the following output:
// Matches for \b(?<n2>\d{2}-)?(?(n2)\d{7}|\d{3}-\d{2}-\d{4})\b:
// 01-9999999 at position 0
// 777-88-9999 at position 22

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(?<n2>\d{2}-)?(?(n2)\d{7}|\d{3}-\d{2}-\d{4})\b"
Dim input As String = "01-9999999 020-333333 777-88-9999"
Console.WriteLine("Matches for {0}:", pattern)
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
End Sub
End Module

El patrón de la expresión regular \b(?<n2>\d{2}-)?(?(n2)\d{7}|\d{3}-\d{2}-\d{4})\b se interpreta como se


muestra en la tabla siguiente:

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(?<n2>\d{2}-)? Coincide con cero o con dos dígitos seguidos por un guión.
Este grupo de captura se denomina n2 .

(?(n2) Prueba si n2 coincidió con la cadena de entrada.

\d{7} Si n2 coincidió, coincide con siete dígitos decimales.

|\d{3}-\d{2}-\d{4} Si n2 no coincidió, coincide con tres dígitos decimales, un


guión, dos dígitos decimales, otro guión y cuatro dígitos
decimales.

\b Coincide con un límite de palabras.

En el ejemplo siguiente se muestra una variación de este ejemplo, pero con un grupo numerado en lugar de un
grupo con nombre. Su patrón de expresión regular es \b(\d{2}-)?(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b .

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\d{2}-)?(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b";
string input = "01-9999999 020-333333 777-88-9999";
Console.WriteLine("Matches for {0}:", pattern);
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);
}
}
// The example display the following output:
// Matches for \b(\d{2}-)?(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b:
// 01-9999999 at position 0
// 777-88-9999 at position 22

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\d{2}-)?(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b"
Dim input As String = "01-9999999 020-333333 777-88-9999"
Console.WriteLine("Matches for {0}:", pattern)
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Matches for \b(\d{2}-)?(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b:
' 01-9999999 at position 0
' 777-88-9999 at position 22

Vea también
Lenguaje de expresiones regulares: referencia rápida
Sustituciones en expresiones regulares
25/11/2019 • 28 minutes to read • Edit Online

Las sustituciones son elementos del lenguaje que se reconocen solo dentro de patrones de reemplazo. Usan un
patrón de expresión regular para definir todo o parte del texto que reemplazará el texto coincidente en la cadena
de entrada. El patrón de reemplazo puede estar compuesto de una o más sustituciones junto con caracteres
literales. Los patrones de reemplazo se proporcionan a las sobrecargas del método Regex.Replace que tiene un
parámetro replacement y al método Match.Result . Los métodos reemplazan el patrón que coincide con el patrón
que define el parámetro replacement .
.NET Framework define los elementos de sustitución que se enumeran en la siguiente tabla.

SUSTITUCIÓN DESCRIPCIÓN

$ number Incluye la última subcadena coincidente por el grupo


capturado que identifica number, donde number es un valor
decimal, en la cadena de reemplazo. Para obtener más
información, vea Sustituir un grupo numerado.

${ name } Incluye la última subcadena coincidente por el grupo con


nombre que designa (?< name > ) en la cadena de
reemplazo. Para obtener más información, vea Sustituir un
grupo con nombre.

$$ Incluye un literal "$" único en la cadena de reemplazo. Para


obtener más información, vea Sustituir un símbolo "$".

$& Incluye una copia de la coincidencia completa en la cadena de


reemplazo. Para obtener más información, vea Sustituir toda
la coincidencia.

$` Incluye todo el texto de la cadena de entrada delante de la


coincidencia en la cadena de reemplazo. Para obtener más
información, vea Sustituir el texto delante de la coincidencia.

$' Incluye todo el texto de la cadena de entrada detrás de la


coincidencia en la cadena de reemplazo. Para obtener más
información, vea Sustituir el texto detrás de la coincidencia.

$+ Incluye el último grupo capturado en la cadena de reemplazo.


Para obtener más información, vea Sustituir el último grupo
capturado.

$_ Incluye la cadena de entrada completa en la cadena de


reemplazo. Para obtener más información, vea Sustituir toda
la cadena de entrada.

Elementos de sustitución y patrones de reemplazo


Las sustituciones son las únicas construcciones especiales reconocidas en un patrón de reemplazo. No se admiten
otros elementos de lenguaje de expresiones regulares, incluidos los escapes de caracteres y el punto ( . ), que
coincidan con cualquier carácter. De igual forma, los elementos de lenguaje de sustitución se reconocen
únicamente en patrones de reemplazo y no son válidos en patrones de expresiones regulares.
El único carácter que puede aparecer en un patrón de expresión regular o en una sustitución es el carácter $ ,
aunque tiene un significado diferente en cada contexto. En un patrón de expresión regular, $ es un delimitador
que coincide con el final de la cadena. En un patrón de reemplazo, $ indica el principio de una sustitución.

NOTE
Para obtener una funcionalidad similar a la de un patrón de reemplazo dentro de una expresión regular, use una referencia
inversa. Para obtener más información acerca de las referencias inversas, vea Construcciones de referencia inversa.

Sustituir un grupo numerado


El elemento de lenguaje $ number incluye la última subcadena coincidente por el grupo de captura number en la
cadena de reemplazo, donde number es el índice del grupo de captura. Por ejemplo, el patrón de reemplazo $1
indica que el primer grupo capturado reemplazará la subcadena coincidente. Para más información sobre los
grupos de captura numerados, vea Grouping Constructs.
Todos los dígitos después del símbolo $ se interpretan como que pertenecen al grupo number . Si esto no es lo
que pretende, puede sustituir un grupo con nombre en su lugar. Por ejemplo, puede utilizar la cadena de
reemplazo ${1}1 en lugar de $11 para definir la cadena de reemplazo como el valor del primer grupo capturado
junto con el número "1". Para obtener más información, vea Sustituir un grupo con nombre.
Los grupos de captura que no tienen nombres asignados explícitamente mediante la sintaxis (?< name >) se
enumeran de izquierda a derecha a partir de uno. Los grupos con nombre también se numeran de izquierda a
derecha, comenzando por uno mayor que el índice del último grupo sin nombre. Por ejemplo, en la expresión
regular (\w)(?<digit>\d) , el índice del grupo con nombre digit es 2.
Si number no especifica ningún grupo de captura válido en el patrón de expresión regular, $ number se
interpreta como una secuencia de caracteres literales que se usa para reemplazar cada coincidencia.
En el ejemplo siguiente se usa la sustitución $ number para quitar el símbolo de divisa de un valor decimal. Quita
los símbolos de divisa encontrados al principio o al final de un valor monetario y reconoce los dos separadores
decimales más comunes ("." y ",").

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\p{Sc}*(\s?\d+[.,]?\d*)\p{Sc}*";
string replacement = "$1";
string input = "$16.32 12.19 £16.29 €18.29 €18,29";
string result = Regex.Replace(input, pattern, replacement);
Console.WriteLine(result);
}
}
// The example displays the following output:
// 16.32 12.19 16.29 18.29 18,29
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\p{Sc}*(\s?\d+[.,]?\d*)\p{Sc}*"
Dim replacement As String = "$1"
Dim input As String = "$16.32 12.19 £16.29 €18.29 €18,29"
Dim result As String = Regex.Replace(input, pattern, replacement)
Console.WriteLine(result)
End Sub
End Module
' The example displays the following output:
' 16.32 12.19 16.29 18.29 18,29

El patrón de expresión regular \p{Sc}*(\s?\d+[.,]?\d*)\p{Sc}* se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\p{Sc}* Busca una coincidencia con cero o más caracteres de símbolo


de divisa.

\s? Busca una coincidencia con cero o un carácter de espacio en


blanco.

\d+ Buscar coincidencias con uno o más dígitos decimales.

[.,]? Busca una coincidencia con cero o un punto o una coma.

\d* Busca cero o más dígitos decimales.

(\s?\d+[.,]?\d*) Busca un espacio en blanco seguido de uno o más dígitos


decimales, seguido de cero o un punto o una coma, seguido
de cero o más dígitos decimales. Este es el primer grupo de
captura. Dado que el patrón de reemplazo es $1 , la llamada
al método Regex.Replace reemplaza la subcadena coincidente
completa por este grupo capturado.

Sustituir un grupo con nombre


El elemento de lenguaje ${ name } sustituye a la última subcadena coincidente por el grupo de captura name ,
donde name es el nombre del grupo de captura definido por el elemento de lenguaje (?< name >) . Para más
información sobre los grupos de captura con nombre, vea Grouping Constructs.
Si name no especifica ningún grupo de captura con nombre válido en el patrón de expresión regular pero consta
de dígitos, ${ name } se interpreta como un grupo numerado.
Si name no especifica ningún grupo de captura con nombre o grupo de captura numerado válido en el patrón de
expresión regular, ${ name } se interpreta como una secuencia de caracteres literales que se utiliza para
reemplazar cada coincidencia.
En el ejemplo siguiente, se usa la sustitución ${ name } para quitar el símbolo de divisa de un valor decimal.
Quita los símbolos de divisa encontrados al principio o al final de un valor monetario y reconoce los dos
separadores decimales más comunes ("." y ",").
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\p{Sc}*(?<amount>\s?\d+[.,]?\d*)\p{Sc}*";
string replacement = "${amount}";
string input = "$16.32 12.19 £16.29 €18.29 €18,29";
string result = Regex.Replace(input, pattern, replacement);
Console.WriteLine(result);
}
}
// The example displays the following output:
// 16.32 12.19 16.29 18.29 18,29

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\p{Sc}*(?<amount>\s?\d+[.,]?\d*)\p{Sc}*"
Dim replacement As String = "${amount}"
Dim input As String = "$16.32 12.19 £16.29 €18.29 €18,29"
Dim result As String = Regex.Replace(input, pattern, replacement)
Console.WriteLine(result)
End Sub
End Module
' The example displays the following output:
' 16.32 12.19 16.29 18.29 18,29

El patrón de expresión regular \p{Sc}*(?<amount>\s?\d[.,]?\d*)\p{Sc}* se define como se muestra en la tabla


siguiente.

MODELO DESCRIPCIÓN

\p{Sc}* Busca una coincidencia con cero o más caracteres de símbolo


de divisa.

\s? Busca una coincidencia con cero o un carácter de espacio en


blanco.

\d+ Buscar coincidencias con uno o más dígitos decimales.

[.,]? Busca una coincidencia con cero o un punto o una coma.

\d* Busca cero o más dígitos decimales.

(?<amount>\s?\d[.,]?\d*) Busca un espacio en blanco, seguido de uno o más dígitos


decimales, seguido de cero o un punto o una coma, seguido
de cero o más dígitos decimales. Este es el grupo de captura
denominado amount . Dado que el patrón de reemplazo es
${amount} , la llamada al método Regex.Replace reemplaza la
subcadena coincidente completa por este grupo capturado.

Sustituir un carácter "$"


La sustitución $$ inserta un carácter "$" literal en la cadena reemplazada.
En el ejemplo siguiente, se usa el objeto NumberFormatInfo para determinar el símbolo de divisa de la referencia
cultural actual y su posición en una cadena de divisa. A continuación, compila dinámicamente un patrón de
expresión regular y un patrón de reemplazo. Si el ejemplo se ejecuta en un equipo cuya referencia cultural actual
es en-US, genera el patrón de expresión regular \b(\d+)(\.(\d+))? y el patrón de reemplazo $$ $1$2 . El patrón
de reemplazo sustituye el texto coincidente por un símbolo de divisa y un espacio seguido del primer y del
segundo grupo capturado.

using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
// Define array of decimal values.
string[] values= { "16.35", "19.72", "1234", "0.99"};
// Determine whether currency precedes (True) or follows (False) number.
bool precedes = NumberFormatInfo.CurrentInfo.CurrencyPositivePattern % 2 == 0;
// Get decimal separator.
string cSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
// Get currency symbol.
string symbol = NumberFormatInfo.CurrentInfo.CurrencySymbol;
// If symbol is a "$", add an extra "$".
if (symbol == "$") symbol = "$$";

// Define regular expression pattern and replacement string.


string pattern = @"\b(\d+)(" + cSeparator + @"(\d+))?";
string replacement = "$1$2";
replacement = precedes ? symbol + " " + replacement : replacement + " " + symbol;
foreach (string value in values)
Console.WriteLine("{0} --> {1}", value, Regex.Replace(value, pattern, replacement));
}
}
// The example displays the following output:
// 16.35 --> $ 16.35
// 19.72 --> $ 19.72
// 1234 --> $ 1234
// 0.99 --> $ 0.99
Imports System.Globalization
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
' Define array of decimal values.
Dim values() As String = { "16.35", "19.72", "1234", "0.99"}
' Determine whether currency precedes (True) or follows (False) number.
Dim precedes As Boolean = (NumberFormatInfo.CurrentInfo.CurrencyPositivePattern Mod 2 = 0)
' Get decimal separator.
Dim cSeparator As String = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator
' Get currency symbol.
Dim symbol As String = NumberFormatInfo.CurrentInfo.CurrencySymbol
' If symbol is a "$", add an extra "$".
If symbol = "$" Then symbol = "$$"

' Define regular expression pattern and replacement string.


Dim pattern As String = "\b(\d+)(" + cSeparator + "(\d+))?"
Dim replacement As String = "$1$2"
replacement = If(precedes, symbol + " " + replacement, replacement + " " + symbol)
For Each value In values
Console.WriteLine("{0} --> {1}", value, Regex.Replace(value, pattern, replacement))
Next
End Sub
End Module
' The example displays the following output:
' 16.35 --> $ 16.35
' 19.72 --> $ 19.72
' 1234 --> $ 1234
' 0.99 --> $ 0.99

El patrón de expresión regular \b(\d+)(\.(\d+))? se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Comenzar la búsqueda de coincidencias al principio de un


límite de palabras.

(\d+) Buscar coincidencias con uno o más dígitos decimales. Este es


el primer grupo de captura.

\. Buscar coincidencias con un punto (el separador decimal).

(\d+) Buscar coincidencias con uno o más dígitos decimales. Éste es


el tercer grupo de captura.

(\.(\d+))? Buscar una coincidencia con cero o una aparición de un punto


seguido de uno o más dígitos decimales. Este es el segundo
grupo de captura.

Sustituir toda la coincidencia


La sustitución $& incluye toda la coincidencia en la cadena de reemplazo. A menudo, se usa para agregar una
subcadena al principio o final de la cadena coincidente. Por ejemplo, el patrón de reemplazo ($&) agrega un
paréntesis al principio y al final de cada coincidencia. Si no hay ninguna coincidencia, la sustitución $& no tiene
ningún efecto.
En el ejemplo siguiente, se usa la sustitución $& para agregar comillas al principio y al final de los títulos de los
libros almacenados en una matriz de cadena.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"^(\w+\s?)+$";
string[] titles = { "A Tale of Two Cities",
"The Hound of the Baskervilles",
"The Protestant Ethic and the Spirit of Capitalism",
"The Origin of Species" };
string replacement = "\"$&\"";
foreach (string title in titles)
Console.WriteLine(Regex.Replace(title, pattern, replacement));
}
}
// The example displays the following output:
// "A Tale of Two Cities"
// "The Hound of the Baskervilles"
// "The Protestant Ethic and the Spirit of Capitalism"
// "The Origin of Species"

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^(\w+\s?)+$"
Dim titles() As String = { "A Tale of Two Cities", _
"The Hound of the Baskervilles", _
"The Protestant Ethic and the Spirit of Capitalism", _
"The Origin of Species" }
Dim replacement As String = """$&"""
For Each title As String In titles
Console.WriteLine(Regex.Replace(title, pattern, replacement))
Next
End Sub
End Module
' The example displays the following output:
' "A Tale of Two Cities"
' "The Hound of the Baskervilles"
' "The Protestant Ethic and the Spirit of Capitalism"
' "The Origin of Species"

El patrón de expresión regular ^(\w+\s?)+$ se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Comenzar la búsqueda de coincidencias al principio de la


cadena de entrada.

(\w+\s?)+ Buscar coincidencias con el patrón de uno o varios caracteres


de palabra seguidos de cero o un carácter de espacio en
blanco una o varias veces.

$ Coincide con el final de la cadena de entrada.

El patrón de reemplazo "$&" agrega una comilla literal al principio y al final de cada coincidencia.

Sustituir el texto delante de la coincidencia


La sustitución $` reemplaza la cadena coincidente por la cadena de entrada completa delante de la coincidencia.
Es decir, duplica la cadena de entrada hasta la coincidencia quitando el texto coincidente. Cualquier texto que siga
al texto coincidente no cambia en la cadena de resultado. Si hay varias coincidencias en una cadena de entrada, el
texto de reemplazo se deriva de la cadena de entrada original, en lugar de la cadena en la que coincidencias
anteriores han reemplazado el texto. (En el ejemplo se ofrece una ilustración.) Si no hay ninguna coincidencia, la
sustitución $` no tiene ningún efecto.
En el ejemplo siguiente, se usa el patrón de expresión regular \d+ para que coincida con una secuencia de uno o
más dígitos decimales en la cadena de entrada. La cadena de reemplazo $` reemplaza estos dígitos por el texto
que antecede a la coincidencia.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "aa1bb2cc3dd4ee5";
string pattern = @"\d+";
string substitution = "$`";
Console.WriteLine("Matches:");
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);

Console.WriteLine("Input string: {0}", input);


Console.WriteLine("Output string: " +
Regex.Replace(input, pattern, substitution));
}
}
// The example displays the following output:
// Matches:
// 1 at position 2
// 2 at position 5
// 3 at position 8
// 4 at position 11
// 5 at position 14
// Input string: aa1bb2cc3dd4ee5
// Output string: aaaabbaa1bbccaa1bb2ccddaa1bb2cc3ddeeaa1bb2cc3dd4ee
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "aa1bb2cc3dd4ee5"
Dim pattern As String = "\d+"
Dim substitution As String = "$`"
Console.WriteLine("Matches:")
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
Console.WriteLine("Input string: {0}", input)
Console.WriteLine("Output string: " + _
Regex.Replace(input, pattern, substitution))
End Sub
End Module
' The example displays the following output:
' Matches:
' 1 at position 2
' 2 at position 5
' 3 at position 8
' 4 at position 11
' 5 at position 14
' Input string: aa1bb2cc3dd4ee5
' Output string: aaaabbaa1bbccaa1bb2ccddaa1bb2cc3ddeeaa1bb2cc3dd4ee

En este ejemplo, la cadena de entrada "aa1bb2cc3dd4ee5" contiene cinco coincidencias. En la siguiente tabla se
muestra cómo la sustitución $` hace que el motor de expresiones regulares reemplace cada coincidencia en la
cadena de entrada. El texto insertado se muestra en negrita en la columna de resultados.

CADENA ANTES DE LA
COINCIDIR CON POSICIÓN COINCIDENCIA CADENA DE RESULTADO

1 2 aa aaaabb2cc3dd4ee5

2 5 aa1bb aaaabbaa1bbcc3dd4ee5

3 8 aa1bb2cc aaaabbaa1bbccaa1bb2ccdd
4ee5

4 11 aa1bb2cc3dd aaaabbaa1bbccaa1bb2ccdda
a1bb2cc3ddee5

5 14 aa1bb2cc3dd4ee aaaabbaa1bbccaa1bb2ccdda
a1bb2cc3ddeeaa1bb2cc3d
d4ee

Sustituir el texto detrás de la coincidencia


La sustitución $' reemplaza la cadena coincidente por la cadena de entrada completa después de la coincidencia.
Es decir, duplica la cadena de entrada después de la coincidencia quitando el texto coincidente. Cualquier texto que
anteceda al texto coincidente no cambia en la cadena de resultado. Si no hay ninguna coincidencia, la sustitución
$' no tiene ningún efecto.

En el ejemplo siguiente, se usa el patrón de expresión regular \d+ para que coincida con una secuencia de uno o
más dígitos decimales en la cadena de entrada. La cadena de reemplazo $' reemplaza estos dígitos por el texto
que sigue a la coincidencia.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "aa1bb2cc3dd4ee5";
string pattern = @"\d+";
string substitution = "$'";
Console.WriteLine("Matches:");
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(" {0} at position {1}", match.Value, match.Index);
Console.WriteLine("Input string: {0}", input);
Console.WriteLine("Output string: " +
Regex.Replace(input, pattern, substitution));
}
}
// The example displays the following output:
// Matches:
// 1 at position 2
// 2 at position 5
// 3 at position 8
// 4 at position 11
// 5 at position 14
// Input string: aa1bb2cc3dd4ee5
// Output string: aabb2cc3dd4ee5bbcc3dd4ee5ccdd4ee5ddee5ee

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "aa1bb2cc3dd4ee5"
Dim pattern As String = "\d+"
Dim substitution As String = "$'"
Console.WriteLine("Matches:")
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(" {0} at position {1}", match.Value, match.Index)
Next
Console.WriteLine("Input string: {0}", input)
Console.WriteLine("Output string: " + _
Regex.Replace(input, pattern, substitution))
End Sub
End Module
' The example displays the following output:
' Matches:
' 1 at position 2
' 2 at position 5
' 3 at position 8
' 4 at position 11
' 5 at position 14
' Input string: aa1bb2cc3dd4ee5
' Output string: aabb2cc3dd4ee5bbcc3dd4ee5ccdd4ee5ddee5ee

En este ejemplo, la cadena de entrada "aa1bb2cc3dd4ee5" contiene cinco coincidencias. En la siguiente tabla se
muestra cómo la sustitución $' hace que el motor de expresiones regulares reemplace cada coincidencia en la
cadena de entrada. El texto insertado se muestra en negrita en la columna de resultados.

CADENA DESPUÉS DE LA
COINCIDIR CON POSICIÓN COINCIDENCIA CADENA DE RESULTADO
CADENA DESPUÉS DE LA
COINCIDIR CON POSICIÓN COINCIDENCIA CADENA DE RESULTADO

1 2 bb2cc3dd4ee5 aabb2cc3dd4ee5bb2cc3dd
4ee5

2 5 cc3dd4ee5 aabb2cc3dd4ee5bbcc3dd4e
e5cc3dd4ee5

3 8 dd4ee5 aabb2cc3dd4ee5bbcc3dd4e
e5ccdd4ee5dd4ee5

4 11 ee5 aabb2cc3dd4ee5bbcc3dd4e
e5ccdd4ee5ddee5ee5

5 14 String.Empty aabb2cc3dd4ee5bbcc3dd4e
e5ccdd4ee5ddee5ee

Sustituir el último grupo capturado


La sustitución $+ reemplaza la cadena coincidente por el último grupo capturado. Si no hay ningún grupo
capturado o si el valor del último grupo capturado es String.Empty, la sustitución $+ no tiene ningún efecto.
En el ejemplo siguiente se identifican las palabras duplicadas en una cadena y se usa la sustitución $+ para
reemplazarlas por una aparición única de la palabra. La opción RegexOptions.IgnoreCase se usa para garantizar
que palabras que difieren en el uso de mayúsculas y minúsculas, pero que de lo contrario son idénticas, se
consideren duplicadas.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\w+)\s\1\b";
string substitution = "$+";
string input = "The the dog jumped over the fence fence.";
Console.WriteLine(Regex.Replace(input, pattern, substitution,
RegexOptions.IgnoreCase));
}
}
// The example displays the following output:
// The dog jumped over the fence.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\w+)\s\1\b"
Dim substitution As String = "$+"
Dim input As String = "The the dog jumped over the fence fence."
Console.WriteLine(Regex.Replace(input, pattern, substitution, _
RegexOptions.IgnoreCase))
End Sub
End Module
' The example displays the following output:
' The dog jumped over the fence.
El patrón de expresión regular \b(\w+)\s\1\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este es el primer grupo de captura.

\s Coincide con un carácter de espacio en blanco.

\1 Buscar una coincidencia con el primer grupo capturado.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Sustituir toda la cadena de entrada


La sustitución $_ reemplaza la cadena coincidente por la cadena de entrada completa. Es decir, quita el texto
coincidente y lo reemplaza por la cadena completa, incluyendo el texto coincidente.
En el ejemplo siguiente se buscan coincidencias para uno o más dígitos decimales en la cadena de entrada. Se usa
la sustitución $_ para reemplazarlos por la cadena de entrada completa.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "ABC123DEF456";
string pattern = @"\d+";
string substitution = "$_";
Console.WriteLine("Original string: {0}", input);
Console.WriteLine("String with substitution: {0}",
Regex.Replace(input, pattern, substitution));
}
}
// The example displays the following output:
// Original string: ABC123DEF456
// String with substitution: ABCABC123DEF456DEFABC123DEF456

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "ABC123DEF456"
Dim pattern As String = "\d+"
Dim substitution As String = "$_"
Console.WriteLine("Original string: {0}", input)
Console.WriteLine("String with substitution: {0}", _
Regex.Replace(input, pattern, substitution))
End Sub
End Module
' The example displays the following output:
' Original string: ABC123DEF456
' String with substitution: ABCABC123DEF456DEFABC123DEF456
En este ejemplo, la cadena de entrada "ABC123DEF456" contiene dos coincidencias. En la siguiente tabla se muestra
cómo la sustitución $_ hace que el motor de expresiones regulares reemplace cada coincidencia en la cadena de
entrada. El texto insertado se muestra en negrita en la columna de resultados.

COINCIDIR CON POSICIÓN COINCIDIR CON CADENA DE RESULTADO

1 3 123 ABCABC123DEF456DEF456

2 5 456 ABCABC123DEF456DEFABC
123DEF456

Vea también
Lenguaje de expresiones regulares: referencia rápida
Opciones de expresiones regulares
25/11/2019 • 71 minutes to read • Edit Online

De forma predeterminada, al comparar una cadena de entrada con los caracteres literales de un patrón de
expresión regular, se distinguen mayúsculas de minúsculas, los espacios en blanco del patrón de expresión
regular se interpretan como caracteres de espacio en blanco literales, y los grupos de captura de la
expresión regular se denominan tanto implícita como explícitamente. Estos y otros aspectos del
comportamiento predeterminado de la expresión regular se pueden modificar mediante la especificación
de las opciones de la expresión regular. Estas opciones —que aparecen enumeradas en la tabla siguiente
— se pueden insertar como parte del patrón de expresión regular, o se pueden suministrar a un
constructor de clases System.Text.RegularExpressions.Regex o a un método estático de coincidencia de
patrones como valor de enumeración de System.Text.RegularExpressions.RegexOptions.

MIEMBRO REGEXOPTIONS CARÁCTER INSERTADO EFECTO

None No disponible Usar el comportamiento


predeterminado. Para obtener más
información, consulte Opciones
predeterminadas.

IgnoreCase i Usa la coincidencia sin distinción


entre mayúsculas y minúsculas. Para
obtener más información, consulte la
sección Coincidencia sin distinción
entre mayúsculas y minúsculas.

Multiline m Usar el modo multilínea, donde ^ y


$ coinciden con el principio y el
final de cada línea (en lugar del
principio y el final de la cadena de
entrada). Para obtener más
información, consulte la sección
Modo multilínea.

Singleline s Usar el modo de una sola línea,


donde el punto (.) coincide con
todos los caracteres (en lugar de
todos los caracteres excepto \n ).
Para obtener más información,
consulte la sección Modo de una
sola línea.

ExplicitCapture n No se capturan grupos sin nombre.


Las únicas capturas válidas son
grupos con nombre explícito o
numerados con el formato (?<
nombre > subexpresión ) . Para
obtener más información, consulte la
sección Solo capturas explícitas.
MIEMBRO REGEXOPTIONS CARÁCTER INSERTADO EFECTO

Compiled No disponible Compilar la expresión regular en un


ensamblado. Para obtener más
información, consulte la sección
Expresiones regulares compiladas.

IgnorePatternWhitespace x Excluir del patrón el espacio en


blanco sin escape y habilitar los
comentarios tras un signo de
número ( # ). Para obtener más
información, consulte la sección
Ignorar el espacio en blanco.

RightToLeft No disponible Cambiar la dirección de búsqueda.


La búsqueda se mueve de derecha a
izquierda en vez de de izquierda a
derecha. Para obtener más
información, consulte la sección
Modo de derecha a izquierda.

ECMAScript No disponible Habilitar un comportamiento


conforme a ECMAScript para la
expresión. Para obtener más
información, consulte la sección
Comportamiento de búsqueda de
coincidencias de ECMAScript.

CultureInvariant No disponible Ignorar las diferencias culturales de


idioma. Para obtener más
información, consulte la sección
Comparación con la referencia
cultural de todos los idiomas.

Especificación de opciones
Las opciones de las expresiones regulares se pueden especificar de tres modos:
En el parámetro options de un constructor de clases System.Text.RegularExpressions.Regex o
método de coincidencia de patrones estático ( Shared en Visual Basic), como Regex.Regex(String,
RegexOptions) o Regex.Match(String, String, RegexOptions). El parámetro options es una
combinación OR bit a bit de valores enumerados de
System.Text.RegularExpressions.RegexOptions.
Cuando se proporcionan opciones a una instancia Regex mediante el parámetro options de un
constructor de clase, las opciones se asignan a la propiedad
System.Text.RegularExpressions.RegexOptions. Sin embargo, la propiedad
System.Text.RegularExpressions.RegexOptions no refleja las opciones insertadas en el mismo
patrón de expresión regular.
Esto se muestra en el ejemplo siguiente. Usa el parámetro options del método
Regex.Match(String, String, RegexOptions) para habilitar la coincidencia sin distinción entre
mayúsculas y minúsculas, así como para ignorar el espacio en blanco del patrón a la hora de
identificar palabras que empiecen por la letra “d”.
string pattern = @"d \w+ \s";
string input = "Dogs are decidedly good pets.";
RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace;

foreach (Match match in Regex.Matches(input, pattern, options))


Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index);
// The example displays the following output:
// 'Dogs // found at index 0.
// 'decidedly // found at index 9.

Dim pattern As String = "d \w+ \s"


Dim input As String = "Dogs are decidedly good pets."
Dim options As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.IgnorePatternWhitespace

For Each match As Match In Regex.Matches(input, pattern, options)


Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Dogs ' found at index 0.
' 'decidedly ' found at index 9.

Con la aplicación de las opciones insertadas en un patrón de expresión regular con la sintaxis
(?imnsx-imnsx) . La opción se aplica al patrón a partir del punto en que la opción se define hasta el
final del patrón o hasta el punto en que otra opción insertada deja a la opción sin definir. Tenga en
cuenta que la propiedad System.Text.RegularExpressions.RegexOptions de una instancia Regex no
refleja estas opciones insertadas. Para más información, consulte el tema Construcciones
misceláneas.
Esto se muestra en el ejemplo siguiente. Usa opciones insertadas para habilitar la coincidencia sin
distinción entre mayúsculas y minúsculas, así como para ignorar el espacio en blanco del patrón a
la hora de identificar palabras que empiecen por la letra “d”.

string pattern = @"(?ix) d \w+ \s";


string input = "Dogs are decidedly good pets.";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index);
// The example displays the following output:
// 'Dogs // found at index 0.
// 'decidedly // found at index 9.

Dim pattern As String = "\b(?ix) d \w+ \s"


Dim input As String = "Dogs are decidedly good pets."

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Dogs ' found at index 0.
' 'decidedly ' found at index 9.

Con la aplicación de opciones insertadas en una construcción de agrupamiento determinada en un


patrón de expresión regular con la sintaxis (?imnsx-imnsx: subexpresión ) . El conjunto de opciones
se activa si no va precedido por un signo y se desactiva si va precedido por un signo menos. ( ? es
una parte fija de la sintaxis del constructor de lenguaje que se necesita si las opciones están
habilitadas o deshabilitadas). La opción solo se aplica a ese grupo. Para más información, consulte
Construcciones de agrupamiento.
Esto se muestra en el ejemplo siguiente. Usa opciones insertadas en una construcción de
agrupamiento para habilitar la coincidencia sin distinción entre mayúsculas y minúsculas, así como
para ignorar el espacio en blanco del patrón a la hora de identificar palabras que empiecen por la
letra “d”.

string pattern = @"\b(?ix: d \w+)\s";


string input = "Dogs are decidedly good pets.";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index);
// The example displays the following output:
// 'Dogs // found at index 0.
// 'decidedly // found at index 9.

Dim pattern As String = "\b(?ix: d \w+)\s"


Dim input As String = "Dogs are decidedly good pets."

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Dogs ' found at index 0.
' 'decidedly ' found at index 9.

Si las opciones están insertadas, un signo menos ( - ) antes de una opción o conjunto de opciones
desactiva dichas opciones. Por ejemplo, la construcción insertada (?ix-ms) activa las opciones
RegexOptions.IgnoreCase y RegexOptions.IgnorePatternWhitespace y desactiva las opciones
RegexOptions.Multiline y RegexOptions.Singleline. Todas las opciones de expresión regular están
desactivadas de forma predeterminada.

NOTE
Si las opciones de expresión regular especificadas en el parámetro options de un constructor o llamada a método
están en conflicto con las opciones insertadas en un patrón de expresión regular, se usan las opciones insertadas.

Las siguientes opciones de expresión regular se pueden establecer con el parámetro y mediante inserción:
RegexOptions.IgnoreCase
RegexOptions.Multiline
RegexOptions.Singleline
RegexOptions.ExplicitCapture
RegexOptions.IgnorePatternWhitespace
Las siguientes cinco opciones de expresión regular se pueden establecer con el parámetro options , pero
no mediante inserción:
RegexOptions.None
RegexOptions.Compiled
RegexOptions.RightToLeft
RegexOptions.CultureInvariant
RegexOptions.ECMAScript
Determinación de opciones
Se pueden determinar las opciones que se proporcionaron a un objeto Regex al crearse su instancia; para
ello, recupere el valor de la propiedad Regex.Options de solo lectura. Esta propiedad resulta
especialmente útil para determinar las opciones definidas para una expresión regular compilada que se ha
creado con el método Regex.CompileToAssembly.
Para probar la presencia de cualquier opción, excepto RegexOptions.None, realice una operación AND
con el valor de la propiedad Regex.Options y el valor de RegexOptions en el que esté interesado. Después,
pruebe si el resultado es igual a ese valor RegexOptions. En el ejemplo siguiente se prueba si se ha
establecido la opción RegexOptions.IgnoreCase.

if ((rgx.Options & RegexOptions.IgnoreCase) == RegexOptions.IgnoreCase)


Console.WriteLine("Case-insensitive pattern comparison.");
else
Console.WriteLine("Case-sensitive pattern comparison.");

If (rgx.Options And RegexOptions.IgnoreCase) = RegexOptions.IgnoreCase Then


Console.WriteLine("Case-insensitive pattern comparison.")
Else
Console.WriteLine("Case-sensitive pattern comparison.")
End If

Para probar RegexOptions.None, determine si el valor de la propiedad Regex.Options es igual a


RegexOptions.None, tal como se muestra en el ejemplo siguiente.

if (rgx.Options == RegexOptions.None)
Console.WriteLine("No options have been set.");

If rgx.Options = RegexOptions.None Then


Console.WriteLine("No options have been set.")
End If

En las secciones siguientes se enumeran las opciones admitidas en una expresión regular de .NET.

Opciones predeterminadas
La opción RegexOptions.None indica que no se ha especificado ninguna opción y que el motor de
expresiones regulares sigue su comportamiento predeterminado. Entre estas estructuras se incluyen las
siguientes:
El patrón se interpreta como un canónico en vez de como una expresión regular ECMAScript.
El patrón de expresión regular se compara con la cadena de entrada de izquierda a derecha.
Las comparaciones distinguen entre mayúsculas y minúsculas.
Los elementos de lenguaje ^ y $ coinciden con el principio y el final de la cadena de entrada.
El elemento de lenguaje . coincide con todos los caracteres excepto \n .
Un espacio en blanco en un patrón de expresión regular se interpreta como un carácter de espacio
literal.
Las convenciones de la referencia cultural actual se usan al comparar el patrón con la cadena de
entrada.
Los grupos de captura del patrón de expresión regular son implícitos y explícitos.

NOTE
La opción RegexOptions.None no tiene ningún equivalente de inserción. Cuando las opciones de expresión regular
se aplican mediante inserción, el comportamiento predeterminado se restaura opción por opción, mediante la
desactivación de una opción concreta. Por ejemplo, (?i) activa la comparación sin distinción entre mayúsculas y
minúsculas, y (?-i) restaura la comparación con distinción entre mayúsculas y minúsculas.

Debido a que la opción RegexOptions.None representa el comportamiento predeterminado del motor de


expresiones regulares, casi nunca se especifica de forma explícita en una llamada a método. En su lugar, se
llama a un constructor o método estático de coincidencia de patrones sin un parámetro options .

Coincidencia sin distinción entre mayúsculas y minúsculas


La opción IgnoreCase, o la opción insertada i , proporciona coincidencia sin distinción entre mayúsculas
y minúsculas. De forma predeterminada, se usan las convenciones sobre el uso de mayúsculas de la
referencia cultural actual.
En el ejemplo siguiente se define un patrón de expresión regular, \bthe\w*\b , por el que coinciden todas
las palabras que empiezan por “the”. Debido a que la primera llamada al método Match usa la
comparación predeterminada con distinción entre mayúsculas y minúsculas, el resultado indica que no
hay coincidencia con la cadena “The” del inicio de la oración. Hay coincidencia cuando se llama al método
Match con las opciones establecidas en IgnoreCase.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\bthe\w*\b";
string input = "The man then told them about that event.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index);

Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnoreCase))
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index);
}
}
// The example displays the following output:
// Found then at index 8.
// Found them at index 18.
//
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\bthe\w*\b"
Dim input As String = "The man then told them about that event."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern, _
RegexOptions.IgnoreCase)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found then at index 8.
' Found them at index 18.
'
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.

En el ejemplo siguiente se modifica el patrón de expresión regular del ejemplo anterior a fin de usar las
opciones insertadas en vez del parámetro options para realizar la comparación sin distinción entre
mayúsculas y minúsculas. El primer parámetro define la opción sin distinción entre mayúsculas y
minúsculas en una construcción de agrupamiento que se aplica solo a la letra “t” de la cadena “the”. Como
la construcción de opciones ocurre al principio del patrón, el segundo patrón aplica la opción sin
distinción entre mayúsculas y minúsculas a toda la expresión regular.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(?i:t)he\w*\b";
string input = "The man then told them about that event.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index);

Console.WriteLine();
pattern = @"(?i)\bthe\w*\b";
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnoreCase))
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index);
}
}
// The example displays the following output:
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
//
// Found The at index 0.
// Found then at index 8.
// Found them at index 18.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(?i:t)he\w*\b"
Dim input As String = "The man then told them about that event."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
Console.WriteLine()
pattern = "(?i)\bthe\w*\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found {0} at index {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.
'
' Found The at index 0.
' Found then at index 8.
' Found them at index 18.

Modo multilínea
La opción RegexOptions.Multiline, o la opción insertada m , habilita al motor de expresiones regulares
para que controle una cadena de entrada que consta de varias líneas. Cambia la interpretación de los
elementos de lenguaje ^ y $ de modo que coincidan con el inicio y el final de una línea, en vez de con el
inicio y el final de la cadena de entrada.
De forma predeterminada, $ coincide solo con el final de la cadena de entrada. Si se especifica la opción
RegexOptions.Multiline, coincide con el carácter de nueva línea ( \n ) o con el final de la cadena de
entrada. Sin embargo, no coincide con la combinación de caracteres de retorno de carro y salto de línea.
Para que coincida correctamente, use la subexpresión \r?$ en vez de simplemente $ .
En el ejemplo siguiente se extraen los nombres y las puntuaciones de los jugadores de bolos y se agregan
a una colección SortedList<TKey,TValue> que los ordena en sentido descendente. Se realizan dos
llamadas al método Matches. En la primera llamada a método, la expresión regular es ^(\w+)\s(\d+)$ y
no se establece ninguna opción. Como muestra el resultado, no se encuentran coincidencias, ya que el
motor de expresiones regulares no puede hacer coincidir el patrón de entrada junto con el principio y el
final de la cadena de entrada. En la segunda llamada a método, la expresión regular se cambia a
^(\w+)\s(\d+)\r?$ y las opciones se establecen en RegexOptions.Multiline. Como muestra el resultado,
los nombres y las puntuaciones coinciden correctamente, y las puntuaciones aparecen en orden
descendente.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
SortedList<int, string> scores = new SortedList<int, string>(new DescendingComparer<int>());

string input = "Joe 164\n" +


"Sam 208\n" +
"Allison 211\n" +
"Gwen 171\n";
string pattern = @"^(\w+)\s(\d+)$";
bool matched = false;

Console.WriteLine("Without Multiline option:");


foreach (Match match in Regex.Matches(input, pattern))
{
scores.Add(Int32.Parse(match.Groups[2].Value), (string) match.Groups[1].Value);
matched = true;
}
if (! matched)
Console.WriteLine(" No matches.");
Console.WriteLine();

// Redefine pattern to handle multiple lines.


pattern = @"^(\w+)\s(\d+)\r*$";
Console.WriteLine("With multiline option:");
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))
scores.Add(Int32.Parse(match.Groups[2].Value), (string) match.Groups[1].Value);

// List scores in descending order.


foreach (KeyValuePair<int, string> score in scores)
Console.WriteLine("{0}: {1}", score.Value, score.Key);
}
}

public class DescendingComparer<T> : IComparer<T>


{
public int Compare(T x, T y)
{
return Comparer<T>.Default.Compare(x, y) * -1;
}
}
// The example displays the following output:
// Without Multiline option:
// No matches.
//
// With multiline option:
// Allison: 211
// Sam: 208
// Gwen: 171
// Joe: 164
Imports System.Collections.Generic
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim scores As New SortedList(Of Integer, String)(New DescendingComparer(Of Integer)())

Dim input As String = "Joe 164" + vbCrLf + _


"Sam 208" + vbCrLf + _
"Allison 211" + vbCrLf + _
"Gwen 171" + vbCrLf
Dim pattern As String = "^(\w+)\s(\d+)$"
Dim matched As Boolean = False

Console.WriteLine("Without Multiline option:")


For Each match As Match In Regex.Matches(input, pattern)
scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
matched = True
Next
If Not matched Then Console.WriteLine(" No matches.")
Console.WriteLine()

' Redefine pattern to handle multiple lines.


pattern = "^(\w+)\s(\d+)\r*$"
Console.WriteLine("With multiline option:")
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)
scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
Next
' List scores in descending order.
For Each score As KeyValuePair(Of Integer, String) In scores
Console.WriteLine("{0}: {1}", score.Value, score.Key)
Next
End Sub
End Module

Public Class DescendingComparer(Of T) : Implements IComparer(Of T)


Public Function Compare(x As T, y As T) As Integer _
Implements IComparer(Of T).Compare
Return Comparer(Of T).Default.Compare(x, y) * -1
End Function
End Class
' The example displays the following output:
' Without Multiline option:
' No matches.
'
' With multiline option:
' Allison: 211
' Sam: 208
' Gwen: 171
' Joe: 164

El patrón de expresión regular ^(\w+)\s(\d+)\r*$ se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Comienza al principio de la línea.

(\w+) Buscar coincidencias con uno o más caracteres


alfabéticos. Este es el primer grupo de captura.

\s Coincide con un carácter de espacio en blanco.


MODELO DESCRIPCIÓN

(\d+) Buscar coincidencias con uno o más dígitos decimales.


Este es el segundo grupo de captura.

\r? Coincidencia con cero o con un carácter de retorno de


carro.

$ Finaliza al final de la línea.

El ejemplo siguiente es equivalente al anterior, a excepción de que usa la opción insertada (?m) para
establecer la opción multilínea.

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
SortedList<int, string> scores = new SortedList<int, string>(new DescendingComparer<int>());

string input = "Joe 164\n" +


"Sam 208\n" +
"Allison 211\n" +
"Gwen 171\n";
string pattern = @"(?m)^(\w+)\s(\d+)\r*$";

foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))


scores.Add(Convert.ToInt32(match.Groups[2].Value), match.Groups[1].Value);

// List scores in descending order.


foreach (KeyValuePair<int, string> score in scores)
Console.WriteLine("{0}: {1}", score.Value, score.Key);
}
}

public class DescendingComparer<T> : IComparer<T>


{
public int Compare(T x, T y)
{
return Comparer<T>.Default.Compare(x, y) * -1;
}
}
// The example displays the following output:
// Allison: 211
// Sam: 208
// Gwen: 171
// Joe: 164
Imports System.Collections.Generic
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim scores As New SortedList(Of Integer, String)(New DescendingComparer(Of Integer)())

Dim input As String = "Joe 164" + vbCrLf + _


"Sam 208" + vbCrLf + _
"Allison 211" + vbCrLf + _
"Gwen 171" + vbCrLf
Dim pattern As String = "(?m)^(\w+)\s(\d+)\r*$"

For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)


scores.Add(CInt(match.Groups(2).Value), match.Groups(1).Value)
Next
' List scores in descending order.
For Each score As KeyValuePair(Of Integer, String) In scores
Console.WriteLine("{0}: {1}", score.Value, score.Key)
Next
End Sub
End Module

Public Class DescendingComparer(Of T) : Implements IComparer(Of T)


Public Function Compare(x As T, y As T) As Integer _
Implements IComparer(Of T).Compare
Return Comparer(Of T).Default.Compare(x, y) * -1
End Function
End Class
' The example displays the following output:
' Allison: 211
' Sam: 208
' Gwen: 171
' Joe: 164

Modo de una sola línea


La opción RegexOptions.Singleline, o la opción insertada s , hace que el motor de expresiones regulares
trate a la cadena de entrada como si constase de una única línea. Para ello, se cambia el comportamiento
del elemento de lenguaje punto ( . ) para que coincida con todos los caracteres, en vez de coincidir con
todos los caracteres excepto con el de nueva línea \n o \u000A.
En el ejemplo siguiente se muestra cómo cambia el comportamiento del elemento de lenguaje . cuando
se usa la opción RegexOptions.Singleline. La expresión regular ^.+ comienza en el principio de la cadena
y coincide con todos los caracteres. De forma predeterminada, la coincidencia termina al final de la
primera línea; el patrón de la expresión regular coincide con el carácter de retorno de carro, \r o \u000D,
pero no coincide con \n . Dado que la opción RegexOptions.Singleline interpreta la cadena de entrada
completa como una sola línea, coincide con cada carácter de la cadena de entrada, incluido \n .
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "^.+";
string input = "This is one line and" + Environment.NewLine + "this is the second.";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(Regex.Escape(match.Value));

Console.WriteLine();
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Singleline))
Console.WriteLine(Regex.Escape(match.Value));
}
}
// The example displays the following output:
// This\ is\ one\ line\ and\r
//
// This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^.+"
Dim input As String = "This is one line and" + vbCrLf + "this is the second."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(Regex.Escape(match.Value))
Next
Console.WriteLine()
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.SingleLine)
Console.WriteLine(Regex.Escape(match.Value))
Next
End Sub
End Module
' The example displays the following output:
' This\ is\ one\ line\ and\r
'
' This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.

El ejemplo siguiente es equivalente al anterior, a excepción de que usa la opción insertada (?s) para
habilitar el modo de una sola línea.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "(?s)^.+";
string input = "This is one line and" + Environment.NewLine + "this is the second.";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine(Regex.Escape(match.Value));
}
}
// The example displays the following output:
// This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "(?s)^.+"
Dim input As String = "This is one line and" + vbCrLf + "this is the second."

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine(Regex.Escape(match.Value))
Next
End Sub
End Module
' The example displays the following output:
' This\ is\ one\ line\ and\r\nthis\ is\ the\ second\.

Solo capturas explícitas


De forma predeterminada, los grupos de captura se definen con el uso de paréntesis en el patrón de
expresión regular. A los grupos con nombre se les asigna un nombre o un número con la opción de
lenguaje (?< nombre > subexpresión ) , mientras que a los grupos sin nombre se accede mediante el
índice. En el objeto GroupCollection, los grupos sin nombre preceden a los grupos con nombre.
A menudo, los constructores de agrupamiento se usan únicamente para aplicar cuantificadores a varios
elementos de lenguaje, y las subcadenas capturadas carecen de interés. Por ejemplo, en la expresión
regular siguiente:
\b\(?((\w+),?\s?)+[\.!?]\)?

Su única finalidad es extraer de un documento las oraciones que finalizan con un punto, signo de
exclamación o signo de interrogación, y solo la oración resultante (representada mediante el objeto
Match) es de interés. En cambio, las palabras individuales de la colección no son de interés.
Los grupos de captura que no se usan posteriormente pueden ser costosos, ya que el motor de
expresiones regulares debe rellenar los objetos de colección GroupCollection y CaptureCollection. Como
alternativa, se puede usar la opción RegexOptions.ExplicitCapture o la opción insertada n para
especificar que las únicas capturas válidas son grupos con nombre o número explícitos que se designan
mediante el constructor (?< nombre > subexpresión ) .
En el ejemplo siguiente se muestra información sobre las coincidencias devueltas por el patrón de
expresión regular \b\(?((\w+),?\s?)+[\.!?]\)? cuando se llama al método Match con y sin la opción
RegexOptions.ExplicitCapture. Tal como muestra el resultado de la primera llamada a método, el motor de
expresiones regulares rellena totalmente los objetos de colección GroupCollection y CaptureCollection
con información sobre las subcadenas capturadas. Dado que el segundo método se llama con options
establecido en RegexOptions.ExplicitCapture, no se captura información en grupos.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b\(?((?>\w+),?\s?)+[\.!?]\)?";
Console.WriteLine("With implicit captures:");
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine("The match: {0}", match.Value);
Console.WriteLine("The match: {0}", match.Value);
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value);
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value);
captureCtr++;
}
}
}
Console.WriteLine();
Console.WriteLine("With explicit captures only:");
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.ExplicitCapture))
{
Console.WriteLine("The match: {0}", match.Value);
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value);
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value);
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// With implicit captures:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// Group 1: sentence
// Capture 0: This
// Capture 1: is
// Capture 2: the
// Capture 3: first
// Capture 4: sentence
// Group 2: sentence
// Capture 0: This
// Capture 1: is
// Capture 2: the
// Capture 3: first
// Capture 4: sentence
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// Group 1: masterpiece
// Capture 0: Is
// Capture 1: it
// Capture 2: the
// Capture 3: beginning
// Capture 4: of
// Capture 5: a
// Capture 6: literary
// Capture 7: masterpiece
// Group 2: masterpiece
// Capture 0: Is
// Capture 1: it
// Capture 2: the
// Capture 3: beginning
// Capture 4: of
// Capture 5: a
// Capture 5: a
// Capture 6: literary
// Capture 7: masterpiece
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// Group 1: not
// Capture 0: I
// Capture 1: think
// Capture 2: not
// Group 2: not
// Capture 0: I
// Capture 1: think
// Capture 2: not
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
// Group 1: paragraph
// Capture 0: Instead,
// Capture 1: it
// Capture 2: is
// Capture 3: a
// Capture 4: nonsensical
// Capture 5: paragraph
// Group 2: paragraph
// Capture 0: Instead
// Capture 1: it
// Capture 2: is
// Capture 3: a
// Capture 4: nonsensical
// Capture 5: paragraph
//
// With explicit captures only:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " + _
"of a literary masterpiece? I think not. Instead, " + _
"it is a nonsensical paragraph."
Dim pattern As String = "\b\(?((?>\w+),?\s?)+[\.!?]\)?"
Console.WriteLine("With implicit captures:")
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
Next
Console.WriteLine()
Console.WriteLine("With explicit captures only:")
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.ExplicitCapture)
Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' With implicit captures:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' Group 1: sentence
' Capture 0: This
' Capture 1: is
' Capture 2: the
' Capture 3: first
' Capture 4: sentence
' Group 2: sentence
' Capture 0: This
' Capture 1: is
' Capture 2: the
' Capture 3: first
' Capture 4: sentence
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' Group 1: masterpiece
' Capture 0: Is
' Capture 1: it
' Capture 2: the
' Capture 3: beginning
' Capture 4: of
' Capture 5: a
' Capture 6: literary
' Capture 7: masterpiece
' Group 2: masterpiece
' Capture 0: Is
' Capture 1: it
' Capture 2: the
' Capture 3: beginning
' Capture 4: of
' Capture 5: a
' Capture 6: literary
' Capture 7: masterpiece
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' Group 1: not
' Capture 0: I
' Capture 1: think
' Capture 2: not
' Group 2: not
' Capture 0: I
' Capture 1: think
' Capture 2: not
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.
' Group 1: paragraph
' Capture 0: Instead,
' Capture 1: it
' Capture 2: is
' Capture 3: a
' Capture 4: nonsensical
' Capture 5: paragraph
' Group 2: paragraph
' Capture 0: Instead
' Capture 1: it
' Capture 2: is
' Capture 3: a
' Capture 4: nonsensical
' Capture 5: paragraph
'
' With explicit captures only:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.

El patrón de expresión regular \b\(?((?>\w+),?\s?)+[\.!?]\)? se define como se muestra en la siguiente


tabla.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

\(? Busca una coincidencia con cero o con una aparición de


los paréntesis de apertura ("(").

(?>\w+),? Busca una coincidencia con uno o más caracteres


alfabéticos seguidos de cero o una coma. No hay
retroceso al coincidir con caracteres alfabéticos.

\s? Busca una coincidencia con cero o un carácter de espacio


en blanco.

((\w+),?\s?)+ Busca una coincidencia con la combinación de uno o


varios caracteres de palabra, cero o una coma, y cero o
un carácter de espacio en blanco una o varias veces.

[\.!?]\)? Busca una coincidencia con cualquiera de los tres


símbolos de puntuación, seguidos de cero o un
paréntesis de cierre (")").

También se puede usar el elemento insertado (?n) para suprimir las capturas automáticas. En el ejemplo
siguiente se modifica el patrón de expresión regular anterior para usar el elemento insertado (?n) en vez
de la opción RegexOptions.ExplicitCapture.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"(?n)\b\(?((?>\w+),?\s?)+[\.!?]\)?";

foreach (Match match in Regex.Matches(input, pattern))


{
Console.WriteLine("The match: {0}", match.Value);
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value);
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value);
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " + _
"of a literary masterpiece? I think not. Instead, " + _
"it is a nonsensical paragraph."
Dim pattern As String = "(?n)\b\(?((?>\w+),?\s?)+[\.!?]\)?"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.

Finalmente, se puede usar el elemento de grupo insertado (?n:) para suprimir las capturas automáticas
grupo a grupo. En el ejemplo siguiente se modifica el patrón anterior para suprimir las capturas sin
nombre en el grupo externo, ((?>\w+),?\s?) . Observe que, de este modo, también se suprimen las
capturas sin nombre en el grupo interno.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b\(?(?n:(?>\w+),?\s?)+[\.!?]\)?";

foreach (Match match in Regex.Matches(input, pattern))


{
Console.WriteLine("The match: {0}", match.Value);
int groupCtr = 0;
foreach (Group group in match.Groups)
{
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value);
groupCtr++;
int captureCtr = 0;
foreach (Capture capture in group.Captures)
{
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value);
captureCtr++;
}
}
}
}
}
// The example displays the following output:
// The match: This is the first sentence.
// Group 0: This is the first sentence.
// Capture 0: This is the first sentence.
// The match: Is it the beginning of a literary masterpiece?
// Group 0: Is it the beginning of a literary masterpiece?
// Capture 0: Is it the beginning of a literary masterpiece?
// The match: I think not.
// Group 0: I think not.
// Capture 0: I think not.
// The match: Instead, it is a nonsensical paragraph.
// Group 0: Instead, it is a nonsensical paragraph.
// Capture 0: Instead, it is a nonsensical paragraph.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " + _
"of a literary masterpiece? I think not. Instead, " + _
"it is a nonsensical paragraph."
Dim pattern As String = "\b\(?(?n:(?>\w+),?\s?)+[\.!?]\)?"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("The match: {0}", match.Value)
Dim groupCtr As Integer = 0
For Each group As Group In match.Groups
Console.WriteLine(" Group {0}: {1}", groupCtr, group.Value)
groupCtr += 1
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
Console.WriteLine(" Capture {0}: {1}", captureCtr, capture.Value)
captureCtr += 1
Next
Next
Next
End Sub
End Module
' The example displays the following output:
' The match: This is the first sentence.
' Group 0: This is the first sentence.
' Capture 0: This is the first sentence.
' The match: Is it the beginning of a literary masterpiece?
' Group 0: Is it the beginning of a literary masterpiece?
' Capture 0: Is it the beginning of a literary masterpiece?
' The match: I think not.
' Group 0: I think not.
' Capture 0: I think not.
' The match: Instead, it is a nonsensical paragraph.
' Group 0: Instead, it is a nonsensical paragraph.
' Capture 0: Instead, it is a nonsensical paragraph.

Expresiones regulares compiladas


Las expresiones de .NET se interpretan de forma predeterminada. Cuando se crea una instancia de un
objeto Regex o se llama a un método Regex estático, el patrón de expresión regular se analiza en un
conjunto de códigos de operación para ejecutar la operación regular. Esto implica una contrapartida: el
coste de inicializar el motor de expresiones regulares se minimiza a costa del rendimiento en tiempo de
ejecución.
Si quiere usar expresiones regulares compiladas en vez de interpretadas, utilice la opción
RegexOptions.Compiled. En este caso, cuando un patrón se pasa al motor de expresiones regulares, se
analiza en un conjunto de códigos de operación y luego se convierte en Lenguaje intermedio de Microsoft
(MSIL, por sus siglas en inglés), que puede pasarse directamente a Common Language Runtime. Las
expresiones regulares compiladas maximizan el rendimiento en tiempo de ejecución a costa del tiempo de
inicialización.

NOTE
Una expresión regular solo se puede compilar si se suministra el valor RegexOptions.Compiled al parámetro
options de un constructor de clases Regex o de un método estático de coincidencia de patrones. No está
disponible como opción insertada.

Las expresiones regulares compiladas se pueden usar en llamadas a expresiones regulares estáticas y de
instancias. En expresiones regulares estáticas, la opción RegexOptions.Compiled se pasa al parámetro
options del método de coincidencia de patrones de expresión regular. En expresiones regulares de
instancia, se pasa al parámetro options del constructor de clases Regex. En ambos casos, tiene como
resultado una mejora en el rendimiento.
No obstante, esta mejora en el rendimiento solo se produce bajo las condiciones siguientes:
Un objeto Regex que representa una expresión regular concreta se usa en varias llamadas a
métodos de coincidencia de patrones de expresión regular.
El objeto Regex no puede estar fuera del ámbito y, por tanto, se puede volver a usar.
Una expresión regular estática se usa en varias llamadas a métodos de coincidencia de patrones de
expresión regular. (La mejora de rendimiento es posible porque el motor de expresiones regulares
almacena en la caché las expresiones regulares que se usan en llamadas de métodos estáticos).

NOTE
La opción RegexOptions.Compiled no está relacionada con el método Regex.CompileToAssembly, que crea un
ensamblado para fines especiales y que contiene expresiones regulares compiladas predefinidas.

Ignorar el espacio en blanco


De forma predeterminada, el espacio en blanco de un patrón de expresión regular es significativo; fuerza
al motor de expresiones regulares a buscar un carácter de espacio en blanco en la cadena de entrada.
Debido a ello, las expresiones regulares " \b\w+\s " y " \b\w+ " son, en líneas generales, expresiones
regulares equivalentes. Además, cuando el signo de número (#) se detecta en un patrón de expresión
regular, se interpreta como un carácter literal para el que se deben buscar coincidencias.
La opción RegexOptions.IgnorePatternWhitespace, o la opción insertada x , cambia su comportamiento
predeterminado del modo siguiente:
El espacio en blanco sin escape del patrón de expresión regular se ignora. Para formar parte de un
patrón de expresión regular, los caracteres de espacio en blanco se deben incluir en secuencias de
escape (por ejemplo, como \s o " \ ").
El signo de número (#) se interpreta como el inicio de un comentario, en vez de como carácter
literal. Todo el texto del patrón de expresión regular comprendido entre el carácter # y el final de la
cadena se interpreta como un comentario.
No obstante, en los casos siguientes, los caracteres de espacio de una expresión regular no se ignoran,
aunque se use la opción RegexOptions.IgnorePatternWhitespace:
Un espacio en blanco dentro de una clase de caracteres se interpreta siempre de forma literal. Por
ejemplo, el patrón de expresión regular [ .,;:] coincide con cualquier carácter de espacio en
blanco, punto, coma, punto y coma o dos puntos.
Los cuantificadores entre corchetes, como { n } , { n ,} y { n , m } , no admiten espacios en
blanco. Por ejemplo, el patrón de expresión regular \d{1, 3} no encontrará ninguna secuencia de
entre uno y tres guarismos porque contiene un carácter de espacio en blanco.
No se admiten espacios en blanco en una secuencia de caracteres que presenta un elemento de
lenguaje. Por ejemplo:
El elemento de lenguaje (?: subexpresión ) representa un grupo sin captura, y la parte
(?: del elemento no puede tener espacios insertados. El modelo (? : subexpresión )
produce una clase ArgumentException en tiempo de ejecución porque el motor de
expresiones regulares no puede analizar el modelo, y el modelo ( ?: subexpresión ) no
coincide con subexpresión.
El elemento de lenguaje \p{ nombre } , que representa una categoría Unicode o bloque
con nombre, no puede incluir espacios insertados en la parte \p{ del elemento. Si se
incluye un espacio en blanco, el elemento produce una ArgumentException en tiempo de
ejecución.
Esta opción sirve para simplificar las expresiones regulares que a menudo resultan difíciles de analizar y
entender. Además, mejora la legibilidad y posibilita la documentación de una expresión regular.
Este ejemplo define el siguiente patrón de expresión regular:
\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.

El modelo es similar al modelo definido en la sección Solo capturas explícitas a excepción de que utiliza la
opción RegexOptions.IgnorePatternWhitespace para ignorar el espacio en blanco del modelo.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.";

foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace))


Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// This is the first sentence.
// Is it the beginning of a literary masterpiece?
// I think not.
// Instead, it is a nonsensical paragraph.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " + _
"of a literary masterpiece? I think not. Instead, " + _
"it is a nonsensical paragraph."
Dim pattern As String = "\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence."

For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace)


Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' This is the first sentence.
' Is it the beginning of a literary masterpiece?
' I think not.
' Instead, it is a nonsensical paragraph.

En el ejemplo siguiente se usa la opción insertada (?x) para ignorar el espacio en blanco del patrón.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is the first sentence. Is it the beginning " +
"of a literary masterpiece? I think not. Instead, " +
"it is a nonsensical paragraph.";
string pattern = @"(?x)\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire sentence.";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// This is the first sentence.
// Is it the beginning of a literary masterpiece?
// I think not.
// Instead, it is a nonsensical paragraph.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is the first sentence. Is it the beginning " + _
"of a literary masterpiece? I think not. Instead, " + _
"it is a nonsensical paragraph."
Dim pattern As String = "(?x)\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # Matches an entire
sentence."

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' This is the first sentence.
' Is it the beginning of a literary masterpiece?
' I think not.
' Instead, it is a nonsensical paragraph.

Modo de derecha a izquierda


De forma predeterminada, el motor de expresiones regulares realiza las búsquedas de izquierda a
derecha. Para invertir la dirección de búsqueda, se puede usar la opción RegexOptions.RightToLeft. De
este modo, la búsqueda empieza automáticamente en la posición del último carácter de la cadena. En los
métodos de coincidencia de patrones que incluyen un parámetro de posición inicial, como
Regex.Match(String, Int32), la posición inicial es el índice del carácter situado más a la derecha en el que
debe empezar la búsqueda.

NOTE
El modo de patrón de derecha a izquierda solo está disponible si se suministra el valor RegexOptions.RightToLeft al
parámetro options de un constructor de clases Regex o de un método estático de coincidencia de patrones. No
está disponible como opción insertada.

La opción RegexOptions.RightToLeft únicamente cambia la dirección de búsqueda, no interpreta el patrón


de expresión regular de derecha a izquierda. Por ejemplo, la expresión regular \bb\w+\s coincide con las
palabras que empiezan por la letra “b” y van seguidas por un carácter de espacio en blanco. En el ejemplo
siguiente, la cadena de entrada consta de tres palabras que incluyen uno o varios caracteres “b”. La
primera palabra empieza por “b”, la segunda finaliza en “b” y la tercera incluye dos caracteres “b” en el
medio de la palabra. Tal como muestra el resultado del ejemplo, solo la primera palabra coincide con el
patrón de expresión regular.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\bb\w+\s";
string input = "builder rob rabble";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.RightToLeft))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);
}
}
// The example displays the following output:
// 'builder ' found at position 0.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\bb\w+\s"
Dim input As String = "builder rob rabble"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.RightToLeft)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' 'builder ' found at position 0.

Observe también que la aserción de búsqueda anticipada (el elemento de lenguaje (?= subexpresión ) ) y
la aserción de búsqueda tardía (el elemento de lenguaje (?<= subexpresión ) ) no cambian de dirección.
Las aserciones de búsqueda anticipada miran hacia la derecha, mientras que las de búsqueda tardía lo
hacen hacia la izquierda. Por ejemplo, la expresión regular (?<=\d{1,2}\s)\w+,?\s\d{4} usa la aserción de
búsqueda tardía para probar una fecha que precede al nombre de un mes. Después, la expresión regular
busca coincidencias con el mes y el año. Para información sobre aserciones de búsqueda anticipada y
tardía, consulte Construcciones de agrupamiento.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "1 May 1917", "June 16, 2003" };
string pattern = @"(?<=\d{1,2}\s)\w+,?\s\d{4}";

foreach (string input in inputs)


{
Match match = Regex.Match(input, pattern, RegexOptions.RightToLeft);
if (match.Success)
Console.WriteLine("The date occurs in {0}.", match.Value);
else
Console.WriteLine("{0} does not match.", input);
}
}
}
// The example displays the following output:
// The date occurs in May 1917.
// June 16, 2003 does not match.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "1 May 1917", "June 16, 2003" }
Dim pattern As String = "(?<=\d{1,2}\s)\w+,?\s\d{4}"

For Each input As String In inputs


Dim match As Match = Regex.Match(input, pattern, RegexOptions.RightToLeft)
If match.Success Then
Console.WriteLine("The date occurs in {0}.", match.Value)
Else
Console.WriteLine("{0} does not match.", input)
End If
Next
End Sub
End Module
' The example displays the following output:
' The date occurs in May 1917.
' June 16, 2003 does not match.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

(?<=\d{1,2}\s) El inicio de la coincidencia debe estar precedido por uno o


dos dígitos decimales seguidos de un espacio.

\w+ Buscar coincidencias con uno o más caracteres


alfabéticos.

,? Buscar coincidencias con cero o un carácter de coma.

\s Coincide con un carácter de espacio en blanco.

\d{4} Buscar coincidencias con cuatro dígitos decimales.


Comportamiento de búsqueda de coincidencias de ECMAScript
De forma predeterminada, el motor de expresiones regulares usa un comportamiento canónico al buscar
coincidencias entre un patrón de expresiones regulares y el texto de entrada. Sin embargo, se puede
especificar la opción RegexOptions.ECMAScript para hacer que el motor de expresiones regulares use el
comportamiento de búsqueda de coincidencias de ECMAScript.

NOTE
El comportamiento conforme a ECMAScript solo está disponible si se suministra el valor RegexOptions.ECMAScript
al parámetro options de un constructor de clases Regex o de un método estático de coincidencia de patrones.
No está disponible como opción insertada.

La opción RegexOptions.ECMAScript únicamente se puede combinar con las opciones


RegexOptions.IgnoreCase y RegexOptions.Multiline. El uso de cualquier otra opción en una expresión
regular provoca una ArgumentOutOfRangeException.
El comportamiento de las expresiones regulares canónicas y ECMAScript se diferencia en tres aspectos:
sintaxis de la clase de caracteres, grupos de captura con autorreferencia e interpretación de referencia
inversa frente a octal.
Sintaxis de la clase de caracteres. Debido a que las expresiones regulares canónicas admiten
Unicode y ECMAScript no, las clases de caracteres de ECMAScript tienen una sintaxis más limitada
y algunos elementos de lenguaje de clases de caracteres tienen un significado diferente. Por
ejemplo, ECMAScript no admite elementos de lenguaje como la categoría Unicode ni elementos
como \p y \P . De igual modo, el elemento \w , que coincide con un carácter literal, es
equivalente a la clase de caracteres [a-zA-Z_0-9] al usar ECMAScript y a
[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}] al usar comportamiento canónico. Para más
información, consulte Clases de caracteres.
En el ejemplo siguiente se muestra la diferencia entre la búsqueda de coincidencias canónica y la
de ECMAScript. Se define una expresión regular, \b(\w+\s*)+ , que busca coincidencias con
palabras seguidas de caracteres de espacio en blanco. La entrada consta de dos cadenas: una que
usa el conjunto de caracteres latinos y otra que usa el conjunto de caracteres del cirílico. Tal como
muestra el resultado, la llamada al método Regex.IsMatch(String, String, RegexOptions) que usa la
búsqueda de coincidencias de ECMAScript no encuentra coincidencias con las palabras del cirílico,
mientras que la llamada al método que usa la búsqueda de coincidencias canónica sí encuentra
coincidencias con estas palabras.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] values = { "целый мир", "the whole world" };
string pattern = @"\b(\w+\s*)+";
foreach (var value in values)
{
Console.Write("Canonical matching: ");
if (Regex.IsMatch(value, pattern))
Console.WriteLine("'{0}' matches the pattern.", value);
else
Console.WriteLine("{0} does not match the pattern.", value);

Console.Write("ECMAScript matching: ");


if (Regex.IsMatch(value, pattern, RegexOptions.ECMAScript))
Console.WriteLine("'{0}' matches the pattern.", value);
else
Console.WriteLine("{0} does not match the pattern.", value);
Console.WriteLine();
}
}
}
// The example displays the following output:
// Canonical matching: 'целый мир' matches the pattern.
// ECMAScript matching: целый мир does not match the pattern.
//
// Canonical matching: 'the whole world' matches the pattern.
// ECMAScript matching: 'the whole world' matches the pattern.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim values() As String = { "целый мир", "the whole world" }
Dim pattern As String = "\b(\w+\s*)+"
For Each value In values
Console.Write("Canonical matching: ")
If Regex.IsMatch(value, pattern)
Console.WriteLine("'{0}' matches the pattern.", value)
Else
Console.WriteLine("{0} does not match the pattern.", value)
End If

Console.Write("ECMAScript matching: ")


If Regex.IsMatch(value, pattern, RegexOptions.ECMAScript)
Console.WriteLine("'{0}' matches the pattern.", value)
Else
Console.WriteLine("{0} does not match the pattern.", value)
End If
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Canonical matching: 'целый мир' matches the pattern.
' ECMAScript matching: целый мир does not match the pattern.
'
' Canonical matching: 'the whole world' matches the pattern.
' ECMAScript matching: 'the whole world' matches the pattern.

Grupos de captura con autorreferencia. Una clase de captura de expresión regular con una
referencia inversa a sí misma debe actualizarse con cada iteración de captura. Como se muestra en
el ejemplo siguiente, esta característica permite a la expresión regular ((a+)(\1) ?)+ coincidir con
la cadena “ aa aaaa aaaaaa ” si se usa ECMAScript, pero no si se usa la búsqueda de coincidencias
canónica.
using System;
using System.Text.RegularExpressions;

public class Example


{
static string pattern;

public static void Main()


{
string input = "aa aaaa aaaaaa ";
pattern = @"((a+)(\1) ?)+";

// Match input using canonical matching.


AnalyzeMatch(Regex.Match(input, pattern));

// Match input using ECMAScript.


AnalyzeMatch(Regex.Match(input, pattern, RegexOptions.ECMAScript));
}

private static void AnalyzeMatch(Match m)


{
if (m.Success)
{
Console.WriteLine("'{0}' matches {1} at position {2}.",
pattern, m.Value, m.Index);
int grpCtr = 0;
foreach (Group grp in m.Groups)
{
Console.WriteLine(" {0}: '{1}'", grpCtr, grp.Value);
grpCtr++;
int capCtr = 0;
foreach (Capture cap in grp.Captures)
{
Console.WriteLine(" {0}: '{1}'", capCtr, cap.Value);
capCtr++;
}
}
}
else
{
Console.WriteLine("No match found.");
}
Console.WriteLine();
}
}
// The example displays the following output:
// No match found.
//
// '((a+)(\1) ?)+' matches aa aaaa aaaaaa at position 0.
// 0: 'aa aaaa aaaaaa '
// 0: 'aa aaaa aaaaaa '
// 1: 'aaaaaa '
// 0: 'aa '
// 1: 'aaaa '
// 2: 'aaaaaa '
// 2: 'aa'
// 0: 'aa'
// 1: 'aa'
// 2: 'aa'
// 3: 'aaaa '
// 0: ''
// 1: 'aa '
// 2: 'aaaa '
Imports System.Text.RegularExpressions

Module Example
Dim pattern As String

Public Sub Main()


Dim input As String = "aa aaaa aaaaaa "
pattern = "((a+)(\1) ?)+"

' Match input using canonical matching.


AnalyzeMatch(Regex.Match(input, pattern))

' Match input using ECMAScript.


AnalyzeMatch(Regex.Match(input, pattern, RegexOptions.ECMAScript))
End Sub

Private Sub AnalyzeMatch(m As Match)


If m.Success
Console.WriteLine("'{0}' matches {1} at position {2}.", _
pattern, m.Value, m.Index)
Dim grpCtr As Integer = 0
For Each grp As Group In m.Groups
Console.WriteLine(" {0}: '{1}'", grpCtr, grp.Value)
grpCtr += 1
Dim capCtr As Integer = 0
For Each cap As Capture In grp.Captures
Console.WriteLine(" {0}: '{1}'", capCtr, cap.Value)
capCtr += 1
Next
Next
Else
Console.WriteLine("No match found.")
End If
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' No match found.
'
' '((a+)(\1) ?)+' matches aa aaaa aaaaaa at position 0.
' 0: 'aa aaaa aaaaaa '
' 0: 'aa aaaa aaaaaa '
' 1: 'aaaaaa '
' 0: 'aa '
' 1: 'aaaa '
' 2: 'aaaaaa '
' 2: 'aa'
' 0: 'aa'
' 1: 'aa'
' 2: 'aa'
' 3: 'aaaa '
' 0: ''
' 1: 'aa '
' 2: 'aaaa '

La expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

(a+) Busca una coincidencia con la letra “a” una o más


veces. Este es el segundo grupo de captura.
MODELO DESCRIPCIÓN

(\1) Busca una coincidencia con la subcadena capturada


por el primer grupo de captura. Éste es el tercer
grupo de captura.

? Busca una coincidencia con cero o un carácter de


espacio.

((a+)(\1) ?)+ Busca una coincidencia con el patrón de uno o varios


caracteres “a” seguidos por una cadena que coincide
con el primer grupo de captura seguido por cero o
por un carácter de espacio una o varias veces. Este es
el primer grupo de captura.

Resolución de ambigüedades entre secuencias de escape octales y referencias inversas. En la tabla


siguiente se indican las diferencias en la interpretación de referencia inversa frente a octal por parte
de expresiones regulares canónicas y de ECMAScript.

EXPRESIÓN REGULAR COMPORTAMIENTO CANÓNICO COMPORTAMIENTO DE ECMASCRIPT

\0 seguido de 0 a 2 dígitos Se interpreta como un octal. Por Mismo comportamiento.


octales ejemplo, \044 se interpreta
siempre como un valor octal y
significa “$”.

\ seguido de un dígito de 1 a 9, Se interpreta como una referencia Si existe un grupo de captura de


seguido de ningún dígito decimal inversa. Por ejemplo, \9 siempre un solo dígito decimal, realice una
adicional significa una referencia inversa de referencia inversa a ese dígito. De
9, incluso si no existe un noveno lo contrario, interprete el valor
grupo de captura. Si el grupo de como literal.
captura no existe, el analizador de
expresiones regulares produce
una ArgumentException.

\ seguido de un dígito de 1 a 9, Interprete los dígitos como un Para interpretarlo como una
seguido de dígitos decimales valor decimal. Si existe ese grupo referencia inversa, convierta todos
adicionales de captura, interprete la expresión los dígitos posibles en un valor
como una referencia inversa. decimal que pueda hacer
referencia a una captura. Si no se
De lo contrario, interprete los puede convertir ningún dígito,
dígitos octales iniciales hasta el interprételo como un octal; para
octal 377; es decir, tenga en ello, use los dígitos octales
cuenta solo los 8 bits inferiores iniciales hasta el octal 377 e
del valor. Interprete el resto de interprete el resto de dígitos
dígitos como literales. Por como literales.
ejemplo, en la expresión \3000 ,
si existe el grupo de captura 300,
interprételo como referencia
inversa de 300; si el grupo de
captura 300 no existe,
interprételo como un octal 300
seguido de 0.

Comparación con la referencia cultural de todos los idiomas


De forma predeterminada, el motor de expresiones regulares, cuando realiza comparaciones sin distinguir
entre mayúsculas y minúsculas, utiliza las convenciones sobre el uso de mayúsculas de la referencia
cultural actual con el fin de determinar los caracteres equivalentes en mayúscula y minúscula.
Sin embargo, este comportamiento no es el deseado en algunos tipos de comparaciones, en particular al
comparar la entrada del usuario con los nombres de recursos del sistema, como pueden ser contraseñas,
archivos o direcciones URL. En el ejemplo siguiente se muestra ese escenario. La finalidad del código es
bloquear el acceso a los recursos cuya dirección URL va precedida de FILE:// . La expresión regular
intenta una búsqueda de coincidencias con la cadena sin distinguir entre mayúsculas y minúsculas y, a tal
fin, usa la expresión $FILE:// . Sin embargo, cuando la referencia cultural actual del sistema es tr-TR
(Turco -Turquía), “I” no es el equivalente en mayúscula de “i”. Como resultado, la llamada al método
Regex.IsMatch devuelve false , con lo que se permite el acceso al archivo.

CultureInfo defaultCulture = Thread.CurrentThread.CurrentCulture;


Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");

string input = "file://c:/Documents.MyReport.doc";


string pattern = "FILE://";

Console.WriteLine("Culture-sensitive matching ({0} culture)...",


Thread.CurrentThread.CurrentCulture.Name);
if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("URLs that access files are not allowed.");
else
Console.WriteLine("Access to {0} is allowed.", input);

Thread.CurrentThread.CurrentCulture = defaultCulture;
// The example displays the following output:
// Culture-sensitive matching (tr-TR culture)...
// Access to file://c:/Documents.MyReport.doc is allowed.

Dim defaultCulture As CultureInfo = Thread.CurrentThread.CurrentCulture


Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")

Dim input As String = "file://c:/Documents.MyReport.doc"


Dim pattern As String = "$FILE://"

Console.WriteLine("Culture-sensitive matching ({0} culture)...", _


Thread.CurrentThread.CurrentCulture.Name)
If Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase) Then
Console.WriteLine("URLs that access files are not allowed.")
Else
Console.WriteLine("Access to {0} is allowed.", input)
End If

Thread.CurrentThread.CurrentCulture = defaultCulture
' The example displays the following output:
' Culture-sensitive matching (tr-TR culture)...
' Access to file://c:/Documents.MyReport.doc is allowed.

NOTE
Para obtener más información sobre la comparación de cadenas con distinción entre mayúsculas y minúsculas, y
con la referencia cultural de todos los idiomas, consulte Procedimientos recomendados para el uso de cadenas.

En vez de usar comparaciones sin distinción entre mayúsculas y minúsculas de la referencia cultural
actual, se puede especificar la opción RegexOptions.CultureInvariant para ignorar las diferencias
culturales de idioma y usar las convenciones de la referencia cultural de todos los idiomas.
NOTE
La comparación con la referencia cultural de todos los idiomas solo está disponible si se suministra el valor
RegexOptions.CultureInvariant al parámetro options de un constructor de clases Regex o de un método estático
de coincidencia de patrones. No está disponible como opción insertada.

El ejemplo siguiente es idéntico al anterior, excepto que se llama al método Regex.IsMatch(String, String,
RegexOptions) estático con opciones que incluyen RegexOptions.CultureInvariant. A pesar de que la
referencia cultural actual está establecida en turco (Turquía), el motor de expresiones regulares es capaz
de encontrar coincidencias con “FILE” y “file” y bloquear el acceso al recurso de archivo.

CultureInfo defaultCulture = Thread.CurrentThread.CurrentCulture;


Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");

string input = "file://c:/Documents.MyReport.doc";


string pattern = "FILE://";

Console.WriteLine("Culture-insensitive matching...");
if (Regex.IsMatch(input, pattern,
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
Console.WriteLine("URLs that access files are not allowed.");
else
Console.WriteLine("Access to {0} is allowed.", input);

Thread.CurrentThread.CurrentCulture = defaultCulture;
// The example displays the following output:
// Culture-insensitive matching...
// URLs that access files are not allowed.

Dim defaultCulture As CultureInfo = Thread.CurrentThread.CurrentCulture


Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")

Dim input As String = "file://c:/Documents.MyReport.doc"


Dim pattern As String = "$FILE://"

Console.WriteLine("Culture-insensitive matching...")
If Regex.IsMatch(input, pattern, _
RegexOptions.IgnoreCase Or RegexOptions.CultureInvariant) Then
Console.WriteLine("URLs that access files are not allowed.")
Else
Console.WriteLine("Access to {0} is allowed.", input)
End If
Thread.CurrentThread.CurrentCulture = defaultCulture
' The example displays the following output:
' Culture-insensitive matching...
' URLs that access files are not allowed.

Vea también
Lenguaje de expresiones regulares: referencia rápida
Construcciones misceláneas en expresiones regulares
04/11/2019 • 11 minutes to read • Edit Online

Las expresiones regulares en .NET incluyen tres construcciones de lenguaje misceláneas. Una permite habilitar o
deshabilitar opciones de coincidencia determinadas en medio de un patrón de expresión regular. Las otras dos
permiten incluir comentarios en una expresión regular.

Opciones insertadas
Puede establecer o deshabilitar opciones de coincidencia de patrones específicas para una parte de una expresión
regular mediante la sintaxis
(?imnsx-imnsx)

Indique las opciones que quiere habilitar después del signo de interrogación y las opciones que quiere
deshabilitar después del signo menos. En la siguiente tabla se describe cada una de las opciones. Para obtener
más información sobre cada opción, consulte Opciones de expresiones regulares.

OPCIÓN DESCRIPCIÓN

i Coincidencia sin distinción entre mayúsculas y minúsculas.

m Modo multilínea.

n Solo capturas explícitas. (Los paréntesis no actúan como


grupos de capturas).

s Modo de una sola línea.

x Se omite el espacio en blanco sin escape y se permiten los


comentarios en modo X.

Cualquier cambio en las opciones de expresión regular definido mediante la construcción (?imnsx-imnsx)
permanece en vigor hasta el final del grupo envolvente.

NOTE
La construcción de agrupamiento (?imnsx-imnsx: subexpresión ) proporciona una funcionalidad idéntica para una
subexpresión. Para obtener más información, consulte Construcciones de agrupamiento.

En el ejemplo siguiente se usan las opciones i , n y x para habilitar las capturas explícitas y la opción que no
hace distinción entre mayúsculas y minúsculas, y para omitir el espacio en blanco del patrón de expresión regular
en medio de una expresión regular.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern;
string input = "double dare double Double a Drooling dog The Dreaded Deep";

pattern = @"\b(D\w+)\s(d\w+)\b";
// Match pattern using default options.
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine(match.Value);
if (match.Groups.Count > 1)
for (int ctr = 1; ctr < match.Groups.Count; ctr++)
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups[ctr].Value);
}
Console.WriteLine();

// Change regular expression pattern to include options.


pattern = @"\b(D\w+)(?ixn) \s (d\w+) \b";
// Match new pattern with options.
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine(match.Value);
if (match.Groups.Count > 1)
for (int ctr = 1; ctr < match.Groups.Count; ctr++)
Console.WriteLine(" Group {0}: '{1}'", ctr, match.Groups[ctr].Value);
}
}
}
// The example displays the following output:
// Drooling dog
// Group 1: Drooling
// Group 2: dog
//
// Drooling dog
// Group 1: 'Drooling'
// Dreaded Deep
// Group 1: 'Dreaded'
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String
Dim input As String = "double dare double Double a Drooling dog The Dreaded Deep"

pattern = "\b(D\w+)\s(d\w+)\b"
' Match pattern using default options.
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
If match.Groups.Count > 1 Then
For ctr As Integer = 1 To match.Groups.Count - 1
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups(ctr).Value)
Next
End If
Next
Console.WriteLine()

' Change regular expression pattern to include options.


pattern = "\b(D\w+)(?ixn) \s (d\w+) \b"
' Match new pattern with options.
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
If match.Groups.Count > 1 Then
For ctr As Integer = 1 To match.Groups.Count - 1
Console.WriteLine(" Group {0}: '{1}'", ctr, match.Groups(ctr).Value)
Next
End If
Next
End Sub
End Module
' The example displays the following output:
' Drooling dog
' Group 1: Drooling
' Group 2: dog
'
' Drooling dog
' Group 1: 'Drooling'
' Dreaded Deep
' Group 1: 'Dreaded'

En el ejemplo se definen dos expresiones regulares. La primera, \b(D\w+)\s(d\w+)\b , coincide con dos palabras
consecutivas que empiezan con una "D" mayúscula y una "d" minúscula. La segunda expresión regular,
\b(D\w+)(?ixn) \s (d\w+) \b , usa opciones insertadas para modificar este patrón, como se describe en la tabla
siguiente. Una comparación de los resultados confirma los efectos de la construcción (?ixn) .

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(D\w+) Coincide con una "D" mayúscula seguida de uno o más


caracteres de palabra. Este es el primer grupo de capturas.

(?ixn) A partir de este punto, hace comparaciones sin distinción


entre mayúsculas y minúsculas, solo hace capturas explícitas y
omite el espacio en blanco del patrón de expresión regular.

\s Coincide con un carácter de espacio en blanco.


MODELO DESCRIPCIÓN

(d\w+) Coincide con una "d" mayúscula o minúscula seguida de uno


o más caracteres de palabra. Este grupo no se captura
porque se ha habilitado la opción n (captura explícita).

\b Coincide con un límite de palabras.

Comentario alineado
La construcción (?# comment ) permite incluir un comentario alineado en una expresión regular. El motor de
expresiones regulares no usa ninguna parte del comentario en la coincidencia de patrones, aunque el comentario
se incluye en la cadena devuelta por el método Regex.ToString. El comentario termina en el primer paréntesis de
cierre.
En el ejemplo siguiente se repite el primer patrón de expresión regular del ejemplo de la sección anterior. Se
agregan dos comentarios alineados en la expresión regular para indicar si la comparación distingue entre
mayúsculas y minúsculas. El patrón de expresión regular,
\b((?# case-sensitive comparison)D\w+)\s(?ixn)((?#case-insensitive comparison)d\w+)\b , se define como se indica
a continuación.

MODELO DESCRIPCIÓN

\b Empieza en un límite de palabras.

(?# case-sensitive comparison) Comentario. No afecta al comportamiento de la coincidencia


de patrones.

(D\w+) Coincide con una "D" mayúscula seguida de uno o más


caracteres de palabra. Este es el primer grupo de captura.

\s Coincide con un carácter de espacio en blanco.

(?ixn) A partir de este punto, hace comparaciones sin distinción


entre mayúsculas y minúsculas, solo hace capturas explícitas y
omite el espacio en blanco del patrón de expresión regular.

(?#case-insensitive comparison) Comentario. No afecta al comportamiento de la coincidencia


de patrones.

(d\w+) Coincide con una "d" mayúscula o minúscula seguida de uno


o más caracteres de palabra. Este es el segundo grupo de
capturas.

\b Coincide con un límite de palabras.


using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b((?# case-sensitive comparison)D\w+)\s(?ixn)((?#case-insensitive
comparison)d\w+)\b";
Regex rgx = new Regex(pattern);
string input = "double dare double Double a Drooling dog The Dreaded Deep";

Console.WriteLine("Pattern: " + pattern.ToString());


// Match pattern using default options.
foreach (Match match in rgx.Matches(input))
{
Console.WriteLine(match.Value);
if (match.Groups.Count > 1)
{
for (int ctr = 1; ctr <match.Groups.Count; ctr++)
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups[ctr].Value);
}
}
}
}
// The example displays the following output:
// Pattern: \b((?# case-sensitive comparison)D\w+)\s(?ixn)((?#case-insensitive comp
// arison)d\w+)\b
// Drooling dog
// Group 1: Drooling
// Dreaded Deep
// Group 1: Dreaded

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b((?# case-sensitive comparison)D\w+)\s(?ixn)((?#case-insensitive
comparison)d\w+)\b"
Dim rgx As New Regex(pattern)
Dim input As String = "double dare double Double a Drooling dog The Dreaded Deep"

Console.WriteLine("Pattern: " + pattern.ToString())


' Match pattern using default options.
For Each match As Match In rgx.Matches(input)
Console.WriteLine(match.Value)
If match.Groups.Count > 1 Then
For ctr As Integer = 1 To match.Groups.Count - 1
Console.WriteLine(" Group {0}: {1}", ctr, match.Groups(ctr).Value)
Next
End If
Next
End Sub
End Module
' The example displays the following output:
' Pattern: \b((?# case-sensitive comparison)D\w+)\s(?ixn)((?#case-insensitive comp
' arison)d\w+)\b
' Drooling dog
' Group 1: Drooling
' Dreaded Deep
' Group 1: Dreaded

Comentario de final de línea


Un signo de número ( # ) marca un comentario en modo X, que empieza en el carácter # sin escape al final del
patrón de expresión regular y continúa hasta el final de la línea. Para usar esta construcción, debe habilitar la
opción x (mediante opciones insertadas) o proporcionar el valor RegexOptions.IgnorePatternWhitespace al
parámetro option al crear una instancia del objeto Regex o al llamar al método Regex estático.
En el ejemplo siguiente se muestra la construcción de comentario de final de línea. Determina si una cadena es
una cadena de formato compuesto que incluye al menos un elemento de formato. En la tabla siguiente se
describe la construcción en el patrón de expresión regular:
\{\d+(,-*\d+)*(\:\w{1,4}?)*\}(?x) # Looks for a composite format item.

MODELO DESCRIPCIÓN

\{ Coincide con una llave de apertura.

\d+ Buscar coincidencias con uno o más dígitos decimales.

(,-*\d+)* Coincide con cero o una aparición de una coma seguida de


un signo menos opcional, seguido de uno o más dígitos
decimales.

(\:\w{1,4}?)* Coincide con cero o una aparición de un signo de dos puntos


seguido de uno a cuatro caracteres de espacio en blanco,
pero el menor número posible.

\} Coincide con una llave de cierre.

(?x) Habilita la opción de ignorar el espacio en blanco del patrón


para que se reconozca el comentario de final de línea.

# Looks for a composite format item. Comentario de final de línea.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\{\d+(,-*\d+)*(\:\w{1,4}?)*\}(?x) # Looks for a composite format item.";
string input = "{0,-3:F}";
Console.WriteLine("'{0}':", input);
if (Regex.IsMatch(input, pattern))
Console.WriteLine(" contains a composite format item.");
else
Console.WriteLine(" does not contain a composite format item.");
}
}
// The example displays the following output:
// '{0,-3:F}':
// contains a composite format item.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\{\d+(,-*\d+)*(\:\w{1,4}?)*\}(?x) # Looks for a composite format item."
Dim input As String = "{0,-3:F}"
Console.WriteLine("'{0}':", input)
If Regex.IsMatch(input, pattern) Then
Console.WriteLine(" contains a composite format item.")
Else
Console.WriteLine(" does not contain a composite format item.")
End If
End Sub
End Module
' The example displays the following output:
' '{0,-3:F}':
' contains a composite format item.

Tenga en cuenta que, en lugar de proporcionar la construcción (?x) en la expresión regular, el comentario
también podía haberse reconocido llamando al método Regex.IsMatch(String, String, RegexOptions) y pasando
el valor de enumeración RegexOptions.IgnorePatternWhitespace.

Vea también
Lenguaje de expresiones regulares: referencia rápida
Procedimientos recomendados con expresiones
regulares en .NET
20/01/2020 • 63 minutes to read • Edit Online

El motor de expresiones regulares de .NET es una herramienta eficaz y completa que procesa texto basándose en
coincidencias de patrones en lugar de comparar y buscar coincidencias con texto literal. En la mayoría de los casos,
realiza la coincidencia de modelos de manera rápida y eficaz. Sin embargo, en algunos casos, puede parecer que el
motor de expresiones regulares es muy lento. En casos extremos, incluso puede parecer que deja de responder
mientras procesa una entrada relativamente pequeña a lo largo de las horas o incluso los días.
En este tema se describen algunos de los procedimientos recomendados que los desarrolladores pueden adoptar
para garantizar que sus expresiones regulares alcancen un rendimiento óptimo.

Considerar el origen de entrada


En general, las expresiones regulares pueden aceptar dos tipos de datos de entrada: restringidos o sin restricciones.
La entrada restringida es texto que se origina en una fuente conocida o confiable y sigue un formato predefinido.
La entrada sin restricciones es texto que se origina en un origen no confiable, como un usuario web, y puede no
seguir un formato predefinido o esperado.
Los patrones de expresiones regulares se suelen escribir para buscar coincidencias con entradas válidas. Es decir,
los desarrolladores examinan el texto que desean buscar y escriben un patrón de expresión regular que coincida
con él. A continuación, los desarrolladores determinan si este patrón necesita alguna corrección o algún
procesamiento adicional probándolo con varios elementos de entrada válidos. Cuando el modelo coincide con
todas las entradas válidas previstas, se declara que está listo para producción y se puede incluir en una aplicación
comercial. Esto hace que un patrón de expresión regular sea adecuado para entradas restringidas coincidentes. Sin
embargo, no es adecuado para datos de entrada sin restricciones coincidentes.
Para buscar coincidencias con datos de entrada sin restricciones, una expresión regular debe poder administrar
eficazmente tres clases de texto:
Texto que coincide con el patrón de expresión regular.
Texto que no coincide con el patrón de expresión regular.
Texto que casi coincide con el patrón de expresión regular.
El último tipo de texto es especialmente problemático para una expresión regular que se ha escrito para tratar
datos de entrada restringidos. Si esa expresión regular también usa mucho retroceso, el motor de expresiones
regulares puede dedicar una cantidad de tiempo excesiva (en algunos casos, muchas horas o días) procesando
texto aparentemente inofensivo.

WARNING
En el ejemplo siguiente se utiliza una expresión regular que es propensa a un retroceso excesivo y que es probable que
rechace direcciones de correo electrónico válidas. No debería utilizarse en una rutina de validación de correo electrónico. Si
desea que una expresión regular valide las direcciones de correo electrónico, vea Procedimiento: Comprobación de que las
cadenas están en un formato de correo electrónico válido.

Por ejemplo, considere una expresión regular de uso muy frecuente pero sumamente problemática para validar el
alias de una dirección de correo electrónico. Se escribe la expresión regular ^[0-9A-Z]([-.\w]*[0-9A-Z])*$ para
procesar qué se considera una dirección de correo electrónico válida, que consta de un carácter alfanumérico
seguido de cero o más caracteres que pueden ser alfanuméricos, puntos o guiones. La expresión regular debe
finalizar con un carácter alfanumérico. Sin embargo, como se muestra en el ejemplo siguiente, aunque esta
expresión regular trata la entrada válida fácilmente, su rendimiento es muy ineficaz cuando está procesando datos
de entrada casi válidos.

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
Stopwatch sw;
string[] addresses = { "AAAAAAAAAAA@contoso.com",
"AAAAAAAAAAaaaaaaaaaa!@contoso.com" };
// The following regular expression should not actually be used to
// validate an email address.
string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])*$";
string input;

foreach (var address in addresses) {


string mailBox = address.Substring(0, address.IndexOf("@"));
int index = 0;
for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--) {
index++;

input = mailBox.Substring(ctr, index);


sw = Stopwatch.StartNew();
Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
sw.Stop();
if (m.Success)
Console.WriteLine("{0,2}. Matched '{1,25}' in {2}",
index, m.Value, sw.Elapsed);
else
Console.WriteLine("{0,2}. Failed '{1,25}' in {2}",
index, input, sw.Elapsed);
}
Console.WriteLine();
}
}
}

// The example displays output similar to the following:


// 1. Matched ' A' in 00:00:00.0007122
// 2. Matched ' AA' in 00:00:00.0000282
// 3. Matched ' AAA' in 00:00:00.0000042
// 4. Matched ' AAAA' in 00:00:00.0000038
// 5. Matched ' AAAAA' in 00:00:00.0000042
// 6. Matched ' AAAAAA' in 00:00:00.0000042
// 7. Matched ' AAAAAAA' in 00:00:00.0000042
// 8. Matched ' AAAAAAAA' in 00:00:00.0000087
// 9. Matched ' AAAAAAAAA' in 00:00:00.0000045
// 10. Matched ' AAAAAAAAAA' in 00:00:00.0000045
// 11. Matched ' AAAAAAAAAAA' in 00:00:00.0000045
//
// 1. Failed ' !' in 00:00:00.0000447
// 2. Failed ' a!' in 00:00:00.0000071
// 3. Failed ' aa!' in 00:00:00.0000071
// 4. Failed ' aaa!' in 00:00:00.0000061
// 5. Failed ' aaaa!' in 00:00:00.0000081
// 6. Failed ' aaaaa!' in 00:00:00.0000126
// 7. Failed ' aaaaaa!' in 00:00:00.0000359
// 8. Failed ' aaaaaaa!' in 00:00:00.0000414
// 9. Failed ' aaaaaaaa!' in 00:00:00.0000758
// 10. Failed ' aaaaaaaaa!' in 00:00:00.0001462
// 10. Failed ' aaaaaaaaa!' in 00:00:00.0001462
// 11. Failed ' aaaaaaaaaa!' in 00:00:00.0002885
// 12. Failed ' Aaaaaaaaaaa!' in 00:00:00.0005780
// 13. Failed ' AAaaaaaaaaaa!' in 00:00:00.0011628
// 14. Failed ' AAAaaaaaaaaaa!' in 00:00:00.0022851
// 15. Failed ' AAAAaaaaaaaaaa!' in 00:00:00.0045864
// 16. Failed ' AAAAAaaaaaaaaaa!' in 00:00:00.0093168
// 17. Failed ' AAAAAAaaaaaaaaaa!' in 00:00:00.0185993
// 18. Failed ' AAAAAAAaaaaaaaaaa!' in 00:00:00.0366723
// 19. Failed ' AAAAAAAAaaaaaaaaaa!' in 00:00:00.1370108
// 20. Failed ' AAAAAAAAAaaaaaaaaaa!' in 00:00:00.1553966
// 21. Failed ' AAAAAAAAAAaaaaaaaaaa!' in 00:00:00.3223372

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim sw As Stopwatch
Dim addresses() As String = { "AAAAAAAAAAA@contoso.com",
"AAAAAAAAAAaaaaaaaaaa!@contoso.com" }
' The following regular expression should not actually be used to
' validate an email address.
Dim pattern As String = "^[0-9A-Z]([-.\w]*[0-9A-Z])*$"
Dim input As String

For Each address In addresses


Dim mailBox As String = address.Substring(0, address.IndexOf("@"))
Dim index As Integer = 0
For ctr As Integer = mailBox.Length - 1 To 0 Step -1
index += 1
input = mailBox.Substring(ctr, index)
sw = Stopwatch.StartNew()
Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
sw.Stop()
if m.Success Then
Console.WriteLine("{0,2}. Matched '{1,25}' in {2}",
index, m.Value, sw.Elapsed)
Else
Console.WriteLine("{0,2}. Failed '{1,25}' in {2}",
index, input, sw.Elapsed)
End If
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays output similar to the following:
' 1. Matched ' A' in 00:00:00.0007122
' 2. Matched ' AA' in 00:00:00.0000282
' 3. Matched ' AAA' in 00:00:00.0000042
' 4. Matched ' AAAA' in 00:00:00.0000038
' 5. Matched ' AAAAA' in 00:00:00.0000042
' 6. Matched ' AAAAAA' in 00:00:00.0000042
' 7. Matched ' AAAAAAA' in 00:00:00.0000042
' 8. Matched ' AAAAAAAA' in 00:00:00.0000087
' 9. Matched ' AAAAAAAAA' in 00:00:00.0000045
' 10. Matched ' AAAAAAAAAA' in 00:00:00.0000045
' 11. Matched ' AAAAAAAAAAA' in 00:00:00.0000045
'
' 1. Failed ' !' in 00:00:00.0000447
' 2. Failed ' a!' in 00:00:00.0000071
' 3. Failed ' aa!' in 00:00:00.0000071
' 4. Failed ' aaa!' in 00:00:00.0000061
' 5. Failed ' aaaa!' in 00:00:00.0000081
' 6. Failed ' aaaaa!' in 00:00:00.0000126
' 7. Failed ' aaaaaa!' in 00:00:00.0000359
' 8. Failed ' aaaaaaa!' in 00:00:00.0000414
' 8. Failed ' aaaaaaa!' in 00:00:00.0000414
' 9. Failed ' aaaaaaaa!' in 00:00:00.0000758
' 10. Failed ' aaaaaaaaa!' in 00:00:00.0001462
' 11. Failed ' aaaaaaaaaa!' in 00:00:00.0002885
' 12. Failed ' Aaaaaaaaaaa!' in 00:00:00.0005780
' 13. Failed ' AAaaaaaaaaaa!' in 00:00:00.0011628
' 14. Failed ' AAAaaaaaaaaaa!' in 00:00:00.0022851
' 15. Failed ' AAAAaaaaaaaaaa!' in 00:00:00.0045864
' 16. Failed ' AAAAAaaaaaaaaaa!' in 00:00:00.0093168
' 17. Failed ' AAAAAAaaaaaaaaaa!' in 00:00:00.0185993
' 18. Failed ' AAAAAAAaaaaaaaaaa!' in 00:00:00.0366723
' 19. Failed ' AAAAAAAAaaaaaaaaaa!' in 00:00:00.1370108
' 20. Failed ' AAAAAAAAAaaaaaaaaaa!' in 00:00:00.1553966
' 21. Failed ' AAAAAAAAAAaaaaaaaaaa!' in 00:00:00.3223372

Como muestra el resultado del ejemplo, el motor de expresiones regulares procesa el alias válido de correo
electrónico casi en el mismo intervalo de tiempo independientemente de su longitud. Por otra parte, cuando la
dirección de correo electrónico casi válida tiene más de cinco caracteres, el tiempo de procesamiento se duplica
aproximadamente por cada carácter de la cadena. Esto significa que una cadena casi válida de 28 caracteres
tardaría más de una hora en procesarse y una cadena casi válida de 33 caracteres tardaría casi un día en
procesarse.
Como esta expresión regular se desarrolló teniendo en cuenta solamente el formato de entrada que había que
hacer coincidir, no tiene en cuenta los datos de entrada que no coinciden con el patrón. A su vez, esto puede
permitir que unos datos de entrada sin restricciones que casi coinciden con el patrón de expresión regular reduzcan
considerablemente el rendimiento.
Para resolver este problema, puede hacer lo siguiente:
A la hora de desarrollar un modelo, debe considerar cómo puede afectar el retroceso al rendimiento del
motor de expresiones regulares, especialmente si la expresión regular está diseñada para procesar datos de
entrada sin restricciones. Para obtener más información, consulte la sección Controlar el retroceso.
Probar exhaustivamente la expresión regular usando datos de entrada no válidos y casi válidos, así como
datos de entrada válidos. Para generar de forma aleatoria la entrada para una expresión regular
determinada, puede usar Rex, que es una herramienta de exploración de expresiones regulares de Microsoft
Research.

Controlar la creación de instancias de objeto correctamente


El núcleo del modelo de objetos de expresiones regulares de .NET es la clase
System.Text.RegularExpressions.Regex, que representa el motor de expresiones regulares. A menudo, el mayor
factor único que afecta al rendimiento de las expresiones regulares es la manera en que se emplea el motor de
Regex. La definición de una expresión regular implica acoplar estrechamente el motor de expresiones regulares con
un patrón de expresión regular. Ese proceso de acoplamiento, tanto si consiste en crear una instancia de un objeto
Regex pasando a su constructor una expresión regular como en llamar a un método estático pasándole el patrón
de expresión regular junto con la cadena que se va a analizar, es necesariamente costoso.

NOTE
Para obtener una explicación más detallada de las implicaciones sobre el rendimiento de usar expresiones regulares
interpretadas y compiladas, vea Optimizing Regular Expression Performance, Part II: (Optimización del rendimiento de
expresiones regulares, Parte II: Control del retroceso) en el blog del equipo de BCL.

Puede acoplar el motor de expresiones regulares con un determinado patrón de expresión regular y, a
continuación, usar el motor para buscar coincidencias con texto de varias maneras:
Puede llamar a un método estático de coincidencia de patrones como Regex.Match(String, String). Para ello
no es necesario crear instancias de un objeto de expresión regular.
Puede crear instancias de un objeto Regex y llamar a una instancia de un método de coincidencia de
modelos de una expresión regular interpretada. Este es el método predeterminado para enlazar el motor de
expresiones regulares a un patrón de expresión regular. Se produce cuando se crea una instancia de un
objeto Regex sin un argumento options que incluya la marca Compiled.
Puede crear instancias de un objeto Regex y llamar a una instancia de un método de coincidencia de
modelos de una expresión regular compilada. Los objetos de expresiones regulares representan modelos
compilados cuando se crea una instancia de un objeto Regex con un argumento options que incluye la
marca Compiled.
Puede crear un objeto Regex especial que esté acoplado estrechamente con un determinado patrón de
expresión regular, compilarlo y guardarlo en un ensamblado independiente. Puede hacerlo llamando al
método Regex.CompileToAssembly.
La forma de llamar a los métodos de coincidencia de expresiones regulares puede tener un impacto significativo en
la aplicación. En las próximas secciones se explica cómo usar llamadas a métodos estáticos, expresiones regulares
interpretadas y expresiones regulares compiladas para mejorar el rendimiento de la aplicación.

IMPORTANT
El formato de la llamada al método (estático, interpretado o compilado) afecta al rendimiento si la misma expresión regular se
usa repetidamente en llamadas a métodos o si una aplicación usa muchos objetos de expresiones regulares.

Expresiones regulares estáticas


Se recomienda el uso de métodos de expresiones regulares estáticas como alternativa a crear repetidamente
instancias de un objeto de expresión regular con la misma expresión regular. A diferencia de los patrones de
expresiones regulares usados por los objetos de expresiones regulares, el motor de expresiones regulares
almacena internamente en memoria caché los códigos de operación o el lenguaje intermedio de Microsoft (MSIL )
compilado de los patrones empleados en las llamadas al método estático.
Por ejemplo, un controlador de eventos llama con frecuencia a otro método para validar los datos proporcionados
por el usuario. Esto se refleja en el código siguiente, en el que se usa el evento Button de un control Click para
llamar a un método denominado IsValidCurrency , que comprueba si el usuario ha escrito un símbolo de moneda
seguido al menos de un dígito decimal.

public void OKButton_Click(object sender, EventArgs e)


{
if (! String.IsNullOrEmpty(sourceCurrency.Text))
if (RegexLib.IsValidCurrency(sourceCurrency.Text))
PerformConversion();
else
status.Text = "The source currency value is invalid.";
}
Public Sub OKButton_Click(sender As Object, e As EventArgs) _
Handles OKButton.Click

If Not String.IsNullOrEmpty(sourceCurrency.Text) Then


If RegexLib.IsValidCurrency(sourceCurrency.Text) Then
PerformConversion()
Else
status.Text = "The source currency value is invalid."
End If
End If
End Sub

En el ejemplo siguiente se muestra una implementación muy poco eficaz del método IsValidCurrency . Observe
que cada llamada al método vuelve a crear una instancia de un objeto Regex con el mismo modelo. Esto, a su vez,
significa que el patrón de expresión regular se debe volver a compilar cada vez que se llama al método.

using System;
using System.Text.RegularExpressions;

public class RegexLib


{
public static bool IsValidCurrency(string currencyValue)
{
string pattern = @"\p{Sc}+\s*\d+";
Regex currencyRegex = new Regex(pattern);
return currencyRegex.IsMatch(currencyValue);
}
}

Imports System.Text.RegularExpressions

Public Module RegexLib


Public Function IsValidCurrency(currencyValue As String) As Boolean
Dim pattern As String = "\p{Sc}+\s*\d+"
Dim currencyRegex As New Regex(pattern)
Return currencyRegex.IsMatch(currencyValue)
End Function
End Module

Debe reemplazar este código ineficaz con una llamada al método estático Regex.IsMatch(String, String). Esto
elimina la necesidad de crear instancias de un objeto Regex cada vez que desea llamar a un método de coincidencia
de modelos y permite que el motor de expresiones regulares recupere una versión compilada de la expresión
regular de su memoria caché.

using System;
using System.Text.RegularExpressions;

public class RegexLib


{
public static bool IsValidCurrency(string currencyValue)
{
string pattern = @"\p{Sc}+\s*\d+";
return Regex.IsMatch(currencyValue, pattern);
}
}
Imports System.Text.RegularExpressions

Public Module RegexLib


Public Function IsValidCurrency(currencyValue As String) As Boolean
Dim pattern As String = "\p{Sc}+\s*\d+"
Return Regex.IsMatch(currencyValue, pattern)
End Function
End Module

De forma predeterminada, se almacenan en caché los 15 últimos patrones de expresiones regulares estáticas
usados recientemente. En el caso de las aplicaciones que necesitan un mayor número de expresiones regulares
estáticas almacenadas en caché, el tamaño de la memoria caché se puede ajustar estableciendo la propiedad
Regex.CacheSize.
La expresión regular \p{Sc}+\s*\d+ que se usa en este ejemplo comprueba que la cadena de entrada consta de un
símbolo de moneda y al menos un dígito decimal. El patrón se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\p{Sc}+ Buscar coincidencias con uno o más caracteres de la categoría


Símbolo Unicode, Moneda.

\s* Busca coincidencias con cero o más caracteres de espacio en


blanco.

\d+ Buscar coincidencias con uno o más dígitos decimales.

Expresiones regulares interpretadas y compiladas


Los patrones de expresiones regulares que no están enlazados al motor de expresiones regulares mediante la
especificación de la opción Compiled se interpretan. Cuando se crea una instancia de un objeto de expresión
regular, el motor de expresiones regulares convierte la expresión regular en un conjunto de códigos de operación.
Cuando se llama a un método de instancia, el compilador JIT ejecuta y convierte a MSIL los códigos de operación.
Del mismo modo, cuando se llama a un método estático de expresión regular y la expresión regular no se
encuentra en la memoria caché, el motor de expresiones regulares convierte la expresión regular en un conjunto de
códigos de operación y los almacena en memoria caché. A continuación, convierte estos códigos de operación a
MSIL para que el compilador JIT pueda ejecutarlos. Las expresiones regulares interpretadas reducen el tiempo de
inicio a costa de un tiempo de ejecución más lento. Por eso, son más adecuadas cuando la expresión regular se usa
en un número reducido de llamadas a métodos o si el número exacto de llamadas a métodos de expresión regular
es desconocido pero se espera que sea pequeño. A medida que aumenta el número de llamadas al método, la
mejora de rendimiento del tiempo de inicio reducido queda oscurecida por una velocidad de ejecución más lenta.
Los patrones de expresiones regulares que están enlazados al motor de expresiones regulares mediante la
especificación de la opción Compiled se compilan. Esto significa que, cuando se crea una instancia de un objeto de
expresión regular, o cuando se llama a un método estático de expresión regular y la expresión regular no se
encuentra en la memoria caché, el motor de expresiones regulares convierte la expresión regular a un conjunto
intermedio de códigos de operación que, a continuación, convierte a MSIL. Cuando se llama a un método, el
compilador JIT ejecuta el código MSIL. A diferencia de las expresiones regulares interpretadas, las expresiones
regulares compiladas aumentan el tiempo de inicio pero ejecutan más deprisa los métodos individuales de
coincidencia de patrones. Por tanto, la ventaja de rendimiento resultante de compilar la expresión regular aumenta
en proporción al número de métodos de expresiones regulares llamados.
En resumen, se recomienda usar expresiones regulares interpretadas al llamar a métodos de expresión regular con
una expresión regular concreta con poca frecuencia relativamente. Debe usar expresiones regulares compiladas al
llamar a métodos de expresión regular con una expresión regular concreta con relativa frecuencia. Es difícil
determinar el umbral exacto en el que las velocidades de ejecución más lentas de las expresiones regulares
interpretadas superan las mejoras de su menor tiempo de inicio, o el umbral en el que los tiempos de inicio más
lentos de las expresiones regulares compiladas superan las mejoras de sus velocidades de ejecución más rápidas.
Depende de diversos factores, como la complejidad de la expresión regular y los datos específicos que procesa.
Para determinar si las expresiones regulares interpretadas o compiladas ofrecen el mejor rendimiento para su
escenario de aplicación concreto, puede usar la clase Stopwatch para comparar sus tiempos de ejecución.
En el ejemplo siguiente, se compara el rendimiento de las expresiones regulares compiladas e interpretadas al leer
las diez primeras frases y al leer todas las frases del texto The Financier de Theodore Dreiser. Como muestra el
resultado del ejemplo, cuando solo se realizan diez llamadas a métodos de coincidencia de expresión regular, una
expresión regular interpreta proporciona un rendimiento mejor que una expresión regular compilada. Sin
embargo, una expresión regular compilada ofrece mejor rendimiento cuando se realiza un gran número de
llamadas (en este caso, más de 13000).

using System;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\w+((\r?\n)|,?\s))*\w+[.?:;!]";
Stopwatch sw;
Match match;
int ctr;

StreamReader inFile = new StreamReader(@".\Dreiser_TheFinancier.txt");


string input = inFile.ReadToEnd();
inFile.Close();

// Read first ten sentences with interpreted regex.


Console.WriteLine("10 Sentences with Interpreted Regex:");
sw = Stopwatch.StartNew();
Regex int10 = new Regex(pattern, RegexOptions.Singleline);
match = int10.Match(input);
for (ctr = 0; ctr <= 9; ctr++) {
if (match.Success)
// Do nothing with the match except get the next match.
match = match.NextMatch();
else
break;
}
sw.Stop();
Console.WriteLine(" {0} matches in {1}", ctr, sw.Elapsed);

// Read first ten sentences with compiled regex.


Console.WriteLine("10 Sentences with Compiled Regex:");
sw = Stopwatch.StartNew();
Regex comp10 = new Regex(pattern,
RegexOptions.Singleline | RegexOptions.Compiled);
match = comp10.Match(input);
for (ctr = 0; ctr <= 9; ctr++) {
if (match.Success)
// Do nothing with the match except get the next match.
match = match.NextMatch();
else
break;
}
sw.Stop();
Console.WriteLine(" {0} matches in {1}", ctr, sw.Elapsed);

// Read all sentences with interpreted regex.


Console.WriteLine("All Sentences with Interpreted Regex:");
Console.WriteLine("All Sentences with Interpreted Regex:");
sw = Stopwatch.StartNew();
Regex intAll = new Regex(pattern, RegexOptions.Singleline);
match = intAll.Match(input);
int matches = 0;
while (match.Success) {
matches++;
// Do nothing with the match except get the next match.
match = match.NextMatch();
}
sw.Stop();
Console.WriteLine(" {0:N0} matches in {1}", matches, sw.Elapsed);

// Read all sentences with compiled regex.


Console.WriteLine("All Sentences with Compiled Regex:");
sw = Stopwatch.StartNew();
Regex compAll = new Regex(pattern,
RegexOptions.Singleline | RegexOptions.Compiled);
match = compAll.Match(input);
matches = 0;
while (match.Success) {
matches++;
// Do nothing with the match except get the next match.
match = match.NextMatch();
}
sw.Stop();
Console.WriteLine(" {0:N0} matches in {1}", matches, sw.Elapsed);
}
}
// The example displays the following output:
// 10 Sentences with Interpreted Regex:
// 10 matches in 00:00:00.0047491
// 10 Sentences with Compiled Regex:
// 10 matches in 00:00:00.0141872
// All Sentences with Interpreted Regex:
// 13,443 matches in 00:00:01.1929928
// All Sentences with Compiled Regex:
// 13,443 matches in 00:00:00.7635869
//
// >compare1
// 10 Sentences with Interpreted Regex:
// 10 matches in 00:00:00.0046914
// 10 Sentences with Compiled Regex:
// 10 matches in 00:00:00.0143727
// All Sentences with Interpreted Regex:
// 13,443 matches in 00:00:01.1514100
// All Sentences with Compiled Regex:
// 13,443 matches in 00:00:00.7432921

Imports System.Diagnostics
Imports System.IO
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\w+((\r?\n)|,?\s))*\w+[.?:;!]"
Dim sw As Stopwatch
Dim match As Match
Dim ctr As Integer

Dim inFile As New StreamReader(".\Dreiser_TheFinancier.txt")


Dim input As String = inFile.ReadToEnd()
inFile.Close()

' Read first ten sentences with interpreted regex.


Console.WriteLine("10 Sentences with Interpreted Regex:")
sw = Stopwatch.StartNew()
Dim int10 As New Regex(pattern, RegexOptions.SingleLine)
Dim int10 As New Regex(pattern, RegexOptions.SingleLine)
match = int10.Match(input)
For ctr = 0 To 9
If match.Success Then
' Do nothing with the match except get the next match.
match = match.NextMatch()
Else
Exit For
End If
Next
sw.Stop()
Console.WriteLine(" {0} matches in {1}", ctr, sw.Elapsed)

' Read first ten sentences with compiled regex.


Console.WriteLine("10 Sentences with Compiled Regex:")
sw = Stopwatch.StartNew()
Dim comp10 As New Regex(pattern,
RegexOptions.SingleLine Or RegexOptions.Compiled)
match = comp10.Match(input)
For ctr = 0 To 9
If match.Success Then
' Do nothing with the match except get the next match.
match = match.NextMatch()
Else
Exit For
End If
Next
sw.Stop()
Console.WriteLine(" {0} matches in {1}", ctr, sw.Elapsed)

' Read all sentences with interpreted regex.


Console.WriteLine("All Sentences with Interpreted Regex:")
sw = Stopwatch.StartNew()
Dim intAll As New Regex(pattern, RegexOptions.SingleLine)
match = intAll.Match(input)
Dim matches As Integer = 0
Do While match.Success
matches += 1
' Do nothing with the match except get the next match.
match = match.NextMatch()
Loop
sw.Stop()
Console.WriteLine(" {0:N0} matches in {1}", matches, sw.Elapsed)

' Read all sentences with compiled regex.


Console.WriteLine("All Sentences with Compiled Regex:")
sw = Stopwatch.StartNew()
Dim compAll As New Regex(pattern,
RegexOptions.SingleLine Or RegexOptions.Compiled)
match = compAll.Match(input)
matches = 0
Do While match.Success
matches += 1
' Do nothing with the match except get the next match.
match = match.NextMatch()
Loop
sw.Stop()
Console.WriteLine(" {0:N0} matches in {1}", matches, sw.Elapsed)
End Sub
End Module
' The example displays output like the following:
' 10 Sentences with Interpreted Regex:
' 10 matches in 00:00:00.0047491
' 10 Sentences with Compiled Regex:
' 10 matches in 00:00:00.0141872
' All Sentences with Interpreted Regex:
' 13,443 matches in 00:00:01.1929928
' All Sentences with Compiled Regex:
' 13,443 matches in 00:00:00.7635869
'
'
' >compare1
' 10 Sentences with Interpreted Regex:
' 10 matches in 00:00:00.0046914
' 10 Sentences with Compiled Regex:
' 10 matches in 00:00:00.0143727
' All Sentences with Interpreted Regex:
' 13,443 matches in 00:00:01.1514100
' All Sentences with Compiled Regex:
' 13,443 matches in 00:00:00.7432921

El patrón de expresión regular usado en el ejemplo, \b(\w+((\r?\n)|,?\s))*\w+[.?:;!] , se define como se muestra


en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

(\r?\n)|,?\s) Buscar una coincidencia con cero o un retorno de carro


seguido de un carácter de nueva línea, o cero o una coma
seguida de un carácter de espacio en blanco.

(\w+((\r?\n)|,?\s))* Buscar coincidencias con cero o más apariciones de uno o más


caracteres alfabéticos que van seguidos de cero o un retorno
de carro y un carácter de nueva línea, o de cero o una coma
seguida de un carácter de espacio en blanco.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

[.?:;!] Buscar una coincidencia con un punto, un signo de


interrogación, dos puntos, punto y coma o un signo de
exclamación.

Expresiones regulares: compiladas en un ensamblado


.NET también permite crear un ensamblado que contenga expresiones regulares compiladas. Esto lleva la merma
de rendimiento de la compilación de la expresión regular del tiempo de ejecución al tiempo de diseño. Aunque
también implica cierto trabajo adicional: Hay que definir las expresiones regulares de antemano y compilarlas en
un ensamblado. El compilador puede hacer referencia a este ensamblado al compilar código fuente que usa
expresiones regulares del ensamblado. Cada expresión regular compilada del ensamblado está representada por
una clase que se deriva de Regex.
Para compilar expresiones regulares en un ensamblado, se llama al método
Regex.CompileToAssembly(RegexCompilationInfo[], AssemblyName) y se le pasa una matriz de objetos
RegexCompilationInfo que representan las expresiones regulares que se van a compilar y un objeto
AssemblyName que contiene información sobre el ensamblado que se va a crear.
Se recomienda compilar expresiones regulares en un ensamblado en las situaciones siguientes:
Si es un desarrollador de componentes que desea crear una biblioteca de expresiones regulares
reutilizables.
Si espera que los métodos de coincidencia de modelos de la expresión regular se llamen un número
indeterminado de veces, desde una o dos veces hasta miles o decenas de miles de veces. A diferencia de las
expresiones regulares compiladas o interpretadas, las expresiones regulares que se compilan en
ensamblados independientes proporcionan un rendimiento coherente independientemente del número de
llamadas a métodos.
Si emplea expresiones regulares compiladas para optimizar el rendimiento, no debe usar la reflexión para crear el
ensamblado, cargar el motor de expresiones regulares y ejecutar sus métodos de coincidencia con modelos. Para
ello es necesario evitar la creación dinámica de expresiones regulares y especificar cualquier opción de coincidencia
de modelos (como la coincidencia de modelos sin distinción entre mayúsculas y minúsculas) en el momento en
que se crea el ensamblado. También debe separar el código que crea el ensamblado del código que usa la
expresión regular.
En el ejemplo siguiente se muestra cómo crear un ensamblado que contiene una expresión regular compilada.
Crea un ensamblado denominado RegexLib.dll con una única clase de expresión regular, SentencePattern , que
contiene el patrón de expresión regular de coincidencia con frases usado en la sección Expresiones regulares
interpretadas frente a expresiones regulares compiladas.

using System;
using System.Reflection;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
RegexCompilationInfo SentencePattern =
new RegexCompilationInfo(@"\b(\w+((\r?\n)|,?\s))*\w+[.?:;!]",
RegexOptions.Multiline,
"SentencePattern",
"Utilities.RegularExpressions",
true);
RegexCompilationInfo[] regexes = { SentencePattern };
AssemblyName assemName = new AssemblyName("RegexLib, Version=1.0.0.1001, Culture=neutral,
PublicKeyToken=null");
Regex.CompileToAssembly(regexes, assemName);
}
}

Imports System.Reflection
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim SentencePattern As New RegexCompilationInfo("\b(\w+((\r?\n)|,?\s))*\w+[.?:;!]",
RegexOptions.Multiline,
"SentencePattern",
"Utilities.RegularExpressions",
True)
Dim regexes() As RegexCompilationInfo = {SentencePattern}
Dim assemName As New AssemblyName("RegexLib, Version=1.0.0.1001, Culture=neutral, PublicKeyToken=null")
Regex.CompileToAssembly(regexes, assemName)
End Sub
End Module

Cuando el ejemplo se compila en un ejecutable y se ejecuta, crea un ensamblado denominado RegexLib.dll . La


expresión regular se representa mediante una clase denominada Utilities.RegularExpressions.SentencePattern
que se deriva de Regex. En el ejemplo siguiente, se usa después la expresión regular compilada para extraer las
frases del texto The Financier de Theodore Dreiser.
using System;
using System.IO;
using System.Text.RegularExpressions;
using Utilities.RegularExpressions;

public class Example


{
public static void Main()
{
SentencePattern pattern = new SentencePattern();
StreamReader inFile = new StreamReader(@".\Dreiser_TheFinancier.txt");
string input = inFile.ReadToEnd();
inFile.Close();

MatchCollection matches = pattern.Matches(input);


Console.WriteLine("Found {0:N0} sentences.", matches.Count);
}
}
// The example displays the following output:
// Found 13,443 sentences.

Imports System.IO
Imports System.Text.RegularExpressions
Imports Utilities.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As New SentencePattern()
Dim inFile As New StreamReader(".\Dreiser_TheFinancier.txt")
Dim input As String = inFile.ReadToEnd()
inFile.Close()

Dim matches As MatchCollection = pattern.Matches(input)


Console.WriteLine("Found {0:N0} sentences.", matches.Count)
End Sub
End Module
' The example displays the following output:
' Found 13,443 sentences.

Controlar el retroceso
Normalmente, el motor de expresiones regulares usa la progresión lineal para desplazarse a través de una cadena
de entrada y compararla con un patrón de expresión regular. Sin embargo, cuando en un patrón de expresión
regular se usan cuantificadores indeterminados como * , + y ? , el motor de expresiones regulares puede
abandonar una parte de las coincidencias parciales correctas y volver a un estado guardado previamente para
buscar una coincidencia correcta de todo el patron. Este proceso se denomina retroceso.

NOTE
Para obtener más información acerca del retroceso, consulte Detalles del comportamiento de expresiones regulares y
Retroceso. Para obtener una explicación detallada del retroceso, vea Optimizing Regular Expression Performance, Part II:
(Optimización del rendimiento de expresiones regulares, Parte II: Control del retroceso) en el blog del equipo de BCL.

La compatibilidad con el retroceso aporta a las expresiones regulares eficacia y flexibilidad. También deja la
responsabilidad de controlar el funcionamiento del motor de expresiones regulares en manos de los
desarrolladores de expresiones regulares. Puesto que los desarrolladores no suelen ser conscientes de esta
responsabilidad, su uso incorrecto del retroceso o su dependencia de un retroceso excesivo suele desempeñar el
rol más significativo en la degradación del rendimiento de las expresiones regulares. En un escenario de caso peor,
el tiempo de ejecución puede duplicarse por cada carácter adicional de la cadena de entrada. De hecho, usando
excesivamente el retroceso, es fácil crear el equivalente en programación de un bucle infinito si la entrada coincide
casi con el patrón de expresiones regulares; el motor de expresiones regulares puede tardar horas o incluso días en
procesar una cadena de entrada relativamente corta.
A menudo, las aplicaciones sufren una reducción del rendimiento por usar el retroceso a pesar de que el retroceso
no es esencial para una coincidencia. Por ejemplo, la expresión regular \b\p{Lu}\w*\b busca una coincidencia con
todas las palabras que comienzan por un carácter en mayúsculas, como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\p{Lu} Busca una coincidencia con un carácter en mayúsculas.

\w* Buscar una coincidencia con cero o más caracteres alfabéticos.

\b Finalizar la búsqueda de coincidencias en un límite de palabras.

Puesto que un límite de palabra no es igual, o un subconjunto de, que un carácter alfabético, no hay ninguna
posibilidad de que el motor de expresiones regulares cruce un límite de palabra cuando busca coincidencias con
caracteres alfabéticos. Esto significa que para esta expresión regular, el retroceso nunca puede contribuir al éxito
global de cualquier coincidencia; solo puede degradar el rendimiento, ya que se fuerza que el motor de expresiones
regulares guarde su estado para cada coincidencia preliminar correcta de un carácter alfabético.
Si determina que el retroceso no es necesario, puede deshabilitarlo mediante el elemento de lenguaje
(?>subexpression) . En el ejemplo siguiente se analiza una cadena de entrada usando dos expresiones regulares. La
primera, \b\p{Lu}\w*\b , se basa en el retroceso. La segunda, \b\p{Lu}(?>\w*)\b , deshabilita el retroceso. Como
muestra el resultado del ejemplo, ambas producen el mismo resultado.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This this word Sentence name Capital";
string pattern = @"\b\p{Lu}\w*\b";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);

Console.WriteLine();

pattern = @"\b\p{Lu}(?>\w*)\b";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// This
// Sentence
// Capital
//
// This
// Sentence
// Capital
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This this word Sentence name Capital"
Dim pattern As String = "\b\p{Lu}\w*\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
Console.WriteLine()

pattern = "\b\p{Lu}(?>\w*)\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' This
' Sentence
' Capital
'
' This
' Sentence
' Capital

En muchos casos, el retroceso es esencial para buscar una coincidencia de un patrón de expresión regular con el
texto de entrada. Sin embargo, el retroceso excesivo puede degradar gravemente el rendimiento y dar la impresión
de que una aplicación ha dejado de responder. En concreto, esto ocurre cuando se anidan los cuantificadores y el
texto que coincide con la subexpresión externa es un subconjunto del texto que coincide con la subexpresión
interna.

WARNING
Además de evitar el retroceso excesivo, se debe utilizar la característica de tiempo de espera para garantizar que el retroceso
excesivo no reduzca gravemente el rendimiento de la expresión regular. Para obtener más información, consulte la sección
Usar valores de tiempo de espera.

Por ejemplo, el patrón de expresión regular ^[0-9A-Z]([-.\w]*[0-9A-Z])*\$$ está diseñado para buscar
coincidencias con un número de pieza que contiene al menos un carácter alfanumérico. Cualquier carácter
adicional puede constar de un carácter alfanumérico, un guión, un carácter de subrayado o un punto, aunque el
último carácter debe ser alfanumérico. El número de pieza termina con un signo de dólar. En algunos casos, este
patrón de expresión regular puede presentar un rendimiento muy deficiente porque los cuantificadores están
anidados y porque la subexpresión [0-9A-Z] es un subconjunto de la subexpresión [-.\w]* .
En estos casos, puede optimizar el rendimiento de la expresión regular quitando los cuantificadores anidados y
reemplazando la subexpresión externa con una aserción de búsqueda anticipada o de búsqueda tardía de ancho
cero. Las aserciones de búsqueda anticipada y de búsqueda tardía son delimitadores; no mueven el puntero en la
cadena de entrada, sino que realizan una búsqueda hacia delante o hacia atrás para comprobar si se cumple una
condición especificada. Por ejemplo, la expresión regular de número de pieza se puede volver a escribir como
^[0-9A-Z][-.\w]*(?<=[0-9A-Z])\$$ . Este patrón de expresión regular se define como se muestra en la tabla
siguiente.

MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias con el principio de la


cadena de entrada.
MODELO DESCRIPCIÓN

[0-9A-Z] Buscar coincidencias de un carácter alfanumérico. El número


de pieza debe constar al menos de este carácter.

[-.\w]* Buscar coincidencias con cero o más apariciones de cualquier


carácter alfabético, guión o punto.

\$ Buscar coincidencias con un signo de dólar.

(?<=[0-9A-Z]) Realizar una búsqueda anticipada del signo de dólar final para
asegurarse de que el carácter anterior es alfanumérico.

$ Finalizar la búsqueda de coincidencias al final de la cadena de


entrada.

En el ejemplo siguiente se muestra el uso de esta expresión regular para encontrar una matriz que contiene los
números de pieza posibles.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"^[0-9A-Z][-.\w]*(?<=[0-9A-Z])\$$";
string[] partNos = { "A1C$", "A4", "A4$", "A1603D$", "A1603D#" };

foreach (var input in partNos) {


Match match = Regex.Match(input, pattern);
if (match.Success)
Console.WriteLine(match.Value);
else
Console.WriteLine("Match not found.");
}
}
}
// The example displays the following output:
// A1C$
// Match not found.
// A4$
// A1603D$
// Match not found.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^[0-9A-Z][-.\w]*(?<=[0-9A-Z])\$$"
Dim partNos() As String = { "A1C$", "A4", "A4$", "A1603D$",
"A1603D#" }

For Each input As String In partNos


Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine(match.Value)
Else
Console.WriteLine("Match not found.")
End If
Next
End Sub
End Module
' The example displays the following output:
' A1C$
' Match not found.
' A4$
' A1603D$
' Match not found.

El lenguaje de expresiones regulares de .NET incluye los elementos del lenguaje siguientes, que puede usar para
eliminar cuantificadores anidados. Para obtener más información, consulte Construcciones de agrupamiento.

ELEMENTO DEL LENGUAJE DESCRIPCIÓN

(?= subexpression ) Búsqueda anticipada positiva de ancho cero. Realizar una


búsqueda anticipada de la posición actual para determinar si
subexpression coincide con la cadena de entrada.

(?! subexpression ) Búsqueda anticipada negativa de ancho cero. Realizar una


búsqueda anticipada de la posición actual para determinar si
subexpression no coincide con la cadena de entrada.

(?<= subexpression ) Búsqueda tardía positiva de ancho cero. Realizar una


búsqueda tardía de la posición actual para determinar si
subexpression coincide con la cadena de entrada.

(?<! subexpression ) Búsqueda tardía negativa de ancho cero. Realizar una


búsqueda tardía de la posición actual para determinar si
subexpression no coincide con la cadena de entrada.

Usar valores de tiempo de espera


Si sus expresiones regulares procesan datos de entrada que prácticamente coinciden con el patrón de expresiones
regulares, normalmente se puede usar el retroceso excesivo, que afecta enormemente al rendimiento. Además de
analizar cuidadosamente el uso del retroceso y probar la expresión regular en entradas casi coincidentes, debe
establecer siempre un valor de tiempo de espera para garantizar que el impacto del retroceso excesivo, si aparece,
se reduzca al mínimo.
El intervalo de tiempo de espera de la expresión regular define el período de tiempo que el motor de expresiones
regulares buscará una coincidencia única antes de que el tiempo se agote. El intervalo de tiempo de espera
predeterminado es Regex.InfiniteMatchTimeout, que significa que no se agotará el tiempo de la expresión regular.
Puede invalidar este valor y definir un intervalo de tiempo de espera de la siguiente manera:
Proporcionando un valor de tiempo de espera al crear una instancia del objeto Regex llamando al
constructor Regex.Regex(String, RegexOptions, TimeSpan).
Llamando a un método estático de coincidencia de patrones, como Regex.Match(String, String,
RegexOptions, TimeSpan) o Regex.Replace(String, String, String, RegexOptions, TimeSpan), que incluya un
parámetro matchTimeout .
Para las expresiones regulares compiladas que se crean mediante una llamada al método
Regex.CompileToAssembly, llamando al constructor que tiene un parámetro de tipo TimeSpan.
Si ha definido un intervalo de tiempo de espera y no se encuentra ninguna coincidencia al final del intervalo, el
método de expresiones regulares produce una excepción RegexMatchTimeoutException. En el controlador de
excepciones, puede elegir reintentar la búsqueda de coincidencias con un intervalo de tiempo de espera más largo,
abandonar el intento de búsqueda de coincidencias y asumir que no hay ninguna coincidencia o abandonar el
intento de búsqueda de coincidencias y registrar la información de excepción para futuros análisis.
En el ejemplo siguiente se define un método GetWordData que crea una instancia de una expresión regular con un
tiempo de espera de 350 milisegundos para calcular el número de palabras y el promedio de caracteres de una
palabra en un documento de texto. Si se agota el tiempo de espera de la operación de coincidencia, el intervalo de
tiempo de espera aumenta en 350 milisegundos y se vuelve a crear una instancia del objeto Regex. Si el nuevo
intervalo de tiempo de espera es mayor de 1 segundo, el método vuelve a producir la excepción y se la envía al
llamador.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
RegexUtilities util = new RegexUtilities();
string title = "Doyle - The Hound of the Baskervilles.txt";
try {
var info = util.GetWordData(title);
Console.WriteLine("Words: {0:N0}", info.Item1);
Console.WriteLine("Average Word Length: {0:N2} characters", info.Item2);
}
catch (IOException e) {
Console.WriteLine("IOException reading file '{0}'", title);
Console.WriteLine(e.Message);
}
catch (RegexMatchTimeoutException e) {
Console.WriteLine("The operation timed out after {0:N0} milliseconds",
e.MatchTimeout.TotalMilliseconds);
}
}
}

public class RegexUtilities


{
public Tuple<int, double> GetWordData(string filename)
{
const int MAX_TIMEOUT = 1000; // Maximum timeout interval in milliseconds.
const int INCREMENT = 350; // Milliseconds increment of timeout.

List<string> exclusions = new List<string>( new string[] { "a", "an", "the" });
int[] wordLengths = new int[29]; // Allocate an array of more than ample size.
string input = null;
StreamReader sr = null;
try {
sr = new StreamReader(filename);
input = sr.ReadToEnd();
input = sr.ReadToEnd();
}
catch (FileNotFoundException e) {
string msg = String.Format("Unable to find the file '{0}'", filename);
throw new IOException(msg, e);
}
catch (IOException e) {
throw new IOException(e.Message, e);
}
finally {
if (sr != null) sr.Close();
}

int timeoutInterval = INCREMENT;


bool init = false;
Regex rgx = null;
Match m = null;
int indexPos = 0;
do {
try {
if (! init) {
rgx = new Regex(@"\b\w+\b", RegexOptions.None,
TimeSpan.FromMilliseconds(timeoutInterval));
m = rgx.Match(input, indexPos);
init = true;
}
else {
m = m.NextMatch();
}
if (m.Success) {
if ( !exclusions.Contains(m.Value.ToLower()))
wordLengths[m.Value.Length]++;

indexPos += m.Length + 1;
}
}
catch (RegexMatchTimeoutException e) {
if (e.MatchTimeout.TotalMilliseconds < MAX_TIMEOUT) {
timeoutInterval += INCREMENT;
init = false;
}
else {
// Rethrow the exception.
throw;
}
}
} while (m.Success);

// If regex completed successfully, calculate number of words and average length.


int nWords = 0;
long totalLength = 0;

for (int ctr = wordLengths.GetLowerBound(0); ctr <= wordLengths.GetUpperBound(0); ctr++) {


nWords += wordLengths[ctr];
totalLength += ctr * wordLengths[ctr];
}
return new Tuple<int, double>(nWords, totalLength/nWords);
}
}

Imports System.Collections.Generic
Imports System.IO
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim util As New RegexUtilities()
Dim title As String = "Doyle - The Hound of the Baskervilles.txt"
Dim title As String = "Doyle - The Hound of the Baskervilles.txt"
Try
Dim info = util.GetWordData(title)
Console.WriteLine("Words: {0:N0}", info.Item1)
Console.WriteLine("Average Word Length: {0:N2} characters", info.Item2)
Catch e As IOException
Console.WriteLine("IOException reading file '{0}'", title)
Console.WriteLine(e.Message)
Catch e As RegexMatchTimeoutException
Console.WriteLine("The operation timed out after {0:N0} milliseconds",
e.MatchTimeout.TotalMilliseconds)
End Try
End Sub
End Module

Public Class RegexUtilities


Public Function GetWordData(filename As String) As Tuple(Of Integer, Double)
Const MAX_TIMEOUT As Integer = 1000 ' Maximum timeout interval in milliseconds.
Const INCREMENT As Integer = 350 ' Milliseconds increment of timeout.

Dim exclusions As New List(Of String)({"a", "an", "the" })


Dim wordLengths(30) As Integer ' Allocate an array of more than ample size.
Dim input As String = Nothing
Dim sr As StreamReader = Nothing
Try
sr = New StreamReader(filename)
input = sr.ReadToEnd()
Catch e As FileNotFoundException
Dim msg As String = String.Format("Unable to find the file '{0}'", filename)
Throw New IOException(msg, e)
Catch e As IOException
Throw New IOException(e.Message, e)
Finally
If sr IsNot Nothing Then sr.Close()
End Try

Dim timeoutInterval As Integer = INCREMENT


Dim init As Boolean = False
Dim rgx As Regex = Nothing
Dim m As Match = Nothing
Dim indexPos As Integer = 0
Do
Try
If Not init Then
rgx = New Regex("\b\w+\b", RegexOptions.None,
TimeSpan.FromMilliseconds(timeoutInterval))
m = rgx.Match(input, indexPos)
init = True
Else
m = m.NextMatch()
End If
If m.Success Then
If Not exclusions.Contains(m.Value.ToLower()) Then
wordLengths(m.Value.Length) += 1
End If
indexPos += m.Length + 1
End If
Catch e As RegexMatchTimeoutException
If e.MatchTimeout.TotalMilliseconds < MAX_TIMEOUT Then
timeoutInterval += INCREMENT
init = False
Else
' Rethrow the exception.
Throw
End If
End Try
Loop While m.Success

' If regex completed successfully, calculate number of words and average length.
Dim nWords As Integer
Dim nWords As Integer
Dim totalLength As Long

For ctr As Integer = wordLengths.GetLowerBound(0) To wordLengths.GetUpperBound(0)


nWords += wordLengths(ctr)
totalLength += ctr * wordLengths(ctr)
Next
Return New Tuple(Of Integer, Double)(nWords, totalLength/nWords)
End Function
End Class

Capturar solo cuando sea necesario


Las expresiones regulares de .NET admiten varias construcciones de agrupación, que permiten agrupar un patrón
de expresión regular en una o más subexpresiones. Las construcciones de agrupación que más se usan en el
lenguaje de expresiones regulares de .NET son ( subexpression ) , que define un grupo de captura numerado, y
(?< name > subexpression ) , que define un grupo de captura con nombre. Las construcciones de agrupación son
esenciales para crear referencias inversas y para definir una subexpresión a la que se aplica un cuantificador.
Sin embargo, el uso de estos elementos de lenguaje tiene un costo. Hacen que el objeto GroupCollection devuelto
por la propiedad Match.Groups se rellene con las capturas sin nombre o con nombre más recientes, y si una única
construcción de agrupación ha capturado varias subcadenas en la cadena de entrada, también rellenan el objeto
CaptureCollection devuelto por la propiedad Group.Captures de un grupo de captura determinado con varios
objetos Capture.
A menudo, las construcciones de agrupación se usan en una expresión regular solo para poder aplicarles
cuantificadores y los grupos capturados por estas subexpresiones no se usan posteriormente. Por ejemplo, la
expresión regular \b(\w+[;,]?\s?)+[.?!] está diseñada para capturar una frase completa. En la tabla siguiente se
describen los elementos del lenguaje de este patrón de expresión regular y su efecto sobre las colecciones Match y
Match.Groups del objeto Group.Captures.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

[;,]? Buscar coincidencias con cero o una coma o un punto y coma.

\s? Busca coincidencias con cero o un carácter de espacio en


blanco.

(\w+[;,]?\s?)+ Buscar coincidencias con una o más apariciones de uno o más


caracteres alfabéticos seguidos de una coma o un punto y
coma opcional, seguido de un carácter opcional de espacio en
blanco. Esto define al primer grupo de captura, que es
necesario para que la combinación de varios caracteres
alfabéticos (es decir, una palabra) seguidos de un signo de
puntuación opcional se repita hasta que el motor de
expresiones regulares llegue al final de una frase.

[.?!] Buscar coincidencias con un punto, un signo de interrogación


o un signo de exclamación.

Como se muestra en el ejemplo siguiente, cuando se encuentra una coincidencia, los objetos GroupCollection y
CaptureCollection se rellenan con capturas de la coincidencia. En este caso, el grupo de captura (\w+[;,]?\s?)
existe para que se le pueda aplicar el cuantificador + , que permite que el patrón de expresión regular coincida con
cada palabra de una frase. De lo contrario, coincidiría con la última palabra de una frase.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is one sentence. This is another.";
string pattern = @"\b(\w+[;,]?\s?)+[.?!]";

foreach (Match match in Regex.Matches(input, pattern)) {


Console.WriteLine("Match: '{0}' at index {1}.",
match.Value, match.Index);
int grpCtr = 0;
foreach (Group grp in match.Groups) {
Console.WriteLine(" Group {0}: '{1}' at index {2}.",
grpCtr, grp.Value, grp.Index);
int capCtr = 0;
foreach (Capture cap in grp.Captures) {
Console.WriteLine(" Capture {0}: '{1}' at {2}.",
capCtr, cap.Value, cap.Index);
capCtr++;
}
grpCtr++;
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// Match: 'This is one sentence.' at index 0.
// Group 0: 'This is one sentence.' at index 0.
// Capture 0: 'This is one sentence.' at 0.
// Group 1: 'sentence' at index 12.
// Capture 0: 'This ' at 0.
// Capture 1: 'is ' at 5.
// Capture 2: 'one ' at 8.
// Capture 3: 'sentence' at 12.
//
// Match: 'This is another.' at index 22.
// Group 0: 'This is another.' at index 22.
// Capture 0: 'This is another.' at 22.
// Group 1: 'another' at index 30.
// Capture 0: 'This ' at 22.
// Capture 1: 'is ' at 27.
// Capture 2: 'another' at 30.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is one sentence. This is another."
Dim pattern As String = "\b(\w+[;,]?\s?)+[.?!]"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("Match: '{0}' at index {1}.",
match.Value, match.Index)
Dim grpCtr As Integer = 0
For Each grp As Group In match.Groups
Console.WriteLine(" Group {0}: '{1}' at index {2}.",
grpCtr, grp.Value, grp.Index)
Dim capCtr As Integer = 0
For Each cap As Capture In grp.Captures
Console.WriteLine(" Capture {0}: '{1}' at {2}.",
capCtr, cap.Value, cap.Index)
capCtr += 1
Next
grpCtr += 1
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Match: 'This is one sentence.' at index 0.
' Group 0: 'This is one sentence.' at index 0.
' Capture 0: 'This is one sentence.' at 0.
' Group 1: 'sentence' at index 12.
' Capture 0: 'This ' at 0.
' Capture 1: 'is ' at 5.
' Capture 2: 'one ' at 8.
' Capture 3: 'sentence' at 12.
'
' Match: 'This is another.' at index 22.
' Group 0: 'This is another.' at index 22.
' Capture 0: 'This is another.' at 22.
' Group 1: 'another' at index 30.
' Capture 0: 'This ' at 22.
' Capture 1: 'is ' at 27.
' Capture 2: 'another' at 30.

Cuando use subexpresiones solo para aplicarles cuantificadores y no le interese el texto capturado, debe
deshabilitar las capturas de grupo. Por ejemplo, el elemento de lenguaje (?:subexpression) impide al grupo al que
se aplica que capture subcadenas coincidentes. En el ejemplo siguiente, el patrón de expresión regular del ejemplo
anterior se cambia a \b(?:\w+[;,]?\s?)+[.?!] . Como muestra el resultado, evita que el motor de expresiones
regulares rellene las colecciones GroupCollection y CaptureCollection.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is one sentence. This is another.";
string pattern = @"\b(?:\w+[;,]?\s?)+[.?!]";

foreach (Match match in Regex.Matches(input, pattern)) {


Console.WriteLine("Match: '{0}' at index {1}.",
match.Value, match.Index);
int grpCtr = 0;
foreach (Group grp in match.Groups) {
Console.WriteLine(" Group {0}: '{1}' at index {2}.",
grpCtr, grp.Value, grp.Index);
int capCtr = 0;
foreach (Capture cap in grp.Captures) {
Console.WriteLine(" Capture {0}: '{1}' at {2}.",
capCtr, cap.Value, cap.Index);
capCtr++;
}
grpCtr++;
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// Match: 'This is one sentence.' at index 0.
// Group 0: 'This is one sentence.' at index 0.
// Capture 0: 'This is one sentence.' at 0.
//
// Match: 'This is another.' at index 22.
// Group 0: 'This is another.' at index 22.
// Capture 0: 'This is another.' at 22.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is one sentence. This is another."
Dim pattern As String = "\b(?:\w+[;,]?\s?)+[.?!]"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine("Match: '{0}' at index {1}.",
match.Value, match.Index)
Dim grpCtr As Integer = 0
For Each grp As Group In match.Groups
Console.WriteLine(" Group {0}: '{1}' at index {2}.",
grpCtr, grp.Value, grp.Index)
Dim capCtr As Integer = 0
For Each cap As Capture In grp.Captures
Console.WriteLine(" Capture {0}: '{1}' at {2}.",
capCtr, cap.Value, cap.Index)
capCtr += 1
Next
grpCtr += 1
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Match: 'This is one sentence.' at index 0.
' Group 0: 'This is one sentence.' at index 0.
' Capture 0: 'This is one sentence.' at 0.
'
' Match: 'This is another.' at index 22.
' Group 0: 'This is another.' at index 22.
' Capture 0: 'This is another.' at 22.

Puede deshabilitar las capturas de una de las maneras siguientes:


Use el elemento de lenguaje (?:subexpression) . Este elemento impide la captura de subcadenas
coincidentes en el grupo al que se aplica. No deshabilita las capturas de subcadenas en ningún grupo
anidado.
Use la opción ExplicitCapture. Deshabilita todas las capturas sin nombre o implícitas en el patrón de
expresión regular. Cuando se usa esta opción, solo se pueden capturar las subcadenas que coinciden con
grupos con nombre definidos con el elemento de lenguaje (?<name>subexpression) . La marca
ExplicitCapture se puede pasar al parámetro options de un constructor de clase Regex o al parámetro
options de un método coincidente estático Regex.

Use la opción n del elemento de lenguaje (?imnsx) . Esta opción deshabilita todas las capturas sin nombre
o implícitas desde el punto del patrón de expresión regular en el que aparece el elemento. Las capturas se
deshabilitan hasta el final del modelo o hasta que la opción (-n) habilita las capturas sin nombre o
implícitas. Para obtener más información, consulte Construcciones misceláneas.
Use la opción n del elemento de lenguaje (?imnsx:subexpression) . Esta opción deshabilita todas las
capturas sin nombre o implícitas en subexpression . Las capturas por grupos de captura anidados sin
nombre o implícitos también se deshabilitan.

Temas relacionados
TITLE DESCRIPCIÓN

Detalles del comportamiento de expresiones regulares Examina la implementación del motor de expresiones regulares
de .NET. El tema se centra en la flexibilidad de las expresiones
regulares y explica la responsabilidad del desarrollador para
garantizar un funcionamiento eficaz y sólido del motor de
expresiones regulares.

Retroceso Explica qué es el retroceso y cómo afecta al rendimiento de las


expresiones regulares, y examine los elementos del lenguaje
que proporcionan alternativas al retroceso.

Lenguaje de expresiones regulares: referencia rápida Describe los elementos del lenguaje de expresiones regulares
de .NET y proporciona vínculos a documentación detallada
sobre cada elemento del lenguaje.
El modelo de objetos de expresión regular
04/11/2019 • 44 minutes to read • Edit Online

En este tema se describe el modelo de objetos usado para trabajar con expresiones regulares de .NET. Contiene
las siguientes secciones:
Motor de expresiones regulares
Objetos MatchCollection y Match
Colección de grupos
Grupo capturado
Colección de capturas
Captura individual

El motor de expresiones regulares


La clase Regex representa el motor de expresiones regulares de .NET. El motor de expresiones regulares es
responsable de analizar y compilar una expresión regular y de realizar operaciones en las que coinciden el patrón
de expresión regular con una cadena de entrada. El motor es el componente central del modelo de objetos de
expresión regular de .NET.
Puede utilizar el motor de expresiones regulares en una de estas dos formas:
Creando métodos estáticos de la clase Regex. Los parámetros de método incluyen la cadena de entrada y
el patrón de expresión regular. El motor de expresiones regulares almacena en memoria caché las
expresiones regulares que se utilizan en llamadas de métodos estáticos, por lo que las llamadas repetidas a
métodos de expresiones regulares estáticos que usan la misma expresión regular ofrecen un rendimiento
relativamente bueno.
Creando instancias de un objeto Regex, al pasar una expresión regular al constructor de clase. En este caso,
el objeto Regex es inmutable (de solo lectura) y representa un motor de expresiones regulares
estrechamente acoplado a una expresión regular única. Dado que las expresiones regulares utilizadas por
instancias Regex no están almacenadas en memoria caché, no debe crear varias veces instancias de un
objeto Regex con la misma expresión regular.
Puede llamar a los métodos de la clase Regex para realizar las operaciones siguientes:
Determinar si una cadena coincide con un patrón de expresión regular.
Extraer una coincidencia única o la primera coincidencia.
Extraer todas las coincidencias.
Reemplazar una subcadena coincidente.
Dividir una cadena única en una matriz de cadenas.
Estas operaciones se describen en las siguientes secciones.
Buscar coincidencias con un patrón de expresión regular
Este método Regex.IsMatch devuelve true si la cadena coincide con el patrón o false en caso contrario. El
método IsMatch se utiliza a menudo para validar una entrada de cadena. Por ejemplo, el siguiente código
garantiza que una cadena coincide con un número válido de la seguridad social en los Estados Unidos.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] values = { "111-22-3333", "111-2-3333"};
string pattern = @"^\d{3}-\d{2}-\d{4}$";
foreach (string value in values) {
if (Regex.IsMatch(value, pattern))
Console.WriteLine("{0} is a valid SSN.", value);
else
Console.WriteLine("{0}: Invalid", value);
}
}
}
// The example displays the following output:
// 111-22-3333 is a valid SSN.
// 111-2-3333: Invalid

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim values() As String = { "111-22-3333", "111-2-3333"}
Dim pattern As String = "^\d{3}-\d{2}-\d{4}$"
For Each value As String In values
If Regex.IsMatch(value, pattern) Then
Console.WriteLine("{0} is a valid SSN.", value)
Else
Console.WriteLine("{0}: Invalid", value)
End If
Next
End Sub
End Module
' The example displays the following output:
' 111-22-3333 is a valid SSN.
' 111-2-3333: Invalid

El patrón de la expresión regular ^\d{3}-\d{2}-\d{4}$ se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Buscar coincidencias con el principio de la cadena de entrada.

\d{3} Coincide con tres dígitos decimales.

- Buscar coincidencias con un guion.

\d{2} Coincide con dos dígitos decimales.

- Buscar coincidencias con un guion.

\d{4} Buscar coincidencias con cuatro dígitos decimales.

$ Coincide con el final de la cadena de entrada.


Extraer una coincidencia única o la primera coincidencia.
El método Regex.Match devuelve un objeto Match que contiene información sobre la primera subcadena que
coincida con un patrón de expresión regular. Si la propiedad Match.Success devuelve true , lo que indica que se
encontró una coincidencia, puede recuperar información sobre las coincidencias subsiguientes llamando al
método Match.NextMatch. Estas llamadas a métodos pueden seguir hasta que la propiedad Match.Success
devuelva false . Por ejemplo, el código siguiente utiliza el método Regex.Match(String, String) para buscar la
primera aparición de una palabra duplicada en una cadena. A continuación, llama al método Match.NextMatch
para encontrar cualquier aparición adicional. El ejemplo examina la propiedad Match.Success después de cada
llamada al método para determinar si la coincidencia actual ha sido correcta y si debe seguir una llamada al
método Match.NextMatch.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is a a farm that that raises dairy cattle.";
string pattern = @"\b(\w+)\W+(\1)\b";
Match match = Regex.Match(input, pattern);
while (match.Success)
{
Console.WriteLine("Duplicate '{0}' found at position {1}.",
match.Groups[1].Value, match.Groups[2].Index);
match = match.NextMatch();
}
}
}
// The example displays the following output:
// Duplicate 'a' found at position 10.
// Duplicate 'that' found at position 22.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is a a farm that that raises dairy cattle."
Dim pattern As String = "\b(\w+)\W+(\1)\b"
Dim match As Match = Regex.Match(input, pattern)
Do While match.Success
Console.WriteLine("Duplicate '{0}' found at position {1}.", _
match.Groups(1).Value, match.Groups(2).Index)
match = match.NextMatch()
Loop
End Sub
End Module
' The example displays the following output:
' Duplicate 'a' found at position 10.
' Duplicate 'that' found at position 22.

El patrón de la expresión regular \b(\w+)\W+(\1)\b se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Comienza la búsqueda de coincidencias en un límite de


palabras.
MODELO DESCRIPCIÓN

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este es el primer grupo de captura.

\W+ Coincide con uno o varios caracteres que no se usan para


formar palabras.

(\1) Buscar coincidencias con la primera cadena capturada. Este es


el segundo grupo de captura.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Extraer todas las coincidencias


El método Regex.Matches devuelve un objeto MatchCollection que contiene información sobre todas las
coincidencias que el motor de expresiones regulares encontró en la cadena de entrada. Por ejemplo, se podría
escribir de nuevo el ejemplo anterior para que llamara al método Matches en lugar de a los métodos Match y
NextMatch.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "This is a a farm that that raises dairy cattle.";
string pattern = @"\b(\w+)\W+(\1)\b";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Duplicate '{0}' found at position {1}.",
match.Groups[1].Value, match.Groups[2].Index);
}
}
// The example displays the following output:
// Duplicate 'a' found at position 10.
// Duplicate 'that' found at position 22.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "This is a a farm that that raises dairy cattle."
Dim pattern As String = "\b(\w+)\W+(\1)\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Duplicate '{0}' found at position {1}.", _
match.Groups(1).Value, match.Groups(2).Index)
Next
End Sub
End Module
' The example displays the following output:
' Duplicate 'a' found at position 10.
' Duplicate 'that' found at position 22.

Reemplazar una subcadena coincidente


El método Regex.Replace reemplaza cada subcadena que hace coincidir el patrón de expresión regular con una
cadena o patrón de expresión regular especificados, y devuelve la cadena de entrada completa con reemplazos.
Por ejemplo, el código siguiente agrega un símbolo de la divisa de EE. UU. antes de un número decimal en una
cadena.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b\d+\.\d{2}\b";
string replacement = "$$$&";
string input = "Total Cost: 103.64";
Console.WriteLine(Regex.Replace(input, pattern, replacement));
}
}
// The example displays the following output:
// Total Cost: $103.64

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b\d+\.\d{2}\b"
Dim replacement As String = "$$$&"
Dim input As String = "Total Cost: 103.64"
Console.WriteLine(Regex.Replace(input, pattern, replacement))
End Sub
End Module
' The example displays the following output:
' Total Cost: $103.64

El patrón de la expresión regular \b\d+\.\d{2}\b se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\d+ Buscar coincidencias con uno o más dígitos decimales.

\. Coincide con un punto.

\d{2} Coincide con dos dígitos decimales.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

El patrón de reemplazo $$$& se interpreta como se muestra en la siguiente tabla.

MODELO CADENA DE REEMPLAZO

$$ El carácter del signo de dólar ($).

$& La subcadena coincidente completa.

Dividir una cadena única en una matriz de cadenas


El método Regex.Split divide la cadena de entrada en las posiciones definidas por una coincidencia de expresión
regular. Por ejemplo, el siguiente código coloca los elementos de una lista numerada en una matriz de cadena.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "1. Eggs 2. Bread 3. Milk 4. Coffee 5. Tea";
string pattern = @"\b\d{1,2}\.\s";
foreach (string item in Regex.Split(input, pattern))
{
if (! String.IsNullOrEmpty(item))
Console.WriteLine(item);
}
}
}
// The example displays the following output:
// Eggs
// Bread
// Milk
// Coffee
// Tea

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "1. Eggs 2. Bread 3. Milk 4. Coffee 5. Tea"
Dim pattern As String = "\b\d{1,2}\.\s"
For Each item As String In Regex.Split(input, pattern)
If Not String.IsNullOrEmpty(item) Then
Console.WriteLine(item)
End If
Next
End Sub
End Module
' The example displays the following output:
' Eggs
' Bread
' Milk
' Coffee
' Tea

El patrón de la expresión regular \b\d{1,2}\.\s se interpreta como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\d{1,2} Buscar coincidencias con uno o dos dígitos decimales.

\. Coincide con un punto.

\s Coincide con un carácter de espacio en blanco.

Objetos MatchCollection y Match


Los métodos Regex devuelven dos objetos que forman parte del modelo de objetos de expresión regular: el
objeto MatchCollection y el objeto Match.
La colección de coincidencias
El método Regex.Matches devuelve un objeto MatchCollection que contiene objetos Match que representan todas
las coincidencias que encontró el motor de expresiones regulares, en el orden en el que aparecen en la cadena de
entrada. Si no hay ninguna coincidencia, el método devuelve un objeto MatchCollection sin miembros. La
propiedad MatchCollection.Item[Int32] proporciona acceso a miembros individuales de la colección por índice,
desde cero hasta uno menos que el valor de la propiedad MatchCollection.Count. Item[Int32] es el indizador de la
colección (en C#) y la propiedad predeterminada (en Visual Basic).
De forma predeterminada, la llamada al método Regex.Matches utiliza la evaluación diferida para rellenar el
objeto MatchCollection. El acceso a propiedades que requieren una colección totalmente rellenada, como las
propiedades MatchCollection.Count y MatchCollection.Item[Int32], puede implicar una reducción del
rendimiento. En consecuencia, recomendamos tener acceso a la colección utilizando el objeto IEnumerator
devuelto por el método MatchCollection.GetEnumerator. Los lenguajes individuales proporcionan construcciones,
como For Each en Visual Basic y foreach en C#, que ajustan la interfaz IEnumerator de la colección.
En el siguiente ejemplo se utiliza el método Regex.Matches(String) para rellenar un objeto MatchCollection con
todas las coincidencias encontradas en una cadena de entrada. El ejemplo enumera la colección, copia las
coincidencias en una matriz de cadena y registra las posiciones de caracteres en una matriz entera.

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
MatchCollection matches;
List<string> results = new List<string>();
List<int> matchposition = new List<int>();

// Create a new Regex object and define the regular expression.


Regex r = new Regex("abc");
// Use the Matches method to find all matches in the input string.
matches = r.Matches("123abc4abcd");
// Enumerate the collection to retrieve all matches and positions.
foreach (Match match in matches)
{
// Add the match string to the string array.
results.Add(match.Value);
// Record the character position where the match was found.
matchposition.Add(match.Index);
}
// List the results.
for (int ctr = 0; ctr < results.Count; ctr++)
Console.WriteLine("'{0}' found at position {1}.",
results[ctr], matchposition[ctr]);
}
}
// The example displays the following output:
// 'abc' found at position 3.
// 'abc' found at position 7.
Imports System.Collections.Generic
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim matches As MatchCollection
Dim results As New List(Of String)
Dim matchposition As New List(Of Integer)

' Create a new Regex object and define the regular expression.
Dim r As New Regex("abc")
' Use the Matches method to find all matches in the input string.
matches = r.Matches("123abc4abcd")
' Enumerate the collection to retrieve all matches and positions.
For Each match As Match In matches
' Add the match string to the string array.
results.Add(match.Value)
' Record the character position where the match was found.
matchposition.Add(match.Index)
Next
' List the results.
For ctr As Integer = 0 To results.Count - 1
Console.WriteLine("'{0}' found at position {1}.", _
results(ctr), matchposition(ctr))
Next
End Sub
End Module
' The example displays the following output:
' 'abc' found at position 3.
' 'abc' found at position 7.

La coincidencia
La clase Match representa el resultado de una coincidencia de expresión regular única. Puede tener acceso a los
objetos Match de dos formas:
Recuperándolos del objeto MatchCollection devuelto por el método Regex.Matches. Para recuperar objetos
Match individuales, itere la colección utilizando una construcción foreach (en C#) o For Each ... Next (en
Visual Basic) o use la propiedad MatchCollection.Item[Int32] para recuperar un determinado objeto Match
por índice o por nombre. También puede recuperar objetos Match individuales de la colección iterando la
colección por índice, desde cero a uno menos que el número de objetos de la colección. Sin embargo, este
método no saca partido de la evaluación diferida, porque tiene acceso a la propiedad
MatchCollection.Count.
En el siguiente ejemplo se recuperan objetos Match individuales de un objeto MatchCollection iterando la
colección mediante la construcción foreach o For Each ... Next . La expresión regular simplemente
coincide con la cadena "abc" de la cadena de entrada.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "abc";
string input = "abc123abc456abc789";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("{0} found at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// abc found at position 0.
// abc found at position 6.
// abc found at position 12.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "abc"
Dim input As String = "abc123abc456abc789"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("{0} found at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' abc found at position 0.
' abc found at position 6.
' abc found at position 12.

Llamando al método Regex.Match, que devuelve un objeto Match que representa la primera coincidencia
en una cadena o una parte de una cadena. Puede determinar si la coincidencia se ha encontrado
recuperando el valor de la propiedad Match.Success . Para recuperar objetos Match que representan las
coincidencias subsiguientes, llame repetidamente al método Match.NextMatch, hasta que la propiedad
Success del objeto Match devuelto sea false .

En el siguiente ejemplo se utilizan los métodos Regex.Match(String, String) y Match.NextMatch para


buscar coincidencias con la cadena "abc" en la cadena de entrada.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "abc";
string input = "abc123abc456abc789";
Match match = Regex.Match(input, pattern);
while (match.Success)
{
Console.WriteLine("{0} found at position {1}.",
match.Value, match.Index);
match = match.NextMatch();
}
}
}
// The example displays the following output:
// abc found at position 0.
// abc found at position 6.
// abc found at position 12.

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "abc"
Dim input As String = "abc123abc456abc789"
Dim match As Match = Regex.Match(input, pattern)
Do While match.Success
Console.WriteLine("{0} found at position {1}.", _
match.Value, match.Index)
match = match.NextMatch()
Loop
End Sub
End Module
' The example displays the following output:
' abc found at position 0.
' abc found at position 6.
' abc found at position 12.

Dos propiedades de la clase Match devuelven objetos de colección:


La propiedad Match.Groups devuelve un objeto GroupCollection que contiene información sobre las
subcadenas que coinciden con grupos de captura en el patrón de expresión regular.
La propiedad Match.Captures devuelve un objeto CaptureCollection que es de uso limitado. La colección
no se rellena para un objeto Match cuya propiedad Success es false . De lo contrario, contiene un único
objeto Capture que tiene la misma información que el objeto Match.
Para obtener más información sobre estos objetos, vea las secciones Colección de grupos y Colección de capturas
más adelante en este tema.
Dos propiedades adicionales de la clase Match proporcionan información sobre la coincidencia. La propiedad
Match.Value devuelve la subcadena en la cadena de entrada que coincide con el patrón de expresión regular. La
propiedad Match.Index devuelve la posición inicial basada en cero de la cadena coincidente en la cadena de
entrada.
La clase Match también tiene dos métodos de coincidencia de patrones:
El método Match.NextMatch encuentra la coincidencia según la coincidencia representada por el objeto
Match actual y devuelve un objeto Match que representa esa coincidencia.
El método Match.Result realiza una operación de reemplazo especificada en la cadena coincidente y
devuelve el resultado.
En el siguiente ejemplo se utiliza el método Match.Result para anteponer un símbolo $ y un espacio antes de cada
número que incluye dos dígitos fraccionarios.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b\d+(,\d{3})*\.\d{2}\b";
string input = "16.32\n194.03\n1,903,672.08";

foreach (Match match in Regex.Matches(input, pattern))


Console.WriteLine(match.Result("$$ $&"));
}
}
// The example displays the following output:
// $ 16.32
// $ 194.03
// $ 1,903,672.08

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b\d+(,\d{3})*\.\d{2}\b"
Dim input As String = "16.32" + vbCrLf + "194.03" + vbCrLf + "1,903,672.08"

For Each match As Match In Regex.Matches(input, pattern)


Console.WriteLine(match.Result("$$ $&"))
Next
End Sub
End Module
' The example displays the following output:
' $ 16.32
' $ 194.03
' $ 1,903,672.08

El patrón de expresión regular \b\d+(,\d{3})*\.\d{2}\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

\d+ Buscar coincidencias con uno o más dígitos decimales.

(,\d{3})* Buscar coincidencias con cero o más apariciones de una coma


seguida de tres dígitos decimales.

\. Buscar coincidencias con el carácter de separador decimal.

\d{2} Coincide con dos dígitos decimales.


MODELO DESCRIPCIÓN

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

El patrón de reemplazo $$ $& indica que la subcadena debe ser reemplazada por un símbolo de signo de dólar
($) (el patrón $$ ), un espacio y el valor de la coincidencia (el patrón $& ).
Volver al principio

La colección de grupos
La propiedad Match.Groups devuelve un objeto GroupCollection que contiene objetos Group que representan los
grupos capturados en una coincidencia única. El primer objeto Group de la colección (en el índice 0) representa la
coincidencia completa. Cada objeto que sigue representa los resultados de un grupo de captura único.
Puede recuperar objetos Group individuales en la colección utilizando la propiedad GroupCollection.Item[String].
Puede recuperar los grupos sin nombre por su posición ordinal en la colección y recuperar grupos con nombre
por nombre o por posición ordinal. Las capturas sin nombre aparecen primero en la colección y se indizan de
izquierda a derecha en el orden en el que aparecen en el patrón de expresión regular. Las capturas con nombre se
indizan después de las capturas sin nombre, de izquierda a derecha en el orden en el que aparecen en el patrón de
expresión regular. Para determinar qué grupos numerados están disponibles en la colección devuelta para un
determinado método de coincidencia de expresión regular, puede llamar al método Regex.GetGroupNumbers de
instancia. Para determinar qué grupos con nombre están disponibles en la colección, puede llamar al método
Regex.GetGroupNames de instancia. Ambos métodos son especialmente útiles en rutinas de uso general que
analizan las coincidencias encontradas por cualquier expresión regular.
La propiedad GroupCollection.Item[String] es el indizador de la colección en C# y la propiedad predeterminada
del objeto de la colección en Visual Basic. Esto significa que se puede tener acceso a los objetos Group
individuales por índice (o por nombre, en el caso de grupos con nombre) del modo siguiente:

Group group = match.Groups[ctr];

Dim group As Group = match.Groups(ctr)

En el siguiente ejemplo se define una expresión regular que usa construcciones de agrupación para capturar el
mes, día y año de una fecha.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(\w+)\s(\d{1,2}),\s(\d{4})\b";
string input = "Born: July 28, 1989";
Match match = Regex.Match(input, pattern);
if (match.Success)
for (int ctr = 0; ctr < match.Groups.Count; ctr++)
Console.WriteLine("Group {0}: {1}", ctr, match.Groups[ctr].Value);
}
}
// The example displays the following output:
// Group 0: July 28, 1989
// Group 1: July
// Group 2: 28
// Group 3: 1989

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(\w+)\s(\d{1,2}),\s(\d{4})\b"
Dim input As String = "Born: July 28, 1989"
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
For ctr As Integer = 0 To match.Groups.Count - 1
Console.WriteLine("Group {0}: {1}", ctr, match.Groups(ctr).Value)
Next
End If
End Sub
End Module
' The example displays the following output:
' Group 0: July 28, 1989
' Group 1: July
' Group 2: 28
' Group 3: 1989

El patrón de expresión regular \b(\w+)\s(\d{1,2}),\s(\d{4})\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Este es el primer grupo de captura.

\s Coincide con un carácter de espacio en blanco.

(\d{1,2}) Buscar coincidencias con uno o dos dígitos decimales. Este es


el segundo grupo de captura.

, Coincide con una coma.

\s Coincide con un carácter de espacio en blanco.


MODELO DESCRIPCIÓN

(\d{4}) Buscar coincidencias con cuatro dígitos decimales. Éste es el


tercer grupo de captura.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Volver al principio

El grupo capturado
La clase Group representa el resultado de un único grupo de captura. La propiedad Item[String] del objeto
GroupCollection devuelto por la propiedad Match.Groups devuelve objetos de grupo que representan grupos de
captura definidos en una expresión regular. La propiedad Item[String] es el indizador (en C#) y la propiedad
predeterminada (en Visual Basic) de la clase Group. También puede recuperar miembros individuales mediante la
iteración de la colección con la construcción foreach o For Each . Para obtener un ejemplo, vea la sección
anterior.
En el siguiente ejemplo se utilizan construcciones de agrupación anidadas para capturar subcadenas en grupos. El
patrón de expresión regular (a(b))c coincide con la cadena "abc". Asigna la subcadena "ab" al primer grupo de
captura y la subcadena "b" al segundo grupo de captura.

var matchposition = new List<int>();


var results = new List<string>();
// Define substrings abc, ab, b.
var r = new Regex("(a(b))c");
Match m = r.Match("abdabc");
for (int i = 0; m.Groups[i].Value != ""; i++)
{
// Add groups to string array.
results.Add(m.Groups[i].Value);
// Record character position.
matchposition.Add(m.Groups[i].Index);
}

// Display the capture groups.


for (int ctr = 0; ctr < results.Count; ctr++)
Console.WriteLine("{0} at position {1}",
results[ctr], matchposition[ctr]);
// The example displays the following output:
// abc at position 3
// ab at position 3
// b at position 4
Dim matchposition As New List(Of Integer)
Dim results As New List(Of String)
' Define substrings abc, ab, b.
Dim r As New Regex("(a(b))c")
Dim m As Match = r.Match("abdabc")
Dim i As Integer = 0
While Not (m.Groups(i).Value = "")
' Add groups to string array.
results.Add(m.Groups(i).Value)
' Record character position.
matchposition.Add(m.Groups(i).Index)
i += 1
End While

' Display the capture groups.


For ctr As Integer = 0 to results.Count - 1
Console.WriteLine("{0} at position {1}", _
results(ctr), matchposition(ctr))
Next
' The example displays the following output:
' abc at position 3
' ab at position 3
' b at position 4

En el siguiente ejemplo se utilizan construcciones de agrupación con nombre para capturar subcadenas de una
cadena que contiene datos en el formato "NOMBREDATOS:VALOR" que la expresión regular divide por el signo
de dos puntos (:).

var r = new Regex(@"^(?<name>\w+):(?<value>\w+)");


Match m = r.Match("Section1:119900");
Console.WriteLine(m.Groups["name"].Value);
Console.WriteLine(m.Groups["value"].Value);
// The example displays the following output:
// Section1
// 119900

Dim r As New Regex("^(?<name>\w+):(?<value>\w+)")


Dim m As Match = r.Match("Section1:119900")
Console.WriteLine(m.Groups("name").Value)
Console.WriteLine(m.Groups("value").Value)
' The example displays the following output:
' Section1
' 119900

El patrón de expresión regular ^(?<name>\w+):(?<value>\w+) se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias con el principio de la


cadena de entrada.

(?<name>\w+) Buscar coincidencias con uno o más caracteres alfabéticos. El


nombre de este grupo de captura es name .

: Buscar coincidencia con un signo de dos puntos.

(?<value>\w+) Buscar coincidencias con uno o más caracteres alfabéticos. El


nombre de este grupo de captura es value .
Las propiedades de la clase Group proporcionan información sobre el grupo capturado: La propiedad
Group.Value contiene la subcadena capturada, la propiedad Group.Index indica la posición inicial del grupo
capturado en el texto de entrada, la propiedad Group.Length contiene la longitud del texto capturado y la
propiedad Group.Success indica si una subcadena coincidió con el patrón definido por el grupo de captura.
Al aplicar cuantificadores a un grupo (para obtener más información, consulte Cuantificadores), se modifica la
relación de una captura por grupo de captura de dos maneras:
Si el cuantificador * o *? (qué especifica cero o más coincidencias) se aplica a un grupo, es posible que
un grupo de captura no tenga una coincidencia en la cadena de entrada. Cuando no haya texto capturado,
las propiedades del objeto Group se establecen como se muestran en la siguiente tabla.

PROPIEDADES DE GRUPO VALOR

Success false

Value String.Empty

Length 0

Esto se muestra en el ejemplo siguiente. En el patrón de expresión regular aaa(bbb)*ccc , se pueden buscar
coincidencias para el primer grupo de captura (la subcadena "bbb") cero o varias veces. Dado que la
cadena de entrada "aaaccc" coincide con el patrón, el grupo de captura no tiene una coincidencia.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "aaa(bbb)*ccc";
string input = "aaaccc";
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match value: {0}", match.Value);
if (match.Groups[1].Success)
Console.WriteLine("Group 1 value: {0}", match.Groups[1].Value);
else
Console.WriteLine("The first capturing group has no match.");
}
}
// The example displays the following output:
// Match value: aaaccc
// The first capturing group has no match.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "aaa(bbb)*ccc"
Dim input As String = "aaaccc"
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match value: {0}", match.Value)
If match.Groups(1).Success Then
Console.WriteLine("Group 1 value: {0}", match.Groups(1).Value)
Else
Console.WriteLine("The first capturing group has no match.")
End If
End Sub
End Module
' The example displays the following output:
' Match value: aaaccc
' The first capturing group has no match.

Los cuantificadores pueden coincidir con varias apariciones de un patrón definido por un grupo de captura.
En este caso, las propiedades Value y Length de un objeto Group solo contienen información sobre la
última subcadena capturada. Por ejemplo, la siguiente coincidencia de expresión regular coincide con una
frase única que finaliza con un punto. La expresión utiliza dos construcciones de agrupación: la primera
captura palabras individuales junto con un carácter de espacio en blanco; la segunda captura palabras
individuales. Como lo muestra el resultado del ejemplo, aunque la expresión regular logre capturar una
frase completa, el segundo grupo de captura solo captura la última palabra.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b((\w+)\s?)+\.";
string input = "This is a sentence. This is another sentence.";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine("Match: " + match.Value);
Console.WriteLine("Group 2: " + match.Groups[2].Value);
}
}
}
// The example displays the following output:
// Match: This is a sentence.
// Group 2: sentence
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b((\w+)\s?)+\."
Dim input As String = "This is a sentence. This is another sentence."
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine("Match: " + match.Value)
Console.WriteLine("Group 2: " + match.Groups(2).Value)
End If
End Sub
End Module
' The example displays the following output:
' Match: This is a sentence.
' Group 2: sentence

Volver al principio

La colección de capturas
El objeto Group solo contiene información sobre la última captura. Sin embargo, el conjunto completo de
capturas realizado por un grupo de captura sigue aún disponible en el objeto CaptureCollection devuelto por la
propiedad Group.Captures. Cada miembro de la colección es un objeto Capture que representa una captura
realizada por este grupo de captura, en el orden en el que se capturaron (y, por consiguiente, en el orden en el que
las cadenas capturadas coincidían de izquierda a derecha en la cadena de entrada). Puede recuperar objetos
Capture individuales de la colección de estas dos formas:
Mediante la iteración de la colección con el uso de una construcción como foreach (en C#) o For Each
(en Visual Basic).
Utilizando la propiedad CaptureCollection.Item[Int32] para recuperar un objeto específico por índice. La
propiedad Item[Int32] es la propiedad predeterminada del objeto CaptureCollection (en Visual Basic) o el
indizador (en C#).
Si no se aplica un cuantificador a un grupo de captura, el objeto CaptureCollection contiene un objeto Capture
único que es de escaso interés, porque proporciona información sobre la misma coincidencia que su objeto
Group. Si se aplica un cuantificador a un grupo de captura, el objeto CaptureCollection contiene todas las
capturas realizadas por el grupo de captura y el último miembro de la colección representa la misma captura que
el objeto Group.
Si utiliza, por ejemplo, el patrón de expresión regular ((a(b))c)+ (donde el cuantificador + indica una o varias
coincidencias) para capturar coincidencias de la cadena "abcabcabc", el objeto CaptureCollection para cada objeto
Group contiene tres miembros.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "((a(b))c)+";
string input = "abcabcabc";

Match match = Regex.Match(input, pattern);


if (match.Success)
{
Console.WriteLine("Match: '{0}' at position {1}",
match.Value, match.Index);
GroupCollection groups = match.Groups;
for (int ctr = 0; ctr < groups.Count; ctr++) {
Console.WriteLine(" Group {0}: '{1}' at position {2}",
ctr, groups[ctr].Value, groups[ctr].Index);
CaptureCollection captures = groups[ctr].Captures;
for (int ctr2 = 0; ctr2 < captures.Count; ctr2++) {
Console.WriteLine(" Capture {0}: '{1}' at position {2}",
ctr2, captures[ctr2].Value, captures[ctr2].Index);
}
}
}
}
}
// The example displays the following output:
// Match: 'abcabcabc' at position 0
// Group 0: 'abcabcabc' at position 0
// Capture 0: 'abcabcabc' at position 0
// Group 1: 'abc' at position 6
// Capture 0: 'abc' at position 0
// Capture 1: 'abc' at position 3
// Capture 2: 'abc' at position 6
// Group 2: 'ab' at position 6
// Capture 0: 'ab' at position 0
// Capture 1: 'ab' at position 3
// Capture 2: 'ab' at position 6
// Group 3: 'b' at position 7
// Capture 0: 'b' at position 1
// Capture 1: 'b' at position 4
// Capture 2: 'b' at position 7
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "((a(b))c)+"
Dim input As STring = "abcabcabc"

Dim match As Match = Regex.Match(input, pattern)


If match.Success Then
Console.WriteLine("Match: '{0}' at position {1}", _
match.Value, match.Index)
Dim groups As GroupCollection = match.Groups
For ctr As Integer = 0 To groups.Count - 1
Console.WriteLine(" Group {0}: '{1}' at position {2}", _
ctr, groups(ctr).Value, groups(ctr).Index)
Dim captures As CaptureCollection = groups(ctr).Captures
For ctr2 As Integer = 0 To captures.Count - 1
Console.WriteLine(" Capture {0}: '{1}' at position {2}", _
ctr2, captures(ctr2).Value, captures(ctr2).Index)
Next
Next
End If
End Sub
End Module
' The example dosplays the following output:
' Match: 'abcabcabc' at position 0
' Group 0: 'abcabcabc' at position 0
' Capture 0: 'abcabcabc' at position 0
' Group 1: 'abc' at position 6
' Capture 0: 'abc' at position 0
' Capture 1: 'abc' at position 3
' Capture 2: 'abc' at position 6
' Group 2: 'ab' at position 6
' Capture 0: 'ab' at position 0
' Capture 1: 'ab' at position 3
' Capture 2: 'ab' at position 6
' Group 3: 'b' at position 7
' Capture 0: 'b' at position 1
' Capture 1: 'b' at position 4
' Capture 2: 'b' at position 7

En el siguiente ejemplo se utiliza la expresión regular (Abc)+ para buscar una o más ejecuciones consecutivas de
la cadena "Abc" en la cadena "XYZAbcAbcAbcXYZAbcAb". El ejemplo ilustra la forma en que se utiliza la
propiedad Group.Captures para que devuelva varios grupos de subcadenas capturadas.
int counter;
Match m;
CaptureCollection cc;
GroupCollection gc;

// Look for groupings of "Abc".


var r = new Regex("(Abc)+");
// Define the string to search.
m = r.Match("XYZAbcAbcAbcXYZAbcAb");
gc = m.Groups;

// Display the number of groups.


Console.WriteLine("Captured groups = " + gc.Count.ToString());

// Loop through each group.


for (int i = 0; i < gc.Count; i++)
{
cc = gc[i].Captures;
counter = cc.Count;

// Display the number of captures in this group.


Console.WriteLine("Captures count = " + counter.ToString());

// Loop through each capture in the group.


for (int ii = 0; ii < counter; ii++)
{
// Display the capture and its position.
Console.WriteLine(cc[ii] + " Starts at character " +
cc[ii].Index);
}
}
// The example displays the following output:
// Captured groups = 2
// Captures count = 1
// AbcAbcAbc Starts at character 3
// Captures count = 3
// Abc Starts at character 3
// Abc Starts at character 6
// Abc Starts at character 9
Dim counter As Integer
Dim m As Match
Dim cc As CaptureCollection
Dim gc As GroupCollection

' Look for groupings of "Abc".


Dim r As New Regex("(Abc)+")
' Define the string to search.
m = r.Match("XYZAbcAbcAbcXYZAbcAb")
gc = m.Groups

' Display the number of groups.


Console.WriteLine("Captured groups = " & gc.Count.ToString())

' Loop through each group.


Dim i, ii As Integer
For i = 0 To gc.Count - 1
cc = gc(i).Captures
counter = cc.Count

' Display the number of captures in this group.


Console.WriteLine("Captures count = " & counter.ToString())

' Loop through each capture in the group.


For ii = 0 To counter - 1
' Display the capture and its position.
Console.WriteLine(cc(ii).ToString() _
& " Starts at character " & cc(ii).Index.ToString())
Next ii
Next i
' The example displays the following output:
' Captured groups = 2
' Captures count = 1
' AbcAbcAbc Starts at character 3
' Captures count = 3
' Abc Starts at character 3
' Abc Starts at character 6
' Abc Starts at character 9

Volver al principio

La captura individual
La clase Capture contiene el resultado de una única captura de subexpresiones. La propiedad Capture.Value
contiene el texto coincidente y la propiedad Capture.Index indica la posición basada en cero en la cadena de
entrada en la que la comienza la subcadena coincidente.
En el siguiente ejemplo se analiza una cadena de entrada para la temperatura de las ciudades seleccionadas. Se
utiliza una coma (",") para separar una ciudad y su temperatura, y un punto y coma (";"), para separar los datos de
cada ciudad. La cadena de entrada completa representa una coincidencia única. En el patrón de expresión regular
((\w+(\s\w+)*),(\d+);)+ , que se utiliza para analizar la cadena, se asigna el nombre de la ciudad al segundo
grupo de captura y la temperatura al cuarto grupo de captura.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "Miami,78;Chicago,62;New York,67;San Francisco,59;Seattle,58;";
string pattern = @"((\w+(\s\w+)*),(\d+);)+";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine("Current temperatures:");
for (int ctr = 0; ctr < match.Groups[2].Captures.Count; ctr++)
Console.WriteLine("{0,-20} {1,3}", match.Groups[2].Captures[ctr].Value,
match.Groups[4].Captures[ctr].Value);
}
}
}
// The example displays the following output:
// Current temperatures:
// Miami 78
// Chicago 62
// New York 67
// San Francisco 59
// Seattle 58

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "Miami,78;Chicago,62;New York,67;San Francisco,59;Seattle,58;"
Dim pattern As String = "((\w+(\s\w+)*),(\d+);)+"
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine("Current temperatures:")
For ctr As Integer = 0 To match.Groups(2).Captures.Count - 1
Console.WriteLine("{0,-20} {1,3}", match.Groups(2).Captures(ctr).Value, _
match.Groups(4).Captures(ctr).Value)
Next
End If
End Sub
End Module
' The example displays the following output:
' Current temperatures:
' Miami 78
' Chicago 62
' New York 67
' San Francisco 59
' Seattle 58

La expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\w+ Buscar coincidencias con uno o más caracteres alfabéticos.

(\s\w+)* Coincide con cero o más apariciones de un carácter de


espacio en blanco seguido de uno o varios caracteres que se
usan para formar palabras. Este patrón busca coincidencias
con nombres de ciudades de múltiples palabras. Éste es el
tercer grupo de captura.
MODELO DESCRIPCIÓN

(\w+(\s\w+)*) Coincide con uno o varios caracteres que se usan para formar
palabras seguidos de cero o más apariciones de un carácter
de espacio en blanco seguidos de uno o varios caracteres que
se usan para formar palabras. Este es el segundo grupo de
captura.

, Coincide con una coma.

(\d+) Buscar coincidencias con uno o más dígitos. Este es el cuarto


grupo de captura.

; Buscar coincidencias con un signo de punto y coma.

((\w+(\s\w+)*),(\d+);)+ Buscar coincidencias con el patrón de una palabra seguido de


cualquier palabra adicional seguida de una coma, uno o más
dígitos y un punto y coma, una o más veces. Este es el primer
grupo de captura.

Vea también
System.Text.RegularExpressions
Expresiones regulares de .NET
Lenguaje de expresiones regulares: referencia rápida
Detalles del comportamiento de expresiones
regulares
20/01/2020 • 31 minutes to read • Edit Online

El motor de expresiones regulares de .NET Framework es un buscador de coincidencias de expresiones regulares


con retroceso que incorpora un motor NFA (autómata finito no determinista) tradicional, como el que usa Perl,
Python, Emacs y Tcl. Esto lo distingue de los motores DFA (autómatas finitos deterministas) de expresiones
regulares puras, más rápidos pero más limitados, como los de awk, egrep o lex. Esto también lo distingue de los
NFA POSIX, estandarizados pero más lentos. En la sección siguiente se describen los tres tipos de motores de
expresiones regulares y se explica por qué las expresiones regulares de .NET Framework se implementan
mediante un motor NFA tradicional.

Ventajas del motor NFA


Cuando los motores DFA realizan una búsqueda de coincidencia de patrones, su orden de procesamiento está
controlado por la cadena de entrada. El motor empieza al principio de la cadena de entrada y continúa de forma
secuencial para determinar si el carácter siguiente coincide con el patrón de expresión regular. Pueden garantizar
una coincidencia con la cadena más larga posible. Dado que nunca prueban el mismo carácter dos veces, los
motores de búsqueda DFA no permiten el retroceso. Pero, como los motores de búsqueda DFA solo contienen
estados finitos, no pueden coincidir con un patrón con referencias inversas y, como no crean una expansión
explícita, no pueden capturar subexpresiones.
A diferencia de los motores DFA, cuando los motores NFA tradicionales realizan una búsqueda de coincidencia de
patrones, su orden de procesamiento está controlado por el patrón de expresión regular. Al procesar un elemento
del lenguaje determinado, el motor usa una búsqueda de coincidencia expansiva, es decir, coincide con la mayor
parte posible de la cadena de entrada. Pero también guarda su estado después de encontrar una coincidencia
correcta con una subexpresión. Si finalmente se produce un error en una coincidencia, el motor puede volver a un
estado guardado para buscar otras coincidencias. Este proceso de abandonar una coincidencia de subexpresión
correcta para que los elementos del lenguaje subsiguientes de la expresión regular también puedan coincidir se
conoce como retroceso. Los motores NFA usan el retroceso para probar todas las expansiones posibles de una
expresión regular en un orden específico y aceptan la primera coincidencia. Puesto que los motores NFA
tradicionales construyen una expansión específica de la expresión regular para encontrar una coincidencia
correcta, pueden capturar coincidencias de subexpresiones y referencias inversas coincidentes. Pero el hecho de
que los motores NFA tradicionales puedan retroceder les permite visitar el mismo estado varias veces si llegan al
estado a través de diferentes rutas de acceso. Como resultado, se pueden ejecutar de forma exponencialmente
lenta en el peor de los casos. Dado que los motores NFA tradicionales aceptan la primera coincidencia que
encuentran, puede darse que no descubran otras coincidencias (probablemente más largas).
Los motores NFA POSIX son como los motores NFA tradicionales, salvo que siguen retrocediendo hasta que
puedan garantizar que han encontrado la coincidencia más larga posible. Como resultado, un motor NFA POSIX
es más lento que un motor NFA tradicional, y cuando se usa un motor NFA POSIX, no se puede dar preferencia a
una coincidencia más corta frente a una más larga cambiando el orden de la búsqueda hacia atrás.
Los motores NFA tradicionales son muy populares entre los programadores porque ofrecen mayor control sobre
la coincidencia de cadenas que los motores de búsqueda DFA o NFA POSIX. Aunque, en el peor de los casos, se
pueden ejecutar con lentitud, se les puede dirigir para que busquen coincidencias en tiempo lineal o polinómico
mediante patrones que reduzcan las ambigüedades y limiten el retroceso. En otras palabras, aunque los motores
NFA sacrifican el rendimiento a favor de la eficacia y la flexibilidad, en la mayoría de los casos ofrecen un
rendimiento aceptable si una expresión regular está escrita correctamente y evitan los casos en los que el
retroceso degrada exponencialmente el rendimiento.

NOTE
Para obtener información sobre la reducción del rendimiento que causa un retroceso excesivo y sobre las maneras de crear
una expresión regular para solucionarlo, consulte Retroceso.

Funcionalidades del motor de .NET Framework


Para aprovechar las ventajas de un motor NFA tradicional, el motor de expresiones regulares de .NET Framework
incluye un conjunto completo de construcciones que permiten a los programadores dirigir el motor de retroceso.
Estas construcciones se pueden usar para buscar coincidencias con mayor rapidez o para dar preferencia a
determinadas expansiones frente a otras.
Otras características del motor de expresiones regulares de .NET Framework son las siguientes:
Cuantificadores diferidos: ?? , *? , +? , { n , m }? . Estas construcciones le indican al motor de retroceso
que busque primero el número mínimo de repeticiones. En cambio, los cuantificadores expansivos
normales intentan buscar primero el número máximo de repeticiones. En el siguiente ejemplo se ilustra la
diferencia entre ambos. Una expresión regular coincide con una oración que termina con un número, y hay
un grupo de capturas diseñado para extraer ese número. La expresión regular .+(\d+)\. incluye el
cuantificador expansivo .+ , lo que hace que el motor de expresiones regulares capture solo el último
dígito del número. En cambio, la expresión regular .+?(\d+)\. incluye el cuantificador diferido .+? , lo que
hace que el motor de expresiones regulares capture el número entero.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string greedyPattern = @".+(\d+)\.";
string lazyPattern = @".+?(\d+)\.";
string input = "This sentence ends with the number 107325.";
Match match;

// Match using greedy quantifier .+.


match = Regex.Match(input, greedyPattern);
if (match.Success)
Console.WriteLine("Number at end of sentence (greedy): {0}",
match.Groups[1].Value);
else
Console.WriteLine("{0} finds no match.", greedyPattern);

// Match using lazy quantifier .+?.


match = Regex.Match(input, lazyPattern);
if (match.Success)
Console.WriteLine("Number at end of sentence (lazy): {0}",
match.Groups[1].Value);
else
Console.WriteLine("{0} finds no match.", lazyPattern);
}
}
// The example displays the following output:
// Number at end of sentence (greedy): 5
// Number at end of sentence (lazy): 107325
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim greedyPattern As String = ".+(\d+)\."
Dim lazyPattern As String = ".+?(\d+)\."
Dim input As String = "This sentence ends with the number 107325."
Dim match As Match

' Match using greedy quantifier .+.


match = Regex.Match(input, greedyPattern)
If match.Success Then
Console.WriteLine("Number at end of sentence (greedy): {0}",
match.Groups(1).Value)
Else
Console.WriteLine("{0} finds no match.", greedyPattern)
End If

' Match using lazy quantifier .+?.


match = Regex.Match(input, lazyPattern)
If match.Success Then
Console.WriteLine("Number at end of sentence (lazy): {0}",
match.Groups(1).Value)
Else
Console.WriteLine("{0} finds no match.", lazyPattern)
End If
End Sub
End Module
' The example displays the following output:
' Number at end of sentence (greedy): 5
' Number at end of sentence (lazy): 107325

Las versiones expansiva y diferida de esta expresión regular se definen como se muestra en la tabla
siguiente:

MODELO DESCRIPCIÓN

.+ (cuantificador expansivo) Buscar al menos una repetición de cualquier carácter. Esto


hace que el motor de expresiones regulares busque una
coincidencia con la cadena completa y, después, retroceda
según sea necesario para coincidir con el resto del patrón.

.+? (cuantificador diferido) Coincide con al menos una repetición de cualquier


carácter, pero el menor número posible.

(\d+) Coincide con al menos un carácter numérico y lo asigna al


primer grupo de capturas.

\. Coincide con un punto.

Para más información sobre los cuantificadores diferidos, vea Cuantificadores.


Búsqueda anticipada positiva: (?= subexpresión ) . Esta característica permite que el motor de retroceso
vuelva a la misma posición en el texto después de encontrar una coincidencia con una subexpresión. Es útil
para buscar en todo el texto mediante la comprobación de varios patrones que empiezan en la misma
posición. Además, permite al motor comprobar que una subcadena existe al final de la coincidencia sin
incluir la subcadena en el texto coincidente. En el ejemplo siguiente se usa la búsqueda anticipada positiva
para extraer las palabras de una oración que no van seguidas de símbolos de puntuación.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b[A-Z]+\b(?=\P{P})";
string input = "If so, what comes next?";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// If
// what
// comes

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b[A-Z]+\b(?=\P{P})"
Dim input As String = "If so, what comes next?"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' If
' what
' comes

La expresión regular \b[A-Z]+\b(?=\P{P}) se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

[A-Z]+ Coincide con cualquier carácter alfabético una o más


veces. Como se llama al método Regex.Matches con la
opción RegexOptions.IgnoreCase, la comparación no
distingue mayúsculas de minúsculas.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

(?=\P{P}) Busca hacia delante para determinar si el siguiente


carácter es un signo de puntuación. Si no es así, se
produce la coincidencia.

Para obtener más información sobre las aserciones de búsqueda anticipada positiva, consulte
Construcciones de agrupamiento.
Búsqueda anticipada negativa: (?! subexpresión ) . Esta característica permite coincidir con una expresión
solo si no se produce una coincidencia con una subexpresión. Esto es especialmente eficaz para restringir
una búsqueda, ya que a menudo resulta más sencillo proporcionar una expresión para un caso que se debe
eliminar, en lugar de una expresión para los casos que se deben incluir. Por ejemplo, es difícil escribir una
expresión para buscar palabras que no comienzan por "non". En el ejemplo siguiente se usa la búsqueda
anticipada negativa para excluirlas.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = @"\b(?!non)\w+\b";
string input = "Nonsense is not always non-functional.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine(match.Value);
}
}
// The example displays the following output:
// is
// not
// always
// functional

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "\b(?!non)\w+\b"
Dim input As String = "Nonsense is not always non-functional."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine(match.Value)
Next
End Sub
End Module
' The example displays the following output:
' is
' not
' always
' functional

El patrón de expresión regular \b(?!non)\w+\b se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de


palabras.

(?!non) Buscar hacia delante para asegurarse de que la cadena


actual no empieza por "non". Si lo hace, se produce un
error de coincidencia.

(\w+) Buscar coincidencias con uno o más caracteres alfabéticos.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

Para obtener más información sobre las aserciones de búsqueda anticipada negativa, consulte
Construcciones de agrupamiento.
Evaluación condicional: (?( expresión ) sí | no ) y (?( nombre ) sí | no ) , donde expresión es una
subexpresión que debe coincidir, nombre es el nombre de un grupo de capturas, sí es la cadena que debe
coincidir si expresión coincide o nombre es un grupo capturado válido y no vacío, y no es la subexpresión
que debe coincidir si expresión no coincide o si nombre no es un grupo capturado válido y no vacío. Esta
característica permite al motor buscar mediante más de un patrón alternativo, según el resultado de una
búsqueda de coincidencia de subexpresión anterior o el resultado de una aserción de ancho cero. Esto
posibilita una forma más eficaz de referencia inversa que permite, por ejemplo, coincidir con una
subexpresión en función de si se produjo una coincidiencia con una subexpresión anterior. La expresión
regular del ejemplo siguiente coincide con párrafos que están pensados tanto para un uso público como
interno. Los párrafos destinados únicamente al uso interno empiezan con una etiqueta <PRIVATE> . El
patrón de expresión regular ^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ usa la
evaluación condicional para asignar el contenido de los párrafos pensados para el uso público y para el uso
interno a grupos de capturas independientes. Después, estos párrafos se pueden tratar de forma diferente.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "<PRIVATE> This is not for public consumption." + Environment.NewLine +
"But this is for public consumption." + Environment.NewLine +
"<PRIVATE> Again, this is confidential.\n";
string pattern = @"^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$";
string publicDocument = null, privateDocument = null;

foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))


{
if (match.Groups[1].Success) {
privateDocument += match.Groups[1].Value + "\n";
}
else {
publicDocument += match.Groups[3].Value + "\n";
privateDocument += match.Groups[3].Value + "\n";
}
}

Console.WriteLine("Private Document:");
Console.WriteLine(privateDocument);
Console.WriteLine("Public Document:");
Console.WriteLine(publicDocument);
}
}
// The example displays the following output:
// Private Document:
// This is not for public consumption.
// But this is for public consumption.
// Again, this is confidential.
//
// Public Document:
// But this is for public consumption.
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "<PRIVATE> This is not for public consumption." + vbCrLf + _
"But this is for public consumption." + vbCrLf + _
"<PRIVATE> Again, this is confidential." + vbCrLf
Dim pattern As String = "^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$"
Dim publicDocument As String = Nothing
Dim privateDocument As String = Nothing

For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)


If match.Groups(1).Success Then
privateDocument += match.Groups(1).Value + vbCrLf
Else
publicDocument += match.Groups(3).Value + vbCrLf
privateDocument += match.Groups(3).Value + vbCrLf
End If
Next

Console.WriteLine("Private Document:")
Console.WriteLine(privateDocument)
Console.WriteLine("Public Document:")
Console.WriteLine(publicDocument)
End Sub
End Module
' The example displays the following output:
' Private Document:
' This is not for public consumption.
' But this is for public consumption.
' Again, this is confidential.
'
' Public Document:
' But this is for public consumption.

El patrón de expresión regular se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Inicia la búsqueda de coincidencias al principio de una


línea.

(?<Pvt>\<PRIVATE\>\s)? Coincide con cero o una repetición de la cadena


<PRIVATE> seguida de un carácter de espacio en blanco.
Asigna la coincidencia a un grupo de capturas
denominado Pvt .

(?(Pvt)((\w+\p{P}?\s)+) Si existe el grupo de capturas Pvt , coincide con una o


más repeticiones de uno o más caracteres de palabra
seguidos de cero o un separador de puntuación, seguido
de un carácter de espacio en blanco. Asigna la subcadena
al primer grupo de capturas.

|((\w+\p{P}?\s)+)) Si no existe el grupo de capturas Pvt , coincide con una o


más repeticiones de uno o más caracteres de palabra
seguidos de cero o un separador de puntuación, seguido
de un carácter de espacio en blanco. Asigna la subcadena
al tercer grupo de capturas.

\r?$ Coincide con el final de una línea o con el final de la


cadena.
Para obtener más información sobre la evaluación condicional, consulte Construcciones de alternancia.
Definiciones de grupos de equilibrio: (?< nombre1 - nombre2 > subexpresión ) . Esta característica
permite al motor de expresiones regulares realizar un seguimiento de construcciones anidadas como
paréntesis o corchetes de apertura y cierre. Para ver un ejemplo, consulte Construcciones de agrupamiento.
Subexpresiones sin retroceso (denominadas también subexpresiones expansivas): (?> subexpresión ) .
Esta característica permite al motor de retroceso garantizar que una subexpresión coincida solo con la
primera coincidencia encontrada para dicha subexpresión, como si la expresión se ejecutara
independientemente de la expresión que la contiene. Si no usa esta construcción, el retroceso en las
búsquedas en la expresión más grande puede cambiar el comportamiento de una subexpresión. Por
ejemplo, la expresión regular (a+)\w coincide con uno o más caracteres "a", junto con un carácter de
palabra que sigue a la secuencia de caracteres "a", y asigna la secuencia de caracteres "a" al primer grupo
de capturas. Pero si el último carácter de la cadena de entrada es también una "a", coincide con el elemento
del lenguaje \w y no se incluye en el grupo capturado.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "aaaaa", "aaaaab" };
string backtrackingPattern = @"(a+)\w";
Match match;

foreach (string input in inputs) {


Console.WriteLine("Input: {0}", input);
match = Regex.Match(input, backtrackingPattern);
Console.WriteLine(" Pattern: {0}", backtrackingPattern);
if (match.Success) {
Console.WriteLine(" Match: {0}", match.Value);
Console.WriteLine(" Group 1: {0}", match.Groups[1].Value);
}
else {
Console.WriteLine(" Match failed.");
}
}
Console.WriteLine();
}
}
// The example displays the following output:
// Input: aaaaa
// Pattern: (a+)\w
// Match: aaaaa
// Group 1: aaaa
// Input: aaaaab
// Pattern: (a+)\w
// Match: aaaaab
// Group 1: aaaaa
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "aaaaa", "aaaaab" }
Dim backtrackingPattern As String = "(a+)\w"
Dim match As Match

For Each input As String In inputs


Console.WriteLine("Input: {0}", input)
match = Regex.Match(input, backtrackingPattern)
Console.WriteLine(" Pattern: {0}", backtrackingPattern)
If match.Success Then
Console.WriteLine(" Match: {0}", match.Value)
Console.WriteLine(" Group 1: {0}", match.Groups(1).Value)
Else
Console.WriteLine(" Match failed.")
End If
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' Input: aaaaa
' Pattern: (a+)\w
' Match: aaaaa
' Group 1: aaaa
' Input: aaaaab
' Pattern: (a+)\w
' Match: aaaaab
' Group 1: aaaaa

La expresión regular ((?>a+))\w impide este comportamiento. Dado que todos los caracteres "a"
consecutivos se buscan sin retroceso, el primer grupo de capturas incluye todos los caracteres "a"
consecutivos. Si los caracteres "a" no van seguidos de al menos otro carácter que no sea "a", se produce un
error de coincidencia.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "aaaaa", "aaaaab" };
string nonbacktrackingPattern = @"((?>a+))\w";
Match match;

foreach (string input in inputs) {


Console.WriteLine("Input: {0}", input);
match = Regex.Match(input, nonbacktrackingPattern);
Console.WriteLine(" Pattern: {0}", nonbacktrackingPattern);
if (match.Success) {
Console.WriteLine(" Match: {0}", match.Value);
Console.WriteLine(" Group 1: {0}", match.Groups[1].Value);
}
else {
Console.WriteLine(" Match failed.");
}
}
Console.WriteLine();
}
}
// The example displays the following output:
// Input: aaaaa
// Pattern: ((?>a+))\w
// Match failed.
// Input: aaaaab
// Pattern: ((?>a+))\w
// Match: aaaaab
// Group 1: aaaaa

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "aaaaa", "aaaaab" }
Dim nonbacktrackingPattern As String = "((?>a+))\w"
Dim match As Match

For Each input As String In inputs


Console.WriteLine("Input: {0}", input)
match = Regex.Match(input, nonbacktrackingPattern)
Console.WriteLine(" Pattern: {0}", nonbacktrackingPattern)
If match.Success Then
Console.WriteLine(" Match: {0}", match.Value)
Console.WriteLine(" Group 1: {0}", match.Groups(1).Value)
Else
Console.WriteLine(" Match failed.")
End If
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' Input: aaaaa
' Pattern: ((?>a+))\w
' Match failed.
' Input: aaaaab
' Pattern: ((?>a+))\w
' Match: aaaaab
' Group 1: aaaaa
Para obtener más información sobre las subexpresiones sin retroceso, consulte Construcciones de
agrupamiento.
La búsqueda de coincidencias de derecha a izquierda se especifica al proporcionar la opción
RegexOptions.RightToLeft a un constructor de clase Regex o a un método coincidente de instancia estática.
Esta característica es útil al realizar búsquedas de derecha a izquierda en lugar de izquierda a derecha, o en
los casos en los que es más eficaz iniciar una búsqueda de coincidencias en la parte derecha del patrón, en
lugar de la izquierda. Como se muestra en el ejemplo siguiente, el uso de la búsqueda de coincidencias de
derecha a izquierda puede cambiar el comportamiento de los cuantificadores expansivos. En el ejemplo se
realizan dos búsquedas de una oración que termina con un número. La búsqueda de izquierda a derecha
que usa el cuantificador expansivo + coincide con uno de los seis dígitos de la oración, mientras que la
búsqueda de derecha a izquierda coincide con los seis dígitos. Para ver una descripción del patrón de
expresión regular, consulte el ejemplo que ilustra los cuantificadores diferidos anteriormente en esta
sección.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string greedyPattern = @".+(\d+)\.";
string input = "This sentence ends with the number 107325.";
Match match;

// Match from left-to-right using lazy quantifier .+?.


match = Regex.Match(input, greedyPattern);
if (match.Success)
Console.WriteLine("Number at end of sentence (left-to-right): {0}",
match.Groups[1].Value);
else
Console.WriteLine("{0} finds no match.", greedyPattern);

// Match from right-to-left using greedy quantifier .+.


match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft);
if (match.Success)
Console.WriteLine("Number at end of sentence (right-to-left): {0}",
match.Groups[1].Value);
else
Console.WriteLine("{0} finds no match.", greedyPattern);
}
}
// The example displays the following output:
// Number at end of sentence (left-to-right): 5
// Number at end of sentence (right-to-left): 107325
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim greedyPattern As String = ".+(\d+)\."
Dim input As String = "This sentence ends with the number 107325."
Dim match As Match

' Match from left-to-right using lazy quantifier .+?.


match = Regex.Match(input, greedyPattern)
If match.Success Then
Console.WriteLine("Number at end of sentence (left-to-right): {0}",
match.Groups(1).Value)
Else
Console.WriteLine("{0} finds no match.", greedyPattern)
End If

' Match from right-to-left using greedy quantifier .+.


match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft)
If match.Success Then
Console.WriteLine("Number at end of sentence (right-to-left): {0}",
match.Groups(1).Value)
Else
Console.WriteLine("{0} finds no match.", greedyPattern)
End If
End Sub
End Module
' The example displays the following output:
' Number at end of sentence (left-to-right): 5
' Number at end of sentence (right-to-left): 107325

Para obtener más información sobre la búsqueda de coincidencias de derecha a izquierda, consulte
Opciones de expresiones regulares.
Búsqueda tardía positiva y negativa: (?<= subexpresión ) para la búsqueda tardía positiva y (?<!
subexpresión ) para la búsqueda tardía negativa. Esta característica es parecida a la búsqueda anticipada,
que se describe anteriormente en este tema. Dado que el motor de expresiones regulares permite una
búsqueda de coincidencias completa de derecha a izquierda, las expresiones regulares permiten búsquedas
tardías sin restricciones. La búsqueda tardía positiva y negativa también se puede usar para evitar anidar
los cuantificadores cuando la subexpresión anidada es un superconjunto de una expresión exterior. Las
expresiones regulares con cuantificadores anidados suelen ofrecer un rendimiento bajo. Por ejemplo, en el
ejemplo siguiente se comprueba que una cadena empieza y acaba con un carácter alfanumérico y que
cualquier otro carácter de la cadena es de un subconjunto más grande. Forma parte de la expresión regular
usada para validar direcciones de correo electrónico. Para obtener más información, vea Procedimiento:
Comprobación de que las cadenas están en un formato de correo electrónico válido.
using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string[] inputs = { "jack.sprat", "dog#", "dog#1", "me.myself",
"me.myself!" };
string pattern = @"^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$";
foreach (string input in inputs) {
if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("{0}: Valid", input);
else
Console.WriteLine("{0}: Invalid", input);
}
}
}
// The example displays the following output:
// jack.sprat: Valid
// dog#: Invalid
// dog#1: Valid
// me.myself: Valid
// me.myself!: Invalid

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim inputs() As String = { "jack.sprat", "dog#", "dog#1", "me.myself",
"me.myself!" }
Dim pattern As String = "^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$"
For Each input As String In inputs
If Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase) Then
Console.WriteLine("{0}: Valid", input)
Else
Console.WriteLine("{0}: Invalid", input)
End If
Next
End Sub
End Module
' The example displays the following output:
' jack.sprat: Valid
' dog#: Invalid
' dog#1: Valid
' me.myself: Valid
' me.myself!: Invalid

La expresión regular ^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$ se define como se muestra en la


tabla siguiente.

MODELO DESCRIPCIÓN

^ Empieza la búsqueda de coincidencias en el principio de la


cadena.

[A-Z0-9] Coincide con cualquier carácter numérico o alfanumérico.


(La comparación no distingue mayúsculas de minúsculas).
MODELO DESCRIPCIÓN

([-!#$%&'.*+/=?^`{}|~\w])* Coincide con cero o más repeticiones de cualquier carácter


de palabra o de cualquiera de los caracteres siguientes: -,
!, #, $, %, &, ', ., *, +, /, =, ?, ^, `, {, }, | o ~.

(?<=[A-Z0-9]) Realiza una búsqueda tardía en el carácter anterior, que


debe ser numérico o alfanumérico. (La comparación no
distingue mayúsculas de minúsculas).

$ Finalizar la búsqueda al final de la cadena.

Para obtener más información sobre la búsqueda tardía positiva y negativa, consulte Construcciones de
agrupamiento.

Artículos relacionados
TITLE DESCRIPCIÓN

Retroceso Proporciona información sobre la manera en que el retroceso


de expresiones regulares se bifurca para buscar coincidencias
alternativas.

Compilar y reutilizar Proporciona información sobre cómo compilar y reutilizar


expresiones regulares para aumentar el rendimiento.

Seguridad para subprocesos Proporciona información sobre la seguridad para subprocesos


de expresiones regulares y explica cuándo se debe sincronizar
el acceso a objetos de expresión regular.

Expresiones regulares de .NET Framework Proporciona información general sobre el aspecto del lenguaje
de programación de expresiones regulares.

Modelo de objetos de expresión regular Proporciona información y ejemplos de código que muestran
cómo usar las clases de expresiones regulares.

Ejemplos de expresiones regulares Contiene ejemplos de código que muestran el uso de


expresiones regulares en aplicaciones comunes.

Lenguaje de expresiones regulares: referencia rápida Ofrece información sobre el conjunto de caracteres,
operadores y construcciones que se pueden usar para definir
expresiones regulares.

Referencia
System.Text.RegularExpressions
Retroceso en expresiones regulares
23/01/2020 • 36 minutes to read • Edit Online

El retroceso se produce cuando un patrón de expresión regular contiene cuantificadores o construcciones de


alternancia opcionales y el motor de expresiones regulares vuelve a un estado guardado anterior para continuar
la búsqueda de una coincidencia. El retroceso es fundamental para la eficacia de las expresiones regulares;
permite que las expresiones sean eficaces y flexibles, y que coincidan con modelos muy complejos. Al mismo
tiempo, esta eficacia tiene un costo. El retroceso suele ser el factor único más importante que afecta al
rendimiento del motor de expresiones regulares. Afortunadamente, el desarrollador tiene control sobre el
comportamiento del motor de expresiones regulares y cómo usa el retroceso. En este tema se explica cómo
funciona el retroceso y cómo se puede controlar.

NOTE
En general, un motor NFA (autómata finito no determinista), como el motor de expresiones regulares de .NET, se encarga
de crear expresiones regulares eficaces y rápidas para el desarrollador.

Comparación lineal sin retroceso


Si un patrón de expresión regular no tiene ningún cuantificador o construcción de alternancia opcional, el motor
de expresiones regulares se ejecuta en tiempo lineal. Es decir, una vez que el motor de expresiones regulares
hace coincidir el primer elemento de lenguaje del patrón con texto de la cadena de entrada, intenta buscar una
coincidencia del siguiente elemento de lenguaje del patrón con el siguiente carácter o grupo de caracteres de la
cadena de entrada. Este proceso continúa hasta que la coincidencia se realiza correctamente o se produce un
error. En cualquier caso, el motor de expresiones regulares avanza de carácter en carácter por la cadena de
entrada.
Esto se muestra en el ejemplo siguiente. La expresión regular e{2}\w\b busca dos apariciones de la letra "e"
seguida de cualquier carácter alfabético seguido de un límite de palabras.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "needing a reed";
string pattern = @"e{2}\w\b";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("{0} found at position {1}",
match.Value, match.Index);
}
}
// The example displays the following output:
// eed found at position 11
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "needing a reed"
Dim pattern As String = "e{2}\w\b"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("{0} found at position {1}", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' eed found at position 11

Aunque esta expresión regular incluye el cuantificador {2} , se evalúa de manera lineal. El motor de
expresiones regulares no retrocede porque {2} no es un cuantificador opcional, ya que especifica un número
exacto y no un número variable de veces que la subexpresión anterior debe coincidir. Como resultado, el motor
de expresiones regulares intenta hacer coincidir el patrón de expresión regular con la cadena de entrada como
se muestra en la tabla siguiente.

OPERACIÓN POSICIÓN EN EL PATRÓN POSICIÓN EN LA CADENA RESULTADO

1 h "needing a reed" (índice 0) Ninguna coincidencia.

2 h "eeding a reed" (índice 1) Posible coincidencia.

3 e{2} "eding a reed" (índice 2) Posible coincidencia.

4 \w "ding a reed" (índice 3) Posible coincidencia.

5 \b "ing a reed" (índice 4) Error en posible


coincidencia.

6 h "eding a reed" (índice 2) Posible coincidencia.

7 e{2} "ding a reed" (índice 3) Error en posible


coincidencia.

8 h "ding a reed" (índice 3) Se produce un error de


coincidencia.

9 h "ing a reed" (índice 4) Ninguna coincidencia.

10 h "ng a reed" (índice 5) Ninguna coincidencia.

11 h "g a reed" (índice 6) Ninguna coincidencia.

12 h " a reed" (índice 7) Ninguna coincidencia.

13 h “a reed” (índice 8) Ninguna coincidencia.

14 h " reed" (índice 9) Ninguna coincidencia.

15 h “reed” (índice 10) Ninguna coincidencia


OPERACIÓN POSICIÓN EN EL PATRÓN POSICIÓN EN LA CADENA RESULTADO

16 h "eed" (índice 11) Posible coincidencia.

17 e{2} "ed" (índice 12) Posible coincidencia.

18 \w "d" (índice 13) Posible coincidencia.

19 \b "" (índice 14) Coincidencia.

Si un patrón de expresión regular no incluye ningún cuantificador o construcción de alternancia opcional, el


número máximo de comparaciones necesarias para hacer coincidir el patrón de expresión regular con la cadena
de entrada es aproximadamente equivalente al número de caracteres de la cadena de entrada. En este caso, el
motor de expresiones regulares usa 19 comparaciones para identificar posibles coincidencias en esta cadena de
13 caracteres. Es decir, el motor de expresiones regulares se ejecuta en tiempo prácticamente lineal si no
contiene ningún cuantificador o construcción de alternancia opcional.

Retroceso con cuantificadores o construcciones de alternancia


opcionales
Cuando una expresión regular incluye cuantificadores o construcciones de alternancia opcionales, la evaluación
de la cadena de entrada ya no es lineal. La coincidencia de modelos con un motor NFA está controlada por los
elementos de lenguaje de la expresión regular y no por los caracteres que se hacen coincidir en la cadena de
entrada. Por tanto, el motor de expresiones regulares intenta hacer coincidir totalmente subexpresiones
opcionales o alternativas. Cuando avanza al elemento de lenguaje siguiente de la subexpresión y la coincidencia
no se realiza correctamente, el motor de expresiones regulares puede abandonar una parte de su coincidencia
correcta y volver a un estado guardado anterior para hacer coincidir la expresión regular en su conjunto con la
cadena de entrada. Este proceso de volver a un estado guardado anterior para encontrar una coincidencia se
denomina retroceso.
Por ejemplo, considere el patrón de expresión regular .*(es) , que hace coincidir los caracteres "es" y todos los
caracteres que lo preceden. Como se muestra en el ejemplo siguiente, si la cadena de entrada es "Essential
services are provided by regular expressions.", el patrón coincide con toda la cadena hasta e incluyendo "es" en
"expressions".

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "Essential services are provided by regular expressions.";
string pattern = ".*(es)";
Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
if (m.Success) {
Console.WriteLine("'{0}' found at position {1}",
m.Value, m.Index);
Console.WriteLine("'es' found at position {0}",
m.Groups[1].Index);
}
}
}
// 'Essential services are provided by regular expres' found at position 0
// 'es' found at position 47
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "Essential services are provided by regular expressions."
Dim pattern As String = ".*(es)"
Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
If m.Success Then
Console.WriteLine("'{0}' found at position {1}", _
m.Value, m.Index)
Console.WriteLine("'es' found at position {0}", _
m.Groups(1).Index)
End If
End Sub
End Module
' 'Essential services are provided by regular expres' found at position 0
' 'es' found at position 47

Para ello, el motor de expresiones regulares usa el retroceso de la manera siguiente:


Coincide con .* (que coincide con cero, una o más apariciones de cualquier carácter) con la cadena de
entrada completa.
Intenta hacer coincidir "e" en el patrón de expresión regular. Sin embargo, la cadena de entrada no tiene
ningún carácter restante disponible para coincidir.
Retrocede hasta su última coincidencia correcta, "Essential services are provided by regular expressions",
e intenta hacer coincidir "e" con el punto del final de la frase. Se produce un error de coincidencia.
Sigue retrocediendo hasta una coincidencia correcta anterior, de carácter en carácter, hasta que la
subcadena coincidente tentativa sea "Essential services are provided by regular expr". A continuación,
compara la "e" del patrón con la segunda "e" de "expressions" y encuentra una coincidencia.
Compara la "s" del patrón con la "s" que sigue al carácter "e" coincidente (la primera "s" de "expressions").
La coincidencia es correcta.
Cuando se usa retroceso, la coincidencia del patrón de expresión regular con la cadena de entrada, que tiene 55
caracteres de longitud, necesita 67 operaciones de comparación. Normalmente, si un patrón de expresión
regular tiene una única construcción de alternancia o un único cuantificador opcional, el número de operaciones
de comparación necesarias para que coincida con el patrón es más del doble del número de caracteres de la
cadena de entrada.

Retroceso con cuantificadores opcionales anidados


El número de operaciones de comparación necesarias para coincidir con un patrón de expresión regular puede
aumentar exponencial si el patrón incluye muchas construcciones de alternancia, si incluye construcciones de
alternancia anidadas o, lo que es más frecuente, si incluye cuantificadores opcionales anidados. Por ejemplo, el
patrón de expresión regular ^(a+)+$ está diseñado para coincidir con una cadena completa que contiene uno o
más caracteres "a". El ejemplo proporciona dos cadenas de entrada de longitud idéntica, pero solo la primera
cadena coincide con el patrón. La clase System.Diagnostics.Stopwatch se usa para determinar cuánto tiempo
tarda la operación de coincidencia.
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string pattern = "^(a+)+$";
string[] inputs = { "aaaaaa", "aaaaa!" };
Regex rgx = new Regex(pattern);
Stopwatch sw;

foreach (string input in inputs) {


sw = Stopwatch.StartNew();
Match match = rgx.Match(input);
sw.Stop();
if (match.Success)
Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed);
else
Console.WriteLine("No match found in {0}", sw.Elapsed);
}
}
}

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim pattern As String = "^(a+)+$"
Dim inputs() As String = { "aaaaaa", "aaaaa!" }
Dim rgx As New Regex(pattern)
Dim sw As Stopwatch

For Each input As String In inputs


sw = Stopwatch.StartNew()
Dim match As Match = rgx.Match(input)
sw.Stop()
If match.Success Then
Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed)
Else
Console.WriteLine("No match found in {0}", sw.Elapsed)
End If
Next
End Sub
End Module

Como muestra el resultado del ejemplo, el motor de expresiones regulares tardó en descubrir que una cadena
de entrada no coincidía con el patrón aproximadamente el doble que en identificar una cadena coincidente. Esto
se debe a que una coincidencia infructuosa siempre representa un escenario de caso peor. El motor de
expresiones regulares debe usar la expresión regular para seguir todas las rutas posibles a través de los datos
antes de poder concluir que la coincidencia no es correcta y los paréntesis anidados crean muchas rutas de
acceso adicionales a través de los datos. El motor de expresiones regulares concluye que la segunda cadena no
coincide con el patrón; para ello, hace lo siguiente:
Comprueba que está al principio de la cadena y, a continuación, busca una coincidencia de los cinco
primeros caracteres de la cadena con el patrón a+ . A continuación, determina que no hay ningún grupo
adicional de caracteres "a" en la cadena. Por último, comprueba que está al final de la cadena. Como en la
cadena queda un carácter adicional, la coincidencia produce un error. Esta coincidencia errónea necesita 9
comparaciones. El motor de expresiones regulares también guarda información de estado de las
coincidencias de "a" (que llamaremos coincidencia 1), "aa" (coincidencia 2), "aaa" (coincidencia 3) y "aaaa"
(coincidencia 4).
Vuelve a la coincidencia 4 guardada previamente. Determina que hay un carácter "a" adicional para
asignar a un grupo capturado adicional. Por último, comprueba que está al final de la cadena. Como en la
cadena queda un carácter adicional, la coincidencia produce un error. Esta coincidencia errónea necesita 4
comparaciones. Hasta ahora, se han realizado un total de 13 comparaciones.
Vuelve a la coincidencia 3 guardada previamente. Determina que hay dos caracteres "a" adicionales para
asignar a un grupo capturado adicional. Sin embargo, se produce un error en la prueba de fin de cadena.
Vuelva a la coincidencia 3 e intenta hacer coincidir los dos caracteres "a" adicionales en dos grupos
capturados adicionales. Se sigue produciendo un error en la prueba de fin de cadena. Estas coincidencias
con error necesitan 12 comparaciones. Hasta ahora, se ha realizado un total de 25 comparaciones.
La comparación de la cadena de entrada con la expresión regular continúa de esta manera hasta que el motor
de expresiones regulares ha intentado todas las posibles combinaciones de coincidencias y, a continuación,
concluye que no hay ninguna coincidencia. Debido a los cuantificadores anidados, esta comparación es O (2n ) o
una operación exponencial, donde n es el número de caracteres de la cadena de entrada. Esto significa que, en el
peor de los casos, una cadena de entrada de 30 caracteres necesita aproximadamente 1.073.741.824
comparaciones y una cadena de entrada de 40 caracteres necesita aproximadamente 1.099.511.627.776
comparaciones. Si usa cadenas de estas longitudes o incluso mayores, los métodos de expresión regular pueden
tardar mucho tiempo en completarse cuando procesan datos de entrada que no coinciden con el patrón de
expresión regular.

Controlar el retroceso
El retroceso permite crear expresiones regulares eficaces y flexibles. Sin embargo, como se ha mostrado en la
sección anterior, estas ventajas pueden conllevar un bajo rendimiento inaceptable. Para evitar el retroceso
excesivo, se debe definir un intervalo de tiempo de espera cuando se instancie un objeto Regex o se llame a un
método estático de coincidencia de expresión regular. Esta técnica se analiza en la sección siguiente. Además,
.NET admite tres elementos del lenguaje de expresiones regulares que limitan o suprimen el retroceso y que
admiten expresiones regulares complejas con poca o ninguna reducción del rendimiento: subexpresiones sin
retroceso, aserciones de búsqueda tardía y aserciones de búsqueda anticipada. Para obtener más información
sobre cada elemento del lenguaje, vea Construcciones de agrupamiento.
Definición de un intervalo de tiempo de espera
A partir de .NET Framework 4.5, se puede establecer un valor de tiempo de espera que representa el intervalo
más largo en el que el motor de expresión regular buscará una coincidencia única antes de abandonar el intento
y generar una excepción RegexMatchTimeoutException. El intervalo de tiempo de espera se especifica al
proporcionar un valor TimeSpan al constructor Regex.Regex(String, RegexOptions, TimeSpan) para las
expresiones regulares de instancias. Además, cada método estático de coincidencia de patrones tiene una
sobrecarga con un parámetro TimeSpan que permite especificar un valor de tiempo de espera. De forma
predeterminada, el intervalo de tiempo de espera se establece en Regex.InfiniteMatchTimeout y el motor de
expresiones regulares no agota dicho tiempo.

IMPORTANT
Recomendamos que se establezca siempre un intervalo de tiempo de espera si la expresión regular se basa en el
retroceso.

Una excepción RegexMatchTimeoutException indica que el motor de expresiones regulares no pudo encontrar
una coincidencia en el intervalo de tiempo de espera especificado, pero no indica por qué se produjo la
excepción. La razón puede ser un retroceso excesivo, aunque también es posible que el intervalo de tiempo de
espera establecido fuera demasiado bajo, dada la carga del sistema en el momento en que se produjo la
excepción. Cuando se controla la excepción, se puede elegir entre abandonar otras coincidencias con la cadena
de entrada o incrementar el intervalo de tiempo de espera y reintentar la operación de coincidencia.
Por ejemplo, el código siguiente llama al constructor Regex.Regex(String, RegexOptions, TimeSpan) para crear
instancias de un objeto Regex con un valor de tiempo de espera de un segundo. El patrón de expresión regular
(a+)+$ , que coincide con una o más secuencias de uno o varios caracteres "a" al final de una línea, está sujeto a
un retroceso excesivo. Si se produce una excepción RegexMatchTimeoutException , el ejemplo incrementa el
valor de tiempo de espera hasta un intervalo máximo de tres segundos. Después, abandona el intento de
coincidir con el patrón.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.Text.RegularExpressions;
using System.Threading;

public class Example


{
const int MaxTimeoutInSeconds = 3;

public static void Main()


{
string pattern = @"(a+)+$"; // DO NOT REUSE THIS PATTERN.
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));
Stopwatch sw = null;

string[] inputs= { "aa", "aaaa>",


"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaa>",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>" };

foreach (var inputValue in inputs) {


Console.WriteLine("Processing {0}", inputValue);
bool timedOut = false;
do {
try {
sw = Stopwatch.StartNew();
// Display the result.
if (rgx.IsMatch(inputValue)) {
sw.Stop();
Console.WriteLine(@"Valid: '{0}' ({1:ss\.fffffff} seconds)",
inputValue, sw.Elapsed);
}
else {
sw.Stop();
Console.WriteLine(@"'{0}' is not a valid string. ({1:ss\.fffff} seconds)",
inputValue, sw.Elapsed);
}
}
catch (RegexMatchTimeoutException e) {
sw.Stop();
// Display the elapsed time until the exception.
Console.WriteLine(@"Timeout with '{0}' after {1:ss\.fffff}",
inputValue, sw.Elapsed);
Thread.Sleep(1500); // Pause for 1.5 seconds.

// Increase the timeout interval and retry.


TimeSpan timeout = e.MatchTimeout.Add(TimeSpan.FromSeconds(1));
if (timeout.TotalSeconds > MaxTimeoutInSeconds) {
Console.WriteLine("Maximum timeout interval of {0} seconds exceeded.",
MaxTimeoutInSeconds);
timedOut = false;
}
else {
Console.WriteLine("Changing the timeout interval to {0}",
Console.WriteLine("Changing the timeout interval to {0}",
timeout);
rgx = new Regex(pattern, RegexOptions.IgnoreCase, timeout);
timedOut = true;
}
}
} while (timedOut);
Console.WriteLine();
}
}
}
// The example displays output like the following :
// Processing aa
// Valid: 'aa' (00.0000779 seconds)
//
// Processing aaaa>
// 'aaaa>' is not a valid string. (00.00005 seconds)
//
// Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// Valid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (00.0000043 seconds)
//
// Processing aaaaaaaaaaaaaaaaaaaaaa>
// Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 01.00469
// Changing the timeout interval to 00:00:02
// Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 02.01202
// Changing the timeout interval to 00:00:03
// Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 03.01043
// Maximum timeout interval of 3 seconds exceeded.
//
// Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
// Timeout with 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>' after 03.01018
// Maximum timeout interval of 3 seconds exceeded.

Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Security
Imports System.Text.RegularExpressions
Imports System.Threading

Module Example
Const MaxTimeoutInSeconds As Integer = 3

Public Sub Main()


Dim pattern As String = "(a+)+$" ' DO NOT REUSE THIS PATTERN.
Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1))
Dim sw As Stopwatch = Nothing

Dim inputs() As String = { "aa", "aaaa>",


"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaa>",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>" }

For Each inputValue In inputs


Console.WriteLine("Processing {0}", inputValue)
Dim timedOut As Boolean = False
Do
Try
sw = Stopwatch.StartNew()
' Display the result.
If rgx.IsMatch(inputValue) Then
sw.Stop()
Console.WriteLine("Valid: '{0}' ({1:ss\.fffffff} seconds)",
inputValue, sw.Elapsed)
Else
sw.Stop()
Console.WriteLine("'{0}' is not a valid string. ({1:ss\.fffff} seconds)",
inputValue, sw.Elapsed)
End If
End If
Catch e As RegexMatchTimeoutException
sw.Stop()
' Display the elapsed time until the exception.
Console.WriteLine("Timeout with '{0}' after {1:ss\.fffff}",
inputValue, sw.Elapsed)
Thread.Sleep(1500) ' Pause for 1.5 seconds.

' Increase the timeout interval and retry.


Dim timeout As TimeSpan = e.MatchTimeout.Add(TimeSpan.FromSeconds(1))
If timeout.TotalSeconds > MaxTimeoutInSeconds Then
Console.WriteLine("Maximum timeout interval of {0} seconds exceeded.",
MaxTimeoutInSeconds)
timedOut = False
Else
Console.WriteLine("Changing the timeout interval to {0}",
timeout)
rgx = New Regex(pattern, RegexOptions.IgnoreCase, timeout)
timedOut = True
End If
End Try
Loop While timedOut
Console.WriteLine()
Next
End Sub
End Module
' The example displays output like the following:
' Processing aa
' Valid: 'aa' (00.0000779 seconds)
'
' Processing aaaa>
' 'aaaa>' is not a valid string. (00.00005 seconds)
'
' Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
' Valid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (00.0000043 seconds)
'
' Processing aaaaaaaaaaaaaaaaaaaaaa>
' Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 01.00469
' Changing the timeout interval to 00:00:02
' Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 02.01202
' Changing the timeout interval to 00:00:03
' Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 03.01043
' Maximum timeout interval of 3 seconds exceeded.
'
' Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
' Timeout with 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>' after 03.01018
' Maximum timeout interval of 3 seconds exceeded.

Subexpresión sin retroceso


El elemento de lenguaje (?> subexpression ) suprime el retroceso en una subexpresión. Es útil para evitar los
problemas de rendimiento asociados a las coincidencias con error.
En el ejemplo siguiente se muestra cómo la supresión del retroceso mejora el rendimiento cuando se usan
cuantificadores anidados. Mide el tiempo necesario para que el motor de expresiones regulares determine que
una cadena de entrada no coincide con dos expresiones regulares. La primera expresión regular usa el retroceso
para intentar buscar una coincidencia de una cadena que contiene una o más apariciones de uno o más dígitos
hexadecimales, seguidas de un signo de dos puntos, seguido de uno o más dígitos hexadecimales, seguido de
dos signos de dos puntos. La segunda expresión regular es idéntica a la primera, salvo que deshabilita el
retroceso. Como muestra el resultado del ejemplo, la mejora de rendimiento que supone deshabilitar el
retroceso es significativa.
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:";
bool matched;
Stopwatch sw;

Console.WriteLine("With backtracking:");
string backPattern = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$";
sw = Stopwatch.StartNew();
matched = Regex.IsMatch(input, backPattern);
sw.Stop();
Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed);
Console.WriteLine();

Console.WriteLine("Without backtracking:");
string noBackPattern = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$";
sw = Stopwatch.StartNew();
matched = Regex.IsMatch(input, noBackPattern);
sw.Stop();
Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed);
}
}
// The example displays output like the following:
// With backtracking:
// Match: False in 00:00:27.4282019
//
// Without backtracking:
// Match: False in 00:00:00.0001391
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:"
Dim matched As Boolean
Dim sw As Stopwatch

Console.WriteLine("With backtracking:")
Dim backPattern As String = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$"
sw = Stopwatch.StartNew()
matched = Regex.IsMatch(input, backPattern)
sw.Stop()
Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed)
Console.WriteLine()

Console.WriteLine("Without backtracking:")
Dim noBackPattern As String = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$"
sw = Stopwatch.StartNew()
matched = Regex.IsMatch(input, noBackPattern)
sw.Stop()
Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed)
End Sub
End Module
' The example displays the following output:
' With backtracking:
' Match: False in 00:00:27.4282019
'
' Without backtracking:
' Match: False in 00:00:00.0001391

aserciones de búsqueda tardía


.NET incluye dos elementos de lenguaje, (?<= subexpresión ) y (?<! subexpresión ) , que buscan una
coincidencia con el carácter o los caracteres anteriores de la cadena de entrada. Ambos elementos de lenguaje
son aserciones de ancho cero, es decir, determinan si el carácter o los caracteres que preceden inmediatamente
al carácter actual coinciden con subexpression, sin avanzar o retroceder.
(?<= subexpression ) es una aserción de búsqueda tardía positiva, es decir, el carácter o los caracteres
situados antes de la posición actual deben coincidir con subexpression. (?<! subexpression ) es una aserción
de búsqueda tardía negativa, es decir, el carácter o los caracteres situados antes de la posición actual no deben
coincidir con subexpression. Tanto las aserciones de búsqueda tardía positivas como las negativas son más útiles
cuando subexpression es un subconjunto de la subexpresión anterior.
En el ejemplo siguiente se usan dos patrones de expresiones regulares equivalentes que validan el nombre de
usuario de una dirección de correo electrónico. El primer patrón tiene un rendimiento bajo debido a un
retroceso excesivo. El segundo patrón modifica la primera expresión regular reemplazando un cuantificador
anidado con una aserción de búsqueda tardía positiva. El resultado del ejemplo muestra el tiempo de ejecución
del método Regex.IsMatch .
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
Stopwatch sw;
string input = "test@contoso.com";
bool result;

string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])?@";


sw = Stopwatch.StartNew();
result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
sw.Stop();
Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed);

string behindPattern = @"^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@";


sw = Stopwatch.StartNew();
result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase);
sw.Stop();
Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed);
}
}
// The example displays output similar to the following:
// Match: True in 00:00:00.0017549
// Match with Lookbehind: True in 00:00:00.0000659

Module Example
Public Sub Main()
Dim sw As Stopwatch
Dim input As String = "test@contoso.com"
Dim result As Boolean

Dim pattern As String = "^[0-9A-Z]([-.\w]*[0-9A-Z])?@"


sw = Stopwatch.StartNew()
result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
sw.Stop()
Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed)

Dim behindPattern As String = "^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@"


sw = Stopwatch.StartNew()
result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase)
sw.Stop()
Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed)
End Sub
End Module
' The example displays output similar to the following:
' Match: True in 00:00:00.0017549
' Match with Lookbehind: True in 00:00:00.0000659

El primer patrón de expresión regular, ^[0-9A-Z]([-.\w]*[0-9A-Z])*@ , se define como se muestra en la tabla


siguiente.

MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias en el principio de la


cadena.
MODELO DESCRIPCIÓN

[0-9A-Z] Buscar coincidencias de un carácter alfanumérico. Esta


comparación no distingue mayúsculas de minúsculas, ya que
se llama al método Regex.IsMatch con la opción
RegexOptions.IgnoreCase .

[-.\w]* Buscar coincidencias con cero, una o más apariciones de un


guión, un punto o un carácter alfabético.

[0-9A-Z] Buscar coincidencias de un carácter alfanumérico.

([-.\w]*[0-9A-Z])* Buscar coincidencias con cero o más apariciones de la


combinación de cero o más guiones, puntos o caracteres
alfabéticos, seguidos de un carácter alfanumérico. Este es el
primer grupo de captura.

@ Buscar coincidencias con un signo ("@").

El segundo patrón de expresión regular, ^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@ , emplea una aserción de búsqueda


tardía positiva. Se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias en el principio de la


cadena.

[0-9A-Z] Buscar coincidencias de un carácter alfanumérico. Esta


comparación no distingue mayúsculas de minúsculas, ya que
se llama al método Regex.IsMatch con la opción
RegexOptions.IgnoreCase .

[-.\w]* Buscar coincidencias con cero o más apariciones de un


guión, un punto o un carácter alfabético.

(?<=[0-9A-Z]) Volver a examinar el último carácter coincidente y continuar


con la coincidencia si es alfanumérica. Tenga en cuenta que
los caracteres alfanuméricos son un subconjunto del
conjunto formado por puntos, guiones y todos los
caracteres alfabéticos.

@ Buscar coincidencias con un signo ("@").

aserciones de búsqueda anticipada


.NET incluye dos elementos de lenguaje, (?= subexpresión ) y (?! subexpresión ) , que buscan una
coincidencia con el carácter o los caracteres siguientes de la cadena de entrada. Ambos elementos de lenguaje
son aserciones de ancho cero, es decir, determinan si el carácter o los caracteres que siguen inmediatamente al
carácter actual coinciden con subexpression, sin avanzar o retroceder.
(?= subexpression ) es una aserción de búsqueda anticipada positiva, es decir, el carácter o los caracteres
situados después de la posición actual deben coincidir con subexpression. (?! subexpression ) es una aserción
de búsqueda anticipada negativa, es decir, el carácter o los caracteres situados después de la posición actual no
deben coincidir con subexpression. Tanto las aserciones de búsqueda anticipada positivas como las negativas
son más útiles cuando subexpression es un subconjunto de la siguiente subexpresión.
En el ejemplo siguiente se usan dos patrones de expresiones regulares que validan un nombre de tipo
completo. El primer patrón tiene un rendimiento bajo debido a un retroceso excesivo. El segundo modifica la
primera expresión regular reemplazando un cuantificador anidado con una aserción de búsqueda anticipada
positiva. El resultado del ejemplo muestra el tiempo de ejecución del método Regex.IsMatch .

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string input = "aaaaaaaaaaaaaaaaaaaaaa.";
bool result;
Stopwatch sw;

string pattern = @"^(([A-Z]\w*)+\.)*[A-Z]\w*$";


sw = Stopwatch.StartNew();
result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
sw.Stop();
Console.WriteLine("{0} in {1}", result, sw.Elapsed);

string aheadPattern = @"^((?=[A-Z])\w+\.)*[A-Z]\w*$";


sw = Stopwatch.StartNew();
result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase);
sw.Stop();
Console.WriteLine("{0} in {1}", result, sw.Elapsed);
}
}
// The example displays the following output:
// False in 00:00:03.8003793
// False in 00:00:00.0000866

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim input As String = "aaaaaaaaaaaaaaaaaaaaaa."
Dim result As Boolean
Dim sw As Stopwatch

Dim pattern As String = "^(([A-Z]\w*)+\.)*[A-Z]\w*$"


sw = Stopwatch.StartNew()
result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
sw.Stop()
Console.WriteLine("{0} in {1}", result, sw.Elapsed)

Dim aheadPattern As String = "^((?=[A-Z])\w+\.)*[A-Z]\w*$"


sw = Stopwatch.StartNew()
result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase)
sw.Stop()
Console.WriteLine("{0} in {1}", result, sw.Elapsed)
End Sub
End Module
' The example displays the following output:
' False in 00:00:03.8003793
' False in 00:00:00.0000866

El primer patrón de expresión regular, ^(([A-Z]\w*)+\.)*[A-Z]\w*$ , se define como se muestra en la tabla


siguiente.
MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias en el principio de la


cadena.

([A-Z]\w*)+\. Buscar coincidencias con un carácter alfabético (A-Z) seguido


de cero o más caracteres alfabéticos una o más veces,
seguidas de un punto. Esta comparación no distingue
mayúsculas de minúsculas, ya que se llama al método
Regex.IsMatch con la opción RegexOptions.IgnoreCase .

(([A-Z]\w*)+\.)* Buscar coincidencias con el patrón anterior cero o más veces.

[A-Z]\w* Buscar coincidencias con un carácter alfabético seguido de


cero o más caracteres alfabéticos.

$ Finalizar la búsqueda de coincidencias al final de la cadena de


entrada.

El segundo patrón de expresión regular, ^((?=[A-Z])\w+\.)*[A-Z]\w*$ , emplea una aserción de búsqueda


anticipada positiva. Se define como se muestra en la tabla siguiente.

MODELO DESCRIPCIÓN

^ Iniciar la búsqueda de coincidencias en el principio de la


cadena.

(?=[A-Z]) Examinar hacia delante el primer carácter y continuar la


búsqueda de coincidencias si es alfabético (A-Z). Esta
comparación no distingue mayúsculas de minúsculas, ya que
se llama al método Regex.IsMatch con la opción
RegexOptions.IgnoreCase .

\w+\. Buscar coincidencias con uno o más caracteres alfabéticos


seguidos de un punto.

((?=[A-Z])\w+\.)* Buscar coincidencias con el patrón de uno o varios caracteres


alfabéticos seguidos de un punto una o varias veces. El
carácter alfabético inicial debe ser alfabético.

[A-Z]\w* Buscar coincidencias con un carácter alfabético seguido de


cero o más caracteres alfabéticos.

$ Finalizar la búsqueda de coincidencias al final de la cadena de


entrada.

Vea también
Expresiones regulares de .NET
Lenguaje de expresiones regulares: referencia rápida
Cuantificadores
Construcciones de alternancia
Construcciones de agrupamiento
Compilar y volver a utilizar en expresiones regulares
04/11/2019 • 5 minutes to read • Edit Online

Puede optimizar el rendimiento de aplicaciones que usan en gran medida las expresiones regulares al comprender
cómo compila expresiones el motor de expresiones regulares y cómo se almacenan en caché las expresiones
regulares. En este tema, se describen la compilación y el almacenamiento en caché.

Expresiones regulares compiladas


De manera predeterminada, el motor de expresiones regulares compila una expresión regular en una secuencia de
instrucciones internas (son códigos de alto nivel diferentes del Lenguaje Intermedio de Microsoft, o MSIL ).
Cuando el motor ejecuta una expresión regular, interpreta los códigos internos.
Si un objeto Regex se construye con la opción RegexOptions.Compiled, compila la expresión regular en código
MSIL explícito en lugar de instrucciones internas de expresiones regulares de alto nivel. De este modo, el
compilador Just-In-Time (JIT) de .NET puede convertir la expresión en código de equipo nativo para un mayor
rendimiento.
En cambio, el lenguaje MSIL generado no se puede descargar. La única forma de descargar el código es descargar
un dominio de aplicación completo (es decir, descargar todo el código de la aplicación). De hecho, una vez
compilada una expresión regular con la opción RegexOptions.Compiled, .NET nunca lanza los recursos usados por
la expresión compilada, aunque la expresión regular la haya creado un objeto Regex liberado para la recolección de
elementos no utilizados.
Debe asegurarse de limitar el número de expresiones regulares distintas que compila con la opción
RegexOptions.Compiled para evitar que se consuman demasiados recursos. Si una aplicación debe usar un
número muy grande o ilimitado de expresiones regulares, cada expresión debe interpretarse, no compilarse. En
cambio, si se usa varias veces un número pequeño de expresiones regulares, estas deben compilarse con
RegexOptions.Compiled para mejorar el rendimiento. Una alternativa consiste en utilizar expresiones regulares
precompiladas. Puede compilar todas las expresiones en un archivo DLL reutilizable con el método
CompileToAssembly. Esto evita la necesidad de compilar en tiempo de ejecución mientras todavía se beneficia de
la velocidad de las expresiones regulares compiladas.

La caché de expresiones regulares


Para mejorar el rendimiento, el motor de expresiones regulares mantiene una caché de la aplicación de
expresiones regulares compiladas. La caché almacena los patrones de expresiones regulares que se usan solo en
las llamadas al método estático. (Los patrones de expresiones regulares proporcionados a métodos de instancia no
se almacenan en caché). Esto evita la necesidad de volver a analizar una expresión en código de bytes de alto nivel
cada vez que se usa.
El valor de la propiedad static ( Shared en Visual Basic) Regex.CacheSize determina el número máximo de
expresiones regulares almacenadas en caché. De manera predeterminada, el motor de expresiones regulares
almacena en caché hasta 15 expresiones regulares compiladas. Si el número de expresiones regulares compiladas
supera el tamaño de la caché, se descarta la expresión regular usada menos recientemente y se almacena en caché
la nueva expresión regular.
La aplicación puede aprovechar las expresiones regulares compiladas previamente en una de las siguientes
formas:
Mediante el uso de un método estático del objeto Regex para definir la expresión regular. Si usa un patrón
de expresión regular que ya se ha definido en otra llamada al método estático, el motor de expresiones
regulares lo recuperará de la caché. De lo contrario, el motor compilará la expresión regular y la agregará a
la caché.
Al volver a usar un objeto Regex existente siempre que sea necesario su patrón de expresión regular.
Debido a la sobrecarga de la creación de instancias de objeto y la compilación de expresiones regulares, crear y
destruir rápidamente numerosos objetos Regex es un proceso muy costoso. Para aplicaciones que usan un gran
número de expresiones regulares diferentes, puede optimizar el rendimiento al realizar llamadas a métodos Regex
estáticos y posiblemente al aumentar el tamaño de la caché de expresiones regulares.

Vea también
Expresiones regulares de .NET
Seguridad para subprocesos en expresiones regulares
04/11/2019 • 2 minutes to read • Edit Online

La clase Regex es en sí misma segura para subprocesos e inmutable (de solo lectura). Es decir, se pueden crear
objetos Regex en cualquier subproceso y compartirlos entre varios subprocesos; los métodos de coincidencia
pueden llamarse desde cualquier subproceso y no modifican nunca el estado global.
Pero los objetos de resultado (Match y MatchCollection) que devuelve Regex deben usarse en un único
subproceso. Aunque muchos de estos objetos son lógicamente inmutables, sus implementaciones pueden retrasar
el cálculo de algunos resultados para mejorar el rendimiento y, en consecuencia, los llamadores deben serializar el
acceso a ellos.
Si es necesario compartir objetos de resultado de Regex en varios subprocesos, estos objetos se pueden convertir
en instancias seguras para subprocesos llamando a sus métodos sincronizados. A excepción de los enumeradores,
todas las clases de expresiones regulares son seguras para subprocesos o pueden convertirse en objetos seguros
para subprocesos mediante un método sincronizado.
Los enumeradores son la única excepción. Las aplicaciones debe serializar las llamadas a enumeradores de
colecciones. La regla es que, si una colección puede enumerarse simultáneamente en más de un subproceso, se
deben sincronizar los métodos de enumerador en el objeto raíz de la colección que recorre el enumerador.

Vea también
Expresiones regulares de .NET
Ejemplos de expresiones regulares
04/11/2019 • 2 minutes to read • Edit Online

Esta sección contiene ejemplos de código que ilustran el uso de expresiones regulares en aplicaciones comunes.

NOTE
El espacio de nombres System.Web.RegularExpressions contiene un número de objetos de expresión regular que
implementan modelos de expresión regular predefinidos para el análisis de cadenas a partir de documentos HTML, XML y
ASP.NET. Por ejemplo, la clase TagRegex identifica las etiquetas de inicio en una cadena y la clase CommentRegex identifica
los comentarios de ASP.NET en una cadena.

En esta sección
Ejemplo: Buscar etiquetas HREF
Ofrece un ejemplo en el que se busca una cadena de entrada y se muestran todos los valores href="…" y sus
ubicaciones en la cadena.
Ejemplo: Cambio de formatos de fecha
Ofrece un ejemplo en el que se reemplazan las fechas en formato mm/dd/aa por fechas en el formato dd-mm-aa.
Cómo: Extraer un protocolo y un número de puerto de una dirección URL
Ofrece un ejemplo en el que se extrae un protocolo y número de puerto de una cadena que contiene una dirección
URL. Por ejemplo, "http://www.contoso.com:8080/letters/readme.html" devuelve "http:8080".
Cómo: Quitar caracteres no válidos de una cadena
Ofrece un ejemplo en el que se eliminan los caracteres no alfanuméricos no válidos de una cadena.
Cómo: Comprobación de que las cadenas están en un formato de correo electrónico válido
Proporciona un ejemplo que comprueba si una cadena tiene un formato de correo electrónico válido.

Referencia
System.Text.RegularExpressions
Ofrece información de referencia de la biblioteca de clases para el espacio de nombres
System.Text.RegularExpressions de .NET.

Secciones relacionadas
Expresiones regulares de .NET
Proporciona información general sobre el aspecto del lenguaje de programación de expresiones regulares.
Modelo de objetos de expresión regular
Describe las clases de expresión regular contenidas en el espacio de nombres System.Text.RegularExpression y
proporciona ejemplos de su uso.
Detalles del comportamiento de expresiones regulares
Proporciona información sobre las funcionalidades y el comportamiento de las expresiones regulares de .NET.
Lenguaje de expresiones regulares: referencia rápida
Ofrece información sobre el conjunto de caracteres, operadores y construcciones que se pueden utilizar para
definir expresiones regulares.
Ejemplo de expresiones regulares: Buscar etiquetas
HREF
04/11/2019 • 6 minutes to read • Edit Online

En el ejemplo siguiente se busca una cadena de entrada y se muestran todos los valores href="…" y sus
ubicaciones en la cadena.

El objeto Regex
Dado que el método DumpHRefs puede llamarse varias veces desde el código de usuario, usa el método static (
Shared en Visual Basic) Regex.Match( String, String, RegexOptions). Esto permite que el motor de expresiones
regulares almacene en caché la expresión regular y evita la sobrecarga que se produciría al crear instancias de un
nuevo objeto Regex cada vez que se llamara al método. Después, se usa un objeto Match para iterar todas las
coincidencias de la cadena.

private static void DumpHRefs(string inputString)


{
Match m;
string HRefPattern = @"href\s*=\s*(?:[""'](?<1>[^""']*)[""']|(?<1>\S+))";

try
{
m = Regex.Match(inputString, HRefPattern,
RegexOptions.IgnoreCase | RegexOptions.Compiled,
TimeSpan.FromSeconds(1));
while (m.Success)
{
Console.WriteLine("Found href " + m.Groups[1] + " at "
+ m.Groups[1].Index);
m = m.NextMatch();
}
}
catch (RegexMatchTimeoutException)
{
Console.WriteLine("The matching operation timed out.");
}
}

Private Sub DumpHRefs(inputString As String)


Dim m As Match
Dim HRefPattern As String = "href\s*=\s*(?:[""'](?<1>[^""']*)[""']|(?<1>\S+))"

Try
m = Regex.Match(inputString, HRefPattern, _
RegexOptions.IgnoreCase Or RegexOptions.Compiled,
TimeSpan.FromSeconds(1))
Do While m.Success
Console.WriteLine("Found href {0} at {1}.", _
m.Groups(1), m.Groups(1).Index)
m = m.NextMatch()
Loop
Catch e As RegexMatchTimeoutException
Console.WriteLine("The matching operation timed out.")
End Try
End Sub
En el ejemplo siguiente se muestra la llamada al método DumpHRefs .

public static void Main()


{
string inputString = "My favorite web sites include:</P>" +
"<A HREF=\"http://msdn2.microsoft.com\">" +
"MSDN Home Page</A></P>" +
"<A HREF=\"http://www.microsoft.com\">" +
"Microsoft Corporation Home Page</A></P>" +
"<A HREF=\"http://blogs.msdn.com/bclteam\">" +
".NET Base Class Library blog</A></P>";
DumpHRefs(inputString);
}
// The example displays the following output:
// Found href http://msdn2.microsoft.com at 43
// Found href http://www.microsoft.com at 102
// Found href http://blogs.msdn.com/bclteam at 176

Public Sub Main()


Dim inputString As String = "My favorite web sites include:</P>" & _
"<A HREF=""http://msdn2.microsoft.com"">" & _
"MSDN Home Page</A></P>" & _
"<A HREF=""http://www.microsoft.com"">" & _
"Microsoft Corporation Home Page</A></P>" & _
"<A HREF=""http://blogs.msdn.com/bclteam"">" & _
".NET Base Class Library blog</A></P>"
DumpHRefs(inputString)
End Sub
' The example displays the following output:
' Found href http://msdn2.microsoft.com at 43
' Found href http://www.microsoft.com at 102
' Found href http://blogs.msdn.com/bclteam/) at 176

El patrón de la expresión regular href\s*=\s*(?:["'](?<1>[^"']*)["']|(?<1>\S+)) se interpreta como se muestra en


la tabla siguiente.

MODELO DESCRIPCIÓN

href Coincide con la cadena literal "href". La búsqueda no distingue


entre mayúsculas y minúsculas.

\s* Busca coincidencias con cero o más caracteres de espacio en


blanco.

= Coincide con el signo igual.

\s* Busca coincidencias con cero o más caracteres de espacio en


blanco.
MODELO DESCRIPCIÓN

(?:\["'\](?<1>\[^"'\]*)["']|(?<1>\S+)) Coincide con uno de los siguientes sin asignar el resultado a


un grupo capturado:
Una comilla o un apóstrofo, seguido de cero o más
apariciones de cualquier carácter que no sea una
comilla o un apóstrofo, seguido por una comilla o
un apóstrofo. El grupo con nombre 1 se incluye
en este patrón.
Uno o varios caracteres que no son espacios en
blanco. El grupo con nombre 1 se incluye en este
patrón.

(?<1>[^"']*) Asigna cero o más apariciones de cualquier carácter que no


sea apóstrofo o comilla al grupo de captura con nombre 1 .

(?<1>\S+) Asigna uno o varios caracteres que no sean un espacio en


blanco al grupo de captura con nombre 1 .

Clase de resultado Match


Los resultados de la búsqueda se almacenan en la clase Match, que proporciona acceso a todas las subcadenas
extraídas por la búsqueda. También recuerda la cadena buscada y la expresión regular que se usa, por lo que puede
llamar al método Match.NextMatch para realizar otra búsqueda desde donde terminó la anterior.

Capturas con nombre explícito


En las expresiones regulares tradicionales, los paréntesis de captura se numeran secuencialmente de forma
automática. Esto origina dos problemas. En primer lugar, si se modifica una expresión regular al insertar o quitar
un conjunto de paréntesis, se debe reescribir todo el código que hace referencia a las capturas numeradas para
reflejar la nueva numeración. En segundo lugar, puesto que a menudo se usan diferentes conjuntos de paréntesis
para proporcionar expresiones alternativas para una coincidencia aceptable, puede resultar difícil determinar cuál
de las dos expresiones devolvió realmente un resultado.
Para abordar estos problemas, la clase Regex admite la sintaxis (?<name>…) para capturar una coincidencia en una
ranura especificada (el nombre dado a la ranura puede ser una cadena o un entero; los enteros se pueden
recuperar con más rapidez). Así, las coincidencias alternativas para la misma cadena se pueden dirigir todas al
mismo lugar. En caso de conflicto, la última coincidencia situada en la ranura es la coincidencia correcta. (Pero está
disponible una lista completa de varias coincidencias para una única ranura. Consulte la colección Group.Captures
para obtener más información).

Vea también
Expresiones regulares de .NET
Ejemplo de expresiones regulares: Cambiar formatos
de fecha
04/11/2019 • 2 minutes to read • Edit Online

En el siguiente ejemplo de código, se usa el método Regex.Replace para reemplazar las fechas con el formato
mm/dd/aa con fechas que tienen el formato dd-mm-aa.

Ejemplo
static string MDYToDMY(string input)
{
try {
return Regex.Replace(input,
@"\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b",
"${day}-${month}-${year}", RegexOptions.None,
TimeSpan.FromMilliseconds(150));
}
catch (RegexMatchTimeoutException) {
return input;
}
}

Function MDYToDMY(input As String) As String


Try
Return Regex.Replace(input, _
"\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b", _
"${day}-${month}-${year}", RegexOptions.None,
TimeSpan.FromMilliseconds(150))
Catch e As RegexMatchTimeoutException
Return input
End Try
End Function

El código siguiente muestra cómo se puede llamar al método MDYToDMY en una aplicación.
using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class Class1


{
public static void Main()
{
string dateString = DateTime.Today.ToString("d",
DateTimeFormatInfo.InvariantInfo);
string resultString = MDYToDMY(dateString);
Console.WriteLine("Converted {0} to {1}.", dateString, resultString);
}

static string MDYToDMY(string input)


{
try {
return Regex.Replace(input,
@"\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b",
"${day}-${month}-${year}", RegexOptions.None,
TimeSpan.FromMilliseconds(150));
}
catch (RegexMatchTimeoutException) {
return input;
}
}
}
// The example displays the following output to the console if run on 8/21/2007:
// Converted 08/21/2007 to 21-08-2007.

Imports System.Globalization
Imports System.Text.RegularExpressions

Module DateFormatReplacement
Public Sub Main()
Dim dateString As String = Date.Today.ToString("d", _
DateTimeFormatInfo.InvariantInfo)
Dim resultString As String = MDYToDMY(dateString)
Console.WriteLine("Converted {0} to {1}.", dateString, resultString)
End Sub

Function MDYToDMY(input As String) As String


Try
Return Regex.Replace(input, _
"\b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b", _
"${day}-${month}-${year}", RegexOptions.None,
TimeSpan.FromMilliseconds(150))
Catch e As RegexMatchTimeoutException
Return input
End Try
End Function
End Module
' The example displays the following output to the console if run on 8/21/2007:
' Converted 08/21/2007 to 21-08-2007.

Comentarios
El patrón de la expresión regular \b(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})\b se interpreta como se
muestra en la tabla siguiente.
MODELO DESCRIPCIÓN

\b Iniciar la búsqueda de coincidencias en un límite de palabras.

(?<month>\d{1,2}) Buscar coincidencias con uno o dos dígitos decimales. Es el


grupo month capturado.

/ Buscar coincidencias con la barra diagonal.

(?<day>\d{1,2}) Buscar coincidencias con uno o dos dígitos decimales. Es el


grupo day capturado.

/ Buscar coincidencias con la barra diagonal.

(?<year>\d{2,4}) Buscar coincidencias de dos a cuatro dígitos decimales. Es el


grupo year capturado.

\b Finalizar la búsqueda de coincidencias en un límite de


palabras.

El patrón ${day}-${month}-${year} define la cadena de reemplazo como se muestra en la siguiente tabla.

MODELO DESCRIPCIÓN

$(day) Agregar la cadena capturada por el grupo de captura day .

- Agregar un guión.

$(month) Agregar la cadena capturada por el grupo de captura month .

- Agregar un guión.

$(year) Agregar la cadena capturada por el grupo de captura year .

Vea también
Expresiones regulares de .NET
Procedimiento para extraer un protocolo y un
número de puerto de una dirección URL
04/11/2019 • 2 minutes to read • Edit Online

En los siguientes ejemplos se extrae un protocolo y un número de puerto de una dirección URL.

Ejemplo
El ejemplo usa el método Match.Result para devolver el protocolo seguido de dos puntos y del número de puerto.

using System;
using System.Text.RegularExpressions;

public class Example


{
public static void Main()
{
string url = "http://www.contoso.com:8080/letters/readme.html";

Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",


RegexOptions.None, TimeSpan.FromMilliseconds(150));
Match m = r.Match(url);
if (m.Success)
Console.WriteLine(m.Result("${proto}${port}"));
}
}
// The example displays the following output:
// http:8080

Imports System.Text.RegularExpressions

Module Example
Public Sub Main()
Dim url As String = "http://www.contoso.com:8080/letters/readme.html"
Dim r As New Regex("^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",
RegexOptions.None, TimeSpan.FromMilliseconds(150))

Dim m As Match = r.Match(url)


If m.Success Then
Console.WriteLine(m.Result("${proto}${port}"))
End If
End Sub
End Module
' The example displays the following output:
' http:8080

El patrón de la expresión regular ^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/ puede interpretarse como se muestra en


la tabla siguiente.

MODELO DESCRIPCIÓN

^ Comenzar la búsqueda de coincidencia al principio de la


cadena.
MODELO DESCRIPCIÓN

(?<proto>\w+) Buscar coincidencias con uno o más caracteres alfabéticos.


Asigne a este grupo el nombre proto .

:// Buscar coincidencias con un signo de dos puntos seguido por


dos barras diagonales.

[^/]+? Buscar coincidencias con una o más apariciones (pero el


menor número posible) de cualquier carácter que no sea una
barra diagonal.

(?<port>:\d+)? Buscar una coincidencia con cero o una aparición de una coma
seguida de uno o más caracteres decimales. Asigne a este
grupo el nombre port .

/ Buscar una coincidencia con una barra diagonal.

El método Match.Result expande la secuencia de reemplazo ${proto}${port} , que concatena el valor de los dos
grupos con nombre capturados en el patrón de expresión regular. Resulta cómodo concatenar explícitamente las
cadenas recuperadas del objeto de la colección devueltas por la propiedad Match.Groups.
El ejemplo usa el método Match.Result con dos sustituciones, ${proto} y ${port} , para incluir los grupos
capturados en la cadena de salida. En su lugar, puede recuperar los grupos capturados del objeto de coincidencia
GroupCollection, como se muestra en el siguiente código.

Console.WriteLine(m.Groups["proto"].Value + m.Groups["port"].Value);

Console.WriteLine(m.Groups("proto").Value + m.Groups("port").Value)

Vea también
Expresiones regulares de .NET
Procedimiento para quitar caracteres no válidos de
una cadena
04/11/2019 • 2 minutes to read • Edit Online

En el ejemplo siguiente se usa el método estático Regex.Replace para quitar caracteres no válidos de una cadena.

Ejemplo
Puede usar el método CleanInput definido en este ejemplo para quitar caracteres potencialmente perjudiciales
que se hayan escrito en un campo de texto que acepta datos del usuario. En este caso, CleanInput elimina todos
los caracteres no alfanuméricos excepto puntos (.), símbolos de arroba (@) y guiones (-), y devuelve la cadena
restante. Pero puede modificar el patrón de expresión regular para que elimine todos los caracteres que no deban
incluirse en una cadena de entrada.

using System;
using System.Text.RegularExpressions;

public class Example


{
static string CleanInput(string strIn)
{
// Replace invalid characters with empty strings.
try {
return Regex.Replace(strIn, @"[^\w\.@-]", "",
RegexOptions.None, TimeSpan.FromSeconds(1.5));
}
// If we timeout when replacing invalid characters,
// we should return Empty.
catch (RegexMatchTimeoutException) {
return String.Empty;
}
}
}

Imports System.Text.RegularExpressions

Module Example
Function CleanInput(strIn As String) As String
' Replace invalid characters with empty strings.
Try
Return Regex.Replace(strIn, "[^\w\.@-]", "")
' If we timeout when replacing invalid characters,
' we should return String.Empty.
Catch e As RegexMatchTimeoutException
Return String.Empty
End Try
End Function
End Module

El patrón de expresión regular [^\w\.@-] coincide con cualquier carácter que no sea un carácter de palabra, un
punto, un símbolo @ o un guion. Un carácter de palabra es cualquier letra, dígito decimal o conector de
puntuación, como un guion bajo. Cualquier carácter que coincida con este patrón se sustituye por String.Empty,
que es la cadena definida por el modelo de reemplazo. Para permitir caracteres adicionales en la entrada de
usuario, agregue esos caracteres a la clase de caracteres en el patrón de la expresión regular. Por ejemplo, el
patrón de expresión regular [^\w\.@-\\%] también permite un símbolo de porcentaje y una barra diagonal inversa
en la cadena de entrada.

Vea también
Expresiones regulares de .NET
Cómo comprobar si las cadenas tienen un formato
de correo electrónico válido
25/11/2019 • 11 minutes to read • Edit Online

En el ejemplo siguiente se usa una expresión regular para comprobar que una cadena tiene un formato de correo
electrónico válido.

Ejemplo
En el ejemplo se define un método IsValidEmail , que devuelve true si la cadena contiene una dirección de
correo electrónico válida y false si no es válida, pero no realiza ninguna otra acción.
Para comprobar que la dirección de correo electrónico es válida, el método IsValidEmail llama al método
Regex.Replace(String, String, MatchEvaluator) con el patrón de expresión regular (@)(.+)$ para separar el
nombre de dominio de la dirección de correo electrónico. El tercer parámetro es un delegado MatchEvaluator
que representa el método que procesa y reemplaza el texto coincidente. El patrón de expresión regular se
interpreta de esta manera:

MODELO DESCRIPCIÓN

(@) Buscar el carácter @. Este es el primer grupo de captura.

(.+) Buscar una coincidencia con una o más apariciones de


cualquier carácter. Este es el segundo grupo de captura.

$ Finalizar la búsqueda al final de la cadena.

El nombre de dominio junto con el carácter @ se pasa al método DomainMapper , que usa la clase IdnMapping
para convertir los caracteres Unicode fuera del intervalo de caracteres EE.UU. - ASCII a Punycode. El método
también establece la marca invalid en True si el método IdnMapping.GetAscii detecta cualquier carácter no
válido en el nombre del dominio. El método devuelve el nombre de dominio Punycode precedido por el símbolo
@ al método IsValidEmail .
A continuación, el método IsValidEmail llama al método Regex.IsMatch(String, String) para comprobar que la
dirección se ajusta a un patrón de expresión regular.
Tenga en cuenta que el método IsValidEmail no realiza la autenticación para validar la dirección de correo
electrónico. Se limita a determinar si su formato es válido para una dirección de correo electrónico. Asimismo, el
método IsValidEmail no comprueba que el nombre del dominio de nivel superior sea un nombre válido
enumerado en la base de datos de la zona de la raíz IANA, lo cual requeriría una operación de búsqueda. En su
lugar, la expresión regular comprueba simplemente que el nombre de dominio de nivel superior conste de entre
dos y veinticuatro caracteres ASCII alfanuméricos, que los caracteres primero y último sean alfanuméricos y que
el resto de caracteres sean alfanuméricos o un guión (-).
using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class RegexUtilities


{
public static bool IsValidEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
return false;

try
{
// Normalize the domain
email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
RegexOptions.None, TimeSpan.FromMilliseconds(200));

// Examines the domain part of the email and normalizes it.


string DomainMapper(Match match)
{
// Use IdnMapping class to convert Unicode domain names.
var idn = new IdnMapping();

// Pull out and process domain name (throws ArgumentException on invalid)


var domainName = idn.GetAscii(match.Groups[2].Value);

return match.Groups[1].Value + domainName;


}
}
catch (RegexMatchTimeoutException e)
{
return false;
}
catch (ArgumentException e)
{
return false;
}

try
{
return Regex.IsMatch(email,
@"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-
z])@))" +
@"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}
[a-z0-9]))$",
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
}
catch (RegexMatchTimeoutException)
{
return false;
}
}
}
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Class RegexUtilities

Public Shared Function IsValidEmail(email As String) As Boolean

If String.IsNullOrWhiteSpace(email) Then Return False

' Use IdnMapping class to convert Unicode domain names.


Try
'Examines the domain part of the email and normalizes it.
Dim DomainMapper =
Function(match As Match) As String

'Use IdnMapping class to convert Unicode domain names.


Dim idn = New IdnMapping

'Pull out and process domain name (throws ArgumentException on invalid)


Dim domainName As String = idn.GetAscii(match.Groups(2).Value)

Return match.Groups(1).Value & domainName

End Function

'Normalize the domain


email = Regex.Replace(email, "(@)(.+)$", DomainMapper,
RegexOptions.None, TimeSpan.FromMilliseconds(200))

Catch e As RegexMatchTimeoutException
Return False

Catch e As ArgumentException
Return False

End Try

Try
Return Regex.IsMatch(email,
"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\
{\}\|~\w])*)(?<=[0-9a-z])@))" +
"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9]
[\-a-z0-9]{0,22}[a-z0-9]))$",
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250))

Catch e As RegexMatchTimeoutException
Return False

End Try

End Function

End Class

En este ejemplo, el patrón de expresión regular


^(?(")(".+?(?<!\\)"@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\
[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$
se interpreta como se muestra en la leyenda siguiente. La expresión regular se compila mediante la marca
RegexOptions.IgnoreCase.
Patrón ^ : Comenzar la búsqueda de coincidencia al principio de la cadena.
Patrón (?(") : Determinar si el primer carácter es una comilla. (?(") es el principio de una construcción de
alternancia.
Patrón (?(")(".+?(?<!\\)"@) : Si el primer carácter es un signo de comillas, buscar unas comillas iniciales
seguidas de al menos un carácter cualquiera, seguido a su vez de unas comillas finales. Las comillas finales no
pueden ir precedidas de un carácter de barra diagonal inversa (\). (?<! es el principio de una aserción de
búsqueda anticipada negativa de ancho cero. La cadena debe concluir con una arroba (@).
Patrón |(([0-9a-z] : Si el primer carácter no es un signo de comillas, buscar cualquier carácter alfabético de la a
a la z o de la A a la Z (la comparación distingue entre mayúsculas y minúsculas) o cualquier carácter numérico del
0 al 9.
Patrón (\.(?!\.)) : Si el carácter siguiente es un punto, determinar que coincide. Si no lo es, buscar más adelante
en el siguiente carácter y probar si coincide. (?!\.) es una aserción de búsqueda anticipada negativa de ancho
igual a cero que evita que aparezcan dos puntos consecutivos en la parte local de una dirección de correo
electrónico.
Patrón |[-!#\$%&'\*\+/=\?\^`\{\}\|~\w] : Si el carácter siguiente no es un punto, busque la coincidencia de
cualquier carácter de palabra o uno de los caracteres siguientes: -!#$%&'*+/=?^`{}|~
Patrón ((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])* : Buscar el modelo de alternancia (un punto seguido de algo
que no sea un punto, o uno de varios caracteres) cero o más veces.
Patrón @ : Buscar el carácter @.
Patrón (?<=[0-9a-z]) : Continuar buscando si el carácter que precede al carácter @ es uno de la A a la Z, de la a a
la z o del 0 al 9. Este patrón define una aserción de búsqueda retrasada (lookbehind) positiva de ancho cero.
Patrón (?(\[) : Comprobar si el carácter que va detrás de @ es un corchete de apertura.
Patrón (\[(\d{1,3}\.){3}\d{1,3}\]) : Si lo es, buscar el corchete de apertura, seguido por una dirección IP (cuatro
grupos de uno a tres dígitos, separados por puntos) y por un corchete de cierre.
Patrón |(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+ : Si el carácter que va detrás de @ no es un corchete de apertura,
buscar un carácter alfanumérico con un valor de la A a la Z, de la a a la z o del 0 al 9, seguido de cero o más
apariciones de un guión, seguido de cero o de un carácter alfanumérico con un valor de la A a la Z, de la a a la z o
del 0 al 9, seguido de un punto. Este patrón se puede repetir una o más veces y debe ir seguido del nombre de
dominio de nivel superior.
Patrón [a-z0-9][\-a-z0-9]{0,22}[a-z0-9])) : El nombre de dominio de nivel superior debe empezar y finalizar por
un carácter alfanumérico (a-z, A-Z y 0-9). También puede incluir de cero a 22 caracteres ASCII que sean
alfanuméricos o guiones.
Patrón $ : Finalizar la búsqueda al final de la cadena.

Compilar el código
Los métodos IsValidEmail y DomainMapper pueden estar incluidos en una biblioteca de métodos de la utilidad de
expresiones regulares o pueden incluirse como métodos estáticos o de instancia privados en la clase de
aplicación.
También puede usar el método Regex.CompileToAssembly para incluir esta expresión regular en una biblioteca
de expresiones regulares.
Si se utilizan en una biblioteca de expresiones regulares, puede llamarlos utilizando código como el siguiente:
class Program
{
static void Main(string[] args)
{
string[] emailAddresses = { "david.jones@proseware.com", "d.j@server1.proseware.com",
"jones@ms1.proseware.com", "j.@server1.proseware.com",
"j@proseware.com9", "js#internal@proseware.com",
"j_9@[129.126.118.1]", "j..s@proseware.com",
"js*@proseware.com", "js@proseware..com",
"js@proseware.com9", "j.s@server1.proseware.com",
"\"j\\\"s\\\"\"@proseware.com", "js@contoso.中国" };

foreach (var emailAddress in emailAddresses)


{
if (RegexUtilities.IsValidEmail(emailAddress))
Console.WriteLine($"Valid: {emailAddress}");
else
Console.WriteLine($"Invalid: {emailAddress}");
}

Console.ReadKey();
}
}
// The example displays the following output:
// Valid: david.jones@proseware.com
// Valid: d.j@server1.proseware.com
// Valid: jones@ms1.proseware.com
// Invalid: j.@server1.proseware.com
// Valid: j@proseware.com9
// Valid: js#internal@proseware.com
// Valid: j_9@[129.126.118.1]
// Invalid: j..s@proseware.com
// Invalid: js*@proseware.com
// Invalid: js@proseware..com
// Valid: js@proseware.com9
// Valid: j.s@server1.proseware.com
// Valid: "j\"s\""@proseware.com
// Valid: js@contoso.中国
Public Class Application
Public Shared Sub Main()
Dim emailAddresses() As String = {"david.jones@proseware.com", "d.j@server1.proseware.com",
"jones@ms1.proseware.com", "j.@server1.proseware.com",
"j@proseware.com9", "js#internal@proseware.com",
"j_9@[129.126.118.1]", "j..s@proseware.com",
"js*@proseware.com", "js@proseware..com",
"js@proseware.com9", "j.s@server1.proseware.com",
"""j\""s\""""@proseware.com", "js@contoso.中国"}

For Each emailAddress As String In emailAddresses


If RegexUtilities.IsValidEmail(emailAddress) Then
Console.WriteLine($"Valid: {emailAddress}")
Else
Console.WriteLine($"Invalid: {emailAddress}")
End If
Next
End Sub
End Class
' The example displays the following output:
' Valid: david.jones@proseware.com
' Valid: d.j@server1.proseware.com
' Valid: jones@ms1.proseware.com
' Invalid: j.@server1.proseware.com
' Valid: j@proseware.com9
' Valid: js#internal@proseware.com
' Valid: j_9@[129.126.118.1]
' Invalid: j..s@proseware.com
' Invalid: js*@proseware.com
' Invalid: js@proseware..com
' Valid: js@proseware.com9
' Valid: j.s@server1.proseware.com
' Valid: "j\"s\""@proseware.com
' Valid: js@contoso.中国

Vea también
Expresiones regulares de .NET Framework
Codificación de caracteres de .NET
13/01/2020 • 69 minutes to read • Edit Online

Los caracteres son entidades abstractas que se pueden representar de muchas maneras diferentes. Una
codificación de caracteres es un sistema que empareja cada carácter de un juego de caracteres compatible con
algún valor que representa ese carácter. Por ejemplo, el código Morse es una codificación de caracteres que
empareja cada carácter del alfabeto latino con un patrón de puntos y guiones que son adecuados para la
transmisión a través de las líneas de telégrafo. Una codificación de caracteres para los equipos empareja cada
carácter de un juego de caracteres compatible con un valor numérico que representa ese carácter. Una codificación
de caracteres tiene dos componentes distintos:
Un codificador, que traduce una secuencia de caracteres en una secuencia de valores numéricos (bytes).
Un descodificador, que traduce una secuencia de bytes en una secuencia de caracteres.
La codificación de caracteres describe las reglas por las que funcionan un codificador y un descodificador. Por
ejemplo, la clase UTF8Encoding describe las reglas para codificar y descodificar del Formato de transformación
Unicode de 8 bits (UTF -8), que usa de uno a cuatro bytes para representar un único carácter Unicode. La
codificación y la descodificación también pueden incluir validación. Por ejemplo, la clase UnicodeEncoding
comprueba todos los suplentes para asegurarse de que constituyen pares suplentes válidos. (Un par suplente
consta de un carácter con un punto de código que va de U+D800 a U+DBFF, seguido de un carácter con un punto
de código que va de U+DC00 a U+DFFF.) Una estrategia de reserva determina cómo trata un codificador los
caracteres no válidos o cómo trata un descodificador los bytes no válidos.

WARNING
Las clases de codificación de .NET proporcionan una manera de almacenar y convertir datos de caracteres. No se deben usar
para almacenar datos binarios en formato de cadena. Dependiendo de la codificación empleada, la conversión de datos
binarios al formato de cadena con las clases de codificación puede presentar un comportamiento inesperado y mostrar datos
inexactos o dañados. Para convertir datos binarios en un formato de cadena, use el método Convert.ToBase64String .

.NET usa la codificación UTF -16 (representada por la clase UnicodeEncoding) para representar caracteres y
cadenas. Las aplicaciones cuyo destino es Common Language Runtime usan descodificadores para asignar
representaciones de caracteres Unicode admitidas por Common Language Runtime a otros esquemas de
codificación. Usan descodificadores para asignar caracteres de codificaciones no Unicode a Unicode.
Este tema consta de las siguientes secciones:
Codificaciones de .NET
Seleccionar una clase de codificación
Usar un objeto de codificación
Elegir una estrategia de reinterpretación
Implementing a Custom Fallback Strategy

Codificaciones de .NET
Todas las clases de codificación de caracteres de .NET heredan de la clase System.Text.Encoding, que es una clase
abstracta que define la funcionalidad común a todas las codificaciones de caracteres. Para acceder a los objetos
individuales de codificación implementados en .NET, haga lo siguiente:
Use las propiedades estáticas de la clase Encoding, que devuelven objetos que representan las
codificaciones de caracteres estándar disponibles en .NET (ASCII, UTF -7, UTF -8, UTF -16 y UTF -32). Por
ejemplo, la propiedad Encoding.Unicode devuelve un objeto UnicodeEncoding : Cada objeto usa la reserva
de reemplazo para controlar las cadenas que no puede codificar y los bytes que no puede descodificar. (Para
obtener más información, vea la sección Replacement Fallback ).
Llame al constructor de clase de la codificación. Se pueden crear instancias de los objetos para las
codificaciones ASCII, UTF -7, UTF -8, UTF -16 y UTF -32 de esta manera. De forma predeterminada, cada
objeto usa la reserva de reemplazo para controlar las cadenas que no puede codificar y los bytes que no
puede descodificar, pero puede especificar que se debe producir una excepción en su lugar. (Para obtener
más información, vea las secciones Replacement Fallback y Exception Fallback ).
Llame al constructor Encoding.Encoding(Int32) y pásele un entero que represente la codificación. Los
objetos de codificación estándar usan la reserva de reemplazo, y los objetos de codificación para la página
de códigos y el juego de caracteres de doble byte (DBCS ) usan el retroceso de ajuste perfecto para controlar
las cadenas que no pueden codificar y los bytes que no pueden descodificar. (Para obtener más información,
vea la sección Best-Fit Fallback ).
Llame al método Encoding.GetEncoding, que devuelve cualquier estándar, página de códigos o codificación
DBCS disponible en .NET. Las sobrecargas permiten especificar un objeto de reserva para el codificador y
para el descodificador.

NOTE
El estándar Unicode asigna un punto de código (un número) y un nombre a cada carácter en todos los scripts admitidos. Por
ejemplo, el carácter "A" está representado por el punto de código U+0041 y el nombre "LATIN CAPITAL LETTER A". Las
codificaciones de Formato de transformación Unicode (UTF) definen formas de codificar ese punto de código en una
secuencia de uno o más bytes. Un esquema de codificación Unicode simplifica el desarrollo de aplicaciones de uso
internacional porque permite que los caracteres de cualquier juego de caracteres estén representados en una única
codificación. Los desarrolladores de aplicaciones ya no tienen que realizar el seguimiento del esquema de codificación
empleado para producir caracteres para un idioma o un sistema de escritura concreto, y se pueden compartir los datos
internacionalmente entre sistemas sin dañarlos.
.NET admite tres codificaciones definidas por el estándar Unicode: UTF-8, UTF-16 y UTF-32. Para obtener más información,
vea el estándar Unicode en la página principal de Unicode.

Se puede recuperar información sobre todas las codificaciones disponibles en .NET llamando al método
Encoding.GetEncodings. .NET admite los sistemas de codificación de caracteres que se muestran en la tabla
siguiente.

CODIFICACIÓN CLASE DESCRIPCIÓN VENTAJAS Y DESVENTAJAS

ASCII ASCIIEncoding Codifica un intervalo Como esta codificación solo


limitado de caracteres admite valores de caracteres
usando los siete bits de U+0000 a U+007F, en la
inferiores de un byte. mayoría de los casos no
resulta suficiente para
aplicaciones de uso
internacional.
CODIFICACIÓN CLASE DESCRIPCIÓN VENTAJAS Y DESVENTAJAS

UTF-7 UTF7Encoding Representa los caracteres UTF-7 admite protocolos


como secuencias de como los protocolos de
caracteres ASCII de 7 bits. correo electrónico y de
Los caracteres Unicode no grupos de noticias. Sin
ASCII se representan con embargo, la codificación
una secuencia de escape de UTF-7 no es particularmente
caracteres ASCII. segura ni sólida. En algunos
casos, cambiar un bit puede
modificar radicalmente la
interpretación de toda una
cadena UTF-7. En otros
casos, diferentes cadenas
UTF-7 pueden codificar el
mismo texto. Para las
secuencias que incluyen
caracteres no ASCII, UTF-7
necesita más espacio que
UTF-8, y la codificación y
descodificación son más
lentas. Por tanto, debe usar
UTF-8 en lugar de UTF-7 si
es posible.

UTF-8 UTF8Encoding Representa cada punto de UTF-8 admite tamaños de


código Unicode como una datos de 8 bits y funciona
secuencia de uno a cuatro bien con muchos sistemas
bytes. operativos existentes. Para el
intervalo ASCII de caracteres,
UTF-8 es idéntico a la
codificación ASCII y permite
un conjunto mayor de
caracteres. Sin embargo,
para los scripts de Chino-
Japonés-Coreano (CJK), UTF-
8 puede necesitar tres bytes
para cada carácter y puede
generar tamaños de datos
mayores que UTF-16. Tenga
en cuenta que, algunas
veces, la cantidad de datos
ASCII, como las etiquetas
HTML, justifica el mayor
tamaño para el intervalo de
CJK.

UTF-16 UnicodeEncoding Representa cada punto de Common Language Runtime


código Unicode como una usa la codificación UTF-16
secuencia de uno o dos para representar valores de
enteros de 16 bits. La tipo Char y String , y el
mayoría de los caracteres sistema operativo Windows
Unicode comunes solo la usa para representar
necesitan un punto de valores de tipo WCHAR .
código UTF-16, aunque los
caracteres Unicode
suplementarios (U+10000 y
posteriores) necesitan dos
puntos de código UTF-16
suplentes. Se admiten tanto
el orden de bytes little-
endian como el big-endian.
CODIFICACIÓN CLASE DESCRIPCIÓN VENTAJAS Y DESVENTAJAS

UTF-32 UTF32Encoding Representa cada punto de La codificación UTF-32 se


código Unicode como un usa cuando las aplicaciones
entero de 32 bits. Se desean evitar el
admiten tanto el orden de comportamiento de punto
bytes little-endian como el de código suplente de la
big-endian. codificación UTF-16 en
sistemas operativos para los
que el espacio codificado es
muy importante. Los glifos
únicos representados en una
pantalla aún se pueden
codificar con más de un
carácter UTF-32.

Codificaciones ANSI/ISO Proporciona compatibilidad Una página de códigos


con diversas páginas de contiene 256 puntos de
códigos. En los sistemas código y se basa en cero. En
operativos Windows, las la mayoría de las páginas de
páginas de códigos se usan códigos, los puntos de
para admitir un idioma o un código 0 a 127 representan
grupo de idiomas concreto. el juego de caracteres ASCII
Para obtener una tabla que y los puntos de código 128 a
muestra las páginas de 255 difieren de forma
códigos admitidas por .NET, significativa entre las páginas
vea la clase Encoding. Puede de códigos. Por ejemplo, la
recuperar un objeto de página de códigos 1252
codificación para una página proporciona los caracteres
de códigos determinada para los sistemas de
llamando al método escritura latinos, incluidos el
Encoding.GetEncoding(Int32) inglés, el alemán y el francés.
. Los últimos 128 puntos de
código de la página de
códigos 1252 contienen los
caracteres de acento. La
página de códigos 1253
proporciona códigos de
caracteres necesarios en el
sistema de escritura griego.
Los últimos 128 puntos de
código de la página de
códigos 1253 contienen los
caracteres griegos. Como
resultado, una aplicación que
se basa en páginas de
códigos ANSI no puede
almacenar griego y alemán
en la misma secuencia de
texto a menos que incluya
un identificador que indique
la página de códigos a la que
se hace referencia.
CODIFICACIÓN CLASE DESCRIPCIÓN VENTAJAS Y DESVENTAJAS

Codificaciones de juegos de Admite idiomas que En un DBCS, un par de


caracteres de doble byte contienen más de 256 puntos de código (un byte
(DBCS) caracteres, como el chino, el doble) representa cada
japonés y el coreano. En un carácter. Cuando una
DBCS, un par de puntos de aplicación controla datos
código (un byte doble) DBCS, el primer byte de un
representa cada carácter. La carácter DBCS (el byte inicial)
propiedad se procesa junto con el byte
Encoding.IsSingleByte final que le sigue
devuelve false para las inmediatamente. Puesto que
codificaciones DBCS. Puede un único par de puntos de
recuperar un objeto de código de doble byte puede
codificación para un DBCS representar caracteres
determinado llamando al diferentes dependiendo de la
método página de códigos, este
Encoding.GetEncoding(Int32) esquema aún no permite la
. combinación de dos idioma,
como el japonés y el chino,
en el mismo flujo de datos.

Estas codificaciones permiten trabajar con caracteres Unicode, así como con codificaciones que son las más usadas
en aplicaciones heredadas. Además, puede crear una codificación personalizada definiendo una clase que se deriva
de Encoding e invalidar sus miembros.
Notas de la plataforma: .NET Core
De manera predeterminada, .NET Core no pone a disposición codificaciones de páginas de código que no sean la
página de códigos 28591 y las codificaciones Unicode, como UTF -8 y UTF -16. Sin embargo, puede agregar que las
codificaciones de páginas de código que se encuentran en las aplicaciones estándar de Windows que tienen como
destino .NET a la aplicación. Para obtener información completa, consulte el tema CodePagesEncodingProvider .

Seleccionar una clase de codificación


Si tiene la oportunidad de elegir la codificación que se usará en la aplicación, debe usar una codificación Unicode,
preferiblemente UTF8Encoding o UnicodeEncoding. (.NET también admite una tercera codificación Unicode,
UTF32Encoding).
Si piensa usar una codificación ASCII (ASCIIEncoding), elija UTF8Encoding en su lugar. Las dos codificaciones son
idénticas para el juego de caracteres ASCII, pero UTF8Encoding presenta las ventajas siguientes:
Puede representar todos los caracteres Unicode, mientras que ASCIIEncoding solo admite los valores de
caracteres Unicode entre U+0000 y U+007F.
Proporciona detección de errores y una mayor seguridad.
Se ha mejorado en materia de velocidad y debe ser más rápida que cualquier otra codificación. Incluso
cuando todo el contenido es ASCII, las operaciones realizadas con UTF8Encoding son más rápidas que las
operaciones realizadas con ASCIIEncoding.
Debe considerar la posibilidad de usar ASCIIEncoding solo para las aplicaciones heredadas. Sin embargo, incluso
para las aplicaciones heredadas, UTF8Encoding podría ser una opción mejor por las razones siguientes
(suponiendo la configuración predeterminada):
Si la aplicación tiene contenido que no es estrictamente ASCII y lo codifica con ASCIIEncoding, cada
carácter no ASCII se codifica como un signo de interrogación (?). Si la aplicación descodifica después estos
datos, la información se pierde.
Si la aplicación tiene contenido que no es estrictamente ASCII y lo codifica con UTF8Encoding, el resultado
parece ininteligible si se interpreta como ASCII. Sin embargo, si la aplicación usa un descodificador UTF -8
para descodificar estos datos, los datos realizan una acción de ida y vuelta correctamente.
En una aplicación web, los caracteres enviados al cliente como respuesta a una solicitud web deben reflejar la
codificación empleada en el cliente. En la mayoría de los casos, debe establecer la propiedad
HttpResponse.ContentEncoding en el valor devuelto por la propiedad HttpRequest.ContentEncoding para mostrar
el texto en la codificación que el usuario espera.

Usar un objeto de codificación


Un codificador convierte una cadena de caracteres (normalmente, caracteres Unicode) en su equivalente numérico
(bytes). Por ejemplo, podría usar un codificador ASCII para convertir caracteres Unicode en ASCII de forma que se
puedan mostrar en la consola. Para realizar la conversión, se llama al método Encoding.GetBytes . Si desea
determinar cuántos bytes son necesarios para almacenar los caracteres codificados antes de realizar la codificación,
puede llamar al método GetByteCount .
En el ejemplo siguiente se usa una única matriz de bytes para codificar cadenas en dos operaciones
independientes. Mantiene un índice que indica la posición inicial de la matriz de bytes para el siguiente conjunto de
bytes codificados con ASCII. Llama al método ASCIIEncoding.GetByteCount(String) para asegurarse de que la
matriz de bytes es suficiente para alojar la cadena codificada. A continuación, llama al método
ASCIIEncoding.GetBytes(String, Int32, Int32, Byte[], Int32) para codificar los caracteres de la cadena.
using System;
using System.Text;

public class Example


{
public static void Main()
{
string[] strings= { "This is the first sentence. ",
"This is the second sentence. " };
Encoding asciiEncoding = Encoding.ASCII;

// Create array of adequate size.


byte[] bytes = new byte[49];
// Create index for current position of array.
int index = 0;

Console.WriteLine("Strings to encode:");
foreach (var stringValue in strings) {
Console.WriteLine(" {0}", stringValue);

int count = asciiEncoding.GetByteCount(stringValue);


if (count + index >= bytes.Length)
Array.Resize(ref bytes, bytes.Length + 50);

int written = asciiEncoding.GetBytes(stringValue, 0,


stringValue.Length,
bytes, index);

index = index + written;


}
Console.WriteLine("\nEncoded bytes:");
Console.WriteLine("{0}", ShowByteValues(bytes, index));
Console.WriteLine();

// Decode Unicode byte array to a string.


string newString = asciiEncoding.GetString(bytes, 0, index);
Console.WriteLine("Decoded: {0}", newString);
}

private static string ShowByteValues(byte[] bytes, int last )


{
string returnString = " ";
for (int ctr = 0; ctr <= last - 1; ctr++) {
if (ctr % 20 == 0)
returnString += "\n ";
returnString += String.Format("{0:X2} ", bytes[ctr]);
}
return returnString;
}
}
// The example displays the following output:
// Strings to encode:
// This is the first sentence.
// This is the second sentence.
//
// Encoded bytes:
//
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
// 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
//
// Decoded: This is the first sentence. This is the second sentence.
Imports System.Text

Module Example
Public Sub Main()
Dim strings() As String = { "This is the first sentence. ",
"This is the second sentence. " }
Dim asciiEncoding As Encoding = Encoding.ASCII

' Create array of adequate size.


Dim bytes(50) As Byte
' Create index for current position of array.
Dim index As Integer = 0

Console.WriteLine("Strings to encode:")
For Each stringValue In strings
Console.WriteLine(" {0}", stringValue)

Dim count As Integer = asciiEncoding.GetByteCount(stringValue)


If count + index >= bytes.Length Then
Array.Resize(bytes, bytes.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetBytes(stringValue, 0,
stringValue.Length,
bytes, index)

index = index + written


Next
Console.WriteLine()
Console.WriteLine("Encoded bytes:")
Console.WriteLine("{0}", ShowByteValues(bytes, index))
Console.WriteLine()

' Decode Unicode byte array to a string.


Dim newString As String = asciiEncoding.GetString(bytes, 0, index)
Console.WriteLine("Decoded: {0}", newString)
End Sub

Private Function ShowByteValues(bytes As Byte(), last As Integer) As String


Dim returnString As String = " "
For ctr As Integer = 0 To last - 1
If ctr Mod 20 = 0 Then returnString += vbCrLf + " "
returnString += String.Format("{0:X2} ", bytes(ctr))
Next
Return returnString
End Function
End Module
' The example displays the following output:
' Strings to encode:
' This is the first sentence.
' This is the second sentence.
'
' Encoded bytes:
'
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20 54 68 69 73 20 69 73 20 74 68 65 20
' 73 65 63 6F 6E 64 20 73 65 6E 74 65 6E 63 65 2E 20
'
' Decoded: This is the first sentence. This is the second sentence.

Un descodificador convierte una matriz de bytes que refleja una codificación de caracteres determinada en un
juego de caracteres, ya sea en una matriz de caracteres o en una cadena. Para descodificar una matriz de bytes en
una matriz de caracteres, se llama al método Encoding.GetChars . Para descodificar una matriz de bytes en una
cadena, se llama al método GetString . Si desea determinar cuántos caracteres son necesarios para almacenar los
bytes descodificados antes de realizar la descodificación, puede llamar al método GetCharCount .
En el ejemplo siguiente se codifican tres cadenas y después se descodifican en una sola matriz de caracteres. Se
mantiene un índice que indica la posición inicial de la matriz de caracteres para el siguiente juego de caracteres
descodificados. Se llama al método GetCharCount para asegurarse de que la matriz de caracteres es
suficientemente grande para alojar todos los caracteres descodificados. A continuación, se llama al método
ASCIIEncoding.GetChars(Byte[], Int32, Int32, Char[], Int32) para descodificar la matriz de bytes.
using System;
using System.Text;

public class Example


{
public static void Main()
{
string[] strings = { "This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. " };
Encoding asciiEncoding = Encoding.ASCII;
// Array to hold encoded bytes.
byte[] bytes;
// Array to hold decoded characters.
char[] chars = new char[50];
// Create index for current position of character array.
int index = 0;

foreach (var stringValue in strings) {


Console.WriteLine("String to Encode: {0}", stringValue);
// Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue);
// Display the encoded bytes.
Console.Write("Encoded bytes: ");
for (int ctr = 0; ctr < bytes.Length; ctr++)
Console.Write(" {0}{1:X2}",
ctr % 20 == 0 ? Environment.NewLine : "",
bytes[ctr]);
Console.WriteLine();

// Decode the bytes to a single character array.


int count = asciiEncoding.GetCharCount(bytes);
if (count + index >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);

int written = asciiEncoding.GetChars(bytes, 0,


bytes.Length,
chars, index);
index = index + written;
Console.WriteLine();
}

// Instantiate a single string containing the characters.


string decodedString = new string(chars, 0, index - 1);
Console.WriteLine("Decoded string: ");
Console.WriteLine(decodedString);
}
}
// The example displays the following output:
// String to Encode: This is the first sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the second sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
// 65 6E 74 65 6E 63 65 2E 20
//
// String to Encode: This is the third sentence.
// Encoded bytes:
// 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
// 6E 74 65 6E 63 65 2E 20
//
// Decoded string:
// This is the first sentence. This is the second sentence. This is the third sentence.
Imports System.Text

Module Example
Public Sub Main()
Dim strings() As String = { "This is the first sentence. ",
"This is the second sentence. ",
"This is the third sentence. " }
Dim asciiEncoding As Encoding = Encoding.ASCII
' Array to hold encoded bytes.
Dim bytes() As Byte
' Array to hold decoded characters.
Dim chars(50) As Char
' Create index for current position of character array.
Dim index As Integer

For Each stringValue In strings


Console.WriteLine("String to Encode: {0}", stringValue)
' Encode the string to a byte array.
bytes = asciiEncoding.GetBytes(stringValue)
' Display the encoded bytes.
Console.Write("Encoded bytes: ")
For ctr As Integer = 0 To bytes.Length - 1
Console.Write(" {0}{1:X2}", If(ctr Mod 20 = 0, vbCrLf, ""),
bytes(ctr))
Next
Console.WriteLine()

' Decode the bytes to a single character array.


Dim count As Integer = asciiEncoding.GetCharCount(bytes)
If count + index >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
Dim written As Integer = asciiEncoding.GetChars(bytes, 0,
bytes.Length,
chars, index)
index = index + written
Console.WriteLine()
Next

' Instantiate a single string containing the characters.


Dim decodedString As New String(chars, 0, index - 1)
Console.WriteLine("Decoded string: ")
Console.WriteLine(decodedString)
End Sub
End Module
' The example displays the following output:
' String to Encode: This is the first sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 66 69 72 73 74 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the second sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 73 65 63 6F 6E 64 20 73
' 65 6E 74 65 6E 63 65 2E 20
'
' String to Encode: This is the third sentence.
' Encoded bytes:
' 54 68 69 73 20 69 73 20 74 68 65 20 74 68 69 72 64 20 73 65
' 6E 74 65 6E 63 65 2E 20
'
' Decoded string:
' This is the first sentence. This is the second sentence. This is the third sentence.

Los métodos de codificación y descodificación de una clase derivada de Encoding están diseñados para funcionar
en un conjunto completo de datos; es decir, todos los datos que se va a codificar o descodificar se proporciona en
una única llamada al método. Sin embargo, en algunos casos, los datos están disponibles en una secuencia y los
datos que se va a codificar o descodificar pueden estar disponibles solo desde operaciones de lectura
independientes. Para ello, la operación de codificación o descodificación debe recordar cualquier estado guardado
de su invocación anterior. Los métodos de clases derivadas de Encoder y Decoder pueden controlar las operaciones
de codificación y descodificación que abarcan varias llamadas a métodos.
Hay disponible un objeto Encoder para una codificación determinada desde la propiedad Encoding.GetEncoder de
esa codificación. Hay disponible un objeto Decoder para una codificación determinada desde la propiedad
Encoding.GetDecoder de esa codificación. Para las operaciones de descodificación, tenga en cuenta que las clases
derivadas de Decoder incluyen un método Decoder.GetChars , pero no tienen un método que se corresponda con
Encoding.GetString.
En el ejemplo siguiente se muestra la diferencia entre el uso de los métodos Encoding.GetChars y
Decoder.GetChars para descodificar una matriz de bytes Unicode. En el ejemplo se codifica una cadena que
contiene algunos caracteres Unicode en un archivo y, a continuación, se usan los dos métodos de descodificación
para descodificarlos de diez bytes en diez bytes. Puesto que hay un par suplente en los bytes décimo y undécimo,
se descodifica en llamadas a métodos independientes. Como muestra el resultado, el método Encoding.GetChars
no puede descodificar los bytes correctamente y, en su lugar, los reemplaza con U+FFFD (carácter de reemplazo).
Por otra parte, el método Decoder.GetChars puede descodificar correctamente la matriz de bytes para obtener la
cadena original.

using System;
using System.IO;
using System.Text;

public class Example


{
public static void Main()
{
// Use default replacement fallback for invalid encoding.
UnicodeEncoding enc = new UnicodeEncoding(true, false, false);

// Define a string with various Unicode characters.


string str1 = "AB YZ 19 \uD800\udc05 \u00e4";
str1 += "Unicode characters. \u00a9 \u010C s \u0062\u0308";
Console.WriteLine("Created original string...\n");

// Convert string to byte array.


byte[] bytes = enc.GetBytes(str1);

FileStream fs = File.Create(@".\characters.bin");
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();

// Read bytes from file.


FileStream fsIn = File.OpenRead(@".\characters.bin");
BinaryReader br = new BinaryReader(fsIn);

const int count = 10; // Number of bytes to read at a time.


byte[] bytesRead = new byte[10]; // Buffer (byte array).
int read; // Number of bytes actually read.
string str2 = String.Empty; // Decoded string.

// Try using Encoding object for all operations.


do {
read = br.Read(bytesRead, 0, count);
str2 += enc.GetString(bytesRead, 0, read);
} while (read == count);
br.Close();
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...");
CompareForEquality(str1, str2);
Console.WriteLine();
// Use Decoder for all operations.
fsIn = File.OpenRead(@".\characters.bin");
br = new BinaryReader(fsIn);
Decoder decoder = enc.GetDecoder();
char[] chars = new char[50];
int index = 0; // Next character to write in array.
int written = 0; // Number of chars written to array.
do {
read = br.Read(bytesRead, 0, count);
if (index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length)
Array.Resize(ref chars, chars.Length + 50);

written = decoder.GetChars(bytesRead, 0, read, chars, index);


index += written;
} while (read == count);
br.Close();
// Instantiate a string with the decoded characters.
string str3 = new String(chars, 0, index);
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...");
CompareForEquality(str1, str3);
}

private static void CompareForEquality(string original, string decoded)


{
bool result = original.Equals(decoded);
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal));
if (! result) {
Console.WriteLine("Code points in original string:");
foreach (var ch in original)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();

Console.WriteLine("Code points in decoded string:");


foreach (var ch in decoded)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
Console.WriteLine();
}
}
}
// The example displays the following output:
// Created original string...
//
// Decoded string using UnicodeEncoding.GetString()...
// original = decoded: False
// Code points in original string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
// Code points in decoded string:
// 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
// 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
// 0020 0073 0020 0062 0308
//
// Decoded string using UnicodeEncoding.Decoder.GetString()...
// original = decoded: True

Imports System.IO
Imports System.Text

Module Example
Public Sub Main()
' Use default replacement fallback for invalid encoding.
Dim enc As New UnicodeEncoding(True, False, False)

' Define a string with various Unicode characters.


Dim str1 As String = String.Format("AB YZ 19 {0}{1} {2}",
ChrW(&hD800), ChrW(&hDC05), ChrW(&h00e4))
str1 += String.Format("Unicode characters. {0} {1} s {2}{3}",
ChrW(&h00a9), ChrW(&h010C), ChrW(&h0062), ChrW(&h0308))
Console.WriteLine("Created original string...")
Console.WriteLine()

' Convert string to byte array.


Dim bytes() As Byte = enc.GetBytes(str1)

Dim fs As FileStream = File.Create(".\characters.bin")


Dim bw As New BinaryWriter(fs)
bw.Write(bytes)
bw.Close()

' Read bytes from file.


Dim fsIn As FileStream = File.OpenRead(".\characters.bin")
Dim br As New BinaryReader(fsIn)

Const count As Integer = 10 ' Number of bytes to read at a time.


Dim bytesRead(9) As Byte ' Buffer (byte array).
Dim read As Integer ' Number of bytes actually read.
Dim str2 As String = "" ' Decoded string.

' Try using Encoding object for all operations.


Do
read = br.Read(bytesRead, 0, count)
str2 += enc.GetString(bytesRead, 0, read)
Loop While read = count
br.Close()
Console.WriteLine("Decoded string using UnicodeEncoding.GetString()...")
CompareForEquality(str1, str2)
Console.WriteLine()

' Use Decoder for all operations.


fsIn = File.OpenRead(".\characters.bin")
br = New BinaryReader(fsIn)
Dim decoder As Decoder = enc.GetDecoder()
Dim chars(50) As Char
Dim index As Integer = 0 ' Next character to write in array.
Dim written As Integer = 0 ' Number of chars written to array.
Do
read = br.Read(bytesRead, 0, count)
If index + decoder.GetCharCount(bytesRead, 0, read) - 1 >= chars.Length Then
Array.Resize(chars, chars.Length + 50)
End If
written = decoder.GetChars(bytesRead, 0, read, chars, index)
index += written
Loop While read = count
br.Close()
' Instantiate a string with the decoded characters.
Dim str3 As New String(chars, 0, index)
Console.WriteLine("Decoded string using UnicodeEncoding.Decoder.GetString()...")
CompareForEquality(str1, str3)
End Sub

Private Sub CompareForEquality(original As String, decoded As String)


Dim result As Boolean = original.Equals(decoded)
Console.WriteLine("original = decoded: {0}",
original.Equals(decoded, StringComparison.Ordinal))
If Not result Then
Console.WriteLine("Code points in original string:")
For Each ch In original
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()

Console.WriteLine("Code points in decoded string:")


For Each ch In decoded
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Created original string...
'
' Decoded string using UnicodeEncoding.GetString()...
' original = decoded: False
' Code points in original string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 D800 DC05 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
' Code points in decoded string:
' 0041 0042 0020 0059 005A 0020 0031 0039 0020 FFFD FFFD 0020 00E4 0055 006E 0069 0063 006F
' 0064 0065 0020 0063 0068 0061 0072 0061 0063 0074 0065 0072 0073 002E 0020 00A9 0020 010C
' 0020 0073 0020 0062 0308
'
' Decoded string using UnicodeEncoding.Decoder.GetString()...
' original = decoded: True

Elegir una estrategia de reinterpretación


Cuando un método intenta codificar o descodificar un carácter pero no existe ninguna asignación, debe
implementar una estrategia de reserva que determine cómo se debe tratar la asignación incorrecta. Hay tres tipos
de estrategias de reserva:
Best-Fit Fallback
Replacement Fallback
Exception Fallback

IMPORTANT
Los problemas más frecuentes en las operaciones de codificación se producen cuando un carácter Unicode no se puede
asignar a una codificación determinada de la página de códigos. Los problemas más comunes de las operaciones de
descodificación se producen cuando las secuencias no válidas de bytes no se pueden traducir a caracteres Unicode válidos.
Por estas razones, debe saber qué estrategia de reserva emplea un determinado objeto de codificación. Siempre que sea
posible, debe especificar la estrategia de reserva usada por un objeto de codificación cuando se crea una instancia del objeto.

Best-Fit Fallback
Cuando un carácter no tiene una coincidencia exacta en la codificación de destino, el codificador puede intentar
asignarle a un carácter similar. (La reserva con ajuste perfecto es principalmente un problema de codificación en
lugar de un problema de descodificación. Hay muy pocas páginas de códigos que contengan caracteres que no se
puedan asignar correctamente a Unicode.) La reserva con ajuste perfecto es el valor predeterminado para las
codificaciones de páginas de códigos y de juegos de caracteres de doble byte recuperadas por las sobrecargas de
Encoding.GetEncoding(Int32) y Encoding.GetEncoding(String).

NOTE
En teoría, las clases de codificación Unicode proporcionadas en .NET (UTF8Encoding, UnicodeEncoding y UTF32Encoding)
admiten cada carácter de todos los juegos de caracteres, por lo que se pueden usar para eliminar los problemas de reserva
con ajuste perfecto.

Las estrategias de ajuste perfecto varían en páginas de códigos diferentes. Por ejemplo, para algunas páginas de
códigos, los caracteres latinos de ancho completo se asignarán a caracteres latinos de ancho medio, que son más
comunes. Para otras páginas de códigos no se realiza esta asignación. Incluso con una estrategia de ajuste perfecto
dinámica, algunos caracteres no tienen un ajuste imaginable en algunas codificaciones. Por ejemplo, un ideograma
chino no tiene ninguna asignación razonable a la página de códigos 1252. En este caso, se emplea una cadena de
reemplazo. De forma predeterminada, esta cadena es simplemente un carácter QUESTION MARK (U+003F ).

NOTE
Las estrategias de ajuste perfecto no están documentadas de forma detallada. Sin embargo, varias páginas de códigos se
documentan en el sitio web de Unicode Consortium. Revise el archivo Léame.txt de esa carpeta para obtener una
descripción de cómo interpretar los archivos de asignación.

En el ejemplo siguiente se usa la página de códigos 1252 (la página de códigos de Windows para los idiomas de
Europa occidental) para mostrar la asignación con ajuste perfecto y sus desventajas. El método
Encoding.GetEncoding(Int32) se usa para recuperar un objeto de codificación para la página de códigos 1252. De
forma predeterminada, usa una asignación con ajuste perfecto para los caracteres Unicode que no admite. En el
ejemplo se crea una instancia de una cadena que contiene tres caracteres no ASCII, CIRCLED LATIN CAPITAL
LETTER S (U+24C8), SUPERSCRIPT FIVE (U+2075) e INFINITY (U+221E ), separados por espacios en blanco.
Como muestra el resultado del ejemplo, cuando se codifica la cadena, los tres caracteres originales que no son
espacios en blanco se reemplazan con QUESTION MARK (U+003F ), DIGIT FIVE (U+0035) y DIGIT EIGHT
(U+0038). DIGIT EIGHT es un reemplazo especialmente deficiente para el carácter INFINITY no compatible y
QUESTION MARK indica que no había ninguna asignación disponible para el carácter original.
using System;
using System.Text;

public class Example


{
public static void Main()
{
// Get an encoding for code page 1252 (Western Europe character set).
Encoding cp1252 = Encoding.GetEncoding(1252);

// Define and display a string.


string str = "\u24c8 \u2075 \u221e";
Console.WriteLine("Original string: " + str);
Console.Write("Code points in string: ");
foreach (var ch in str)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine("\n");

// Encode a Unicode string.


Byte[] bytes = cp1252.GetBytes(str);
Console.Write("Encoded bytes: ");
foreach (byte byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");

// Decode the string.


string str2 = cp1252.GetString(bytes);
Console.WriteLine("String round-tripped: {0}", str.Equals(str2));
if (! str.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));
}
}
}
// The example displays the following output:
// Original string: Ⓢ ⁵ ∞
// Code points in string: 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 35 20 38
//
// String round-tripped: False
// ? 5 8
// 003F 0020 0035 0020 0038
Imports System.Text

Module Example
Public Sub Main()
' Get an encoding for code page 1252 (Western Europe character set).
Dim cp1252 As Encoding = Encoding.GetEncoding(1252)

' Define and display a string.


Dim str As String = String.Format("{0} {1} {2}", ChrW(&h24c8), ChrW(&H2075), ChrW(&h221E))
Console.WriteLine("Original string: " + str)
Console.Write("Code points in string: ")
For Each ch In str
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()

' Encode a Unicode string.


Dim bytes() As Byte = cp1252.GetBytes(str)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()

' Decode the string.


Dim str2 As String = cp1252.GetString(bytes)
Console.WriteLine("String round-tripped: {0}", str.Equals(str2))
If Not str.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
End If
End Sub
End Module
' The example displays the following output:
' Original string: Ⓢ ⁵ ∞
' Code points in string: 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 35 20 38
'
' String round-tripped: False
' ? 5 8
' 003F 0020 0035 0020 0038

La asignación con ajuste perfecto es el comportamiento predeterminado para un objeto Encoding que codifica los
datos Unicode en datos de página de códigos, y hay aplicaciones heredadas que se basan en este comportamiento.
Sin embargo, la mayoría de las aplicaciones nuevas deben evitarlo por razones de seguridad. Por ejemplo, las
aplicaciones no deben asignar nombres de dominio mediante una codificación con ajuste perfecto.

NOTE
También puede implementar una asignación personalizada de reserva con ajuste perfecto para una codificación. Para más
información, vea la sección Implementing a Custom Fallback Strategy .

Si la reserva con ajuste perfecto es el valor predeterminado para un objeto de codificación, puede elegir otra
estrategia de reserva cuando se recupera un objeto Encoding llamando a la sobrecarga de
Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) o Encoding.GetEncoding(String, EncoderFallback,
DecoderFallback) . La próxima sección incluye un ejemplo que reemplaza con un asterisco (*) cada carácter que no
se puede asignar a la página de códigos 1252.
using System;
using System.Text;

public class Example


{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));

string str1 = "\u24C8 \u2075 \u221E";


Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();

byte[] bytes = cp1252r.GetBytes(str1);


string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text

Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))

Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))


Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()

Dim bytes() As Byte = cp1252r.GetBytes(str1)


Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A

Replacement Fallback
Cuando un carácter no tiene una coincidencia exacta en el esquema de destino, pero no hay ningún carácter
adecuado al que se pueda asignar, la aplicación puede especificar un carácter o una cadena de reemplazo. Este es el
comportamiento predeterminado del descodificador Unicode, que reemplaza cualquier secuencia de dos bytes que
no pueda descodificar con REPLACEMENT_CHARACTER (U+FFFD ). También es el comportamiento
predeterminado de la clase ASCIIEncoding , que reemplaza cada carácter que no puede codificar o descodificar con
un signo de interrogación. En el ejemplo siguiente se muestra el reemplazo de caracteres para la cadena Unicode
del ejemplo anterior. Como muestra el resultado, cada carácter que no se puede descodificar en un valor de bytes
ASCII se reemplaza con 0x3F, que es el código ASCII de un signo de interrogación.
using System;
using System.Text;

public class Example


{
public static void Main()
{
Encoding enc = Encoding.ASCII;

string str1 = "\u24C8 \u2075 \u221E";


Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine("\n");

// Encode the original string using the ASCII encoder.


byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);
Console.WriteLine("\n");

// Decode the ASCII bytes.


string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Encoded bytes: 3F 20 3F 20 3F
//
// Round-trip: False
// ? ? ?
// 003F 0020 003F 0020 003F
Imports System.Text

Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.Ascii

Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))


Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()

' Encode the original string using the ASCII encoder.


Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()

' Decode the ASCII bytes.


Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Encoded bytes: 3F 20 3F 20 3F
'
' Round-trip: False
' ? ? ?
' 003F 0020 003F 0020 003F

.NET incluye las clases EncoderReplacementFallback y DecoderReplacementFallback, que sustituyen una cadena de
reemplazo si un carácter no se asigna exactamente en una operación de codificación o descodificación. De forma
predeterminada, esta cadena de reemplazo es un signo de interrogación, pero puede llamar a una sobrecarga del
constructor de clase para elegir otra cadena diferente. Normalmente, la cadena de reemplazo es un carácter único,
aunque esto no es un requisito. En el ejemplo siguiente se cambia el comportamiento del codificador de la página
de códigos 1252 creando una instancia de un objeto EncoderReplacementFallback que usa un asterisco (*) como
cadena de reemplazo.
using System;
using System.Text;

public class Example


{
public static void Main()
{
Encoding cp1252r = Encoding.GetEncoding(1252,
new EncoderReplacementFallback("*"),
new DecoderReplacementFallback("*"));

string str1 = "\u24C8 \u2075 \u221E";


Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();

byte[] bytes = cp1252r.GetBytes(str1);


string str2 = cp1252r.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();
}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
// Round-trip: False
// * * *
// 002A 0020 002A 0020 002A
Imports System.Text

Module Example
Public Sub Main()
Dim cp1252r As Encoding = Encoding.GetEncoding(1252,
New EncoderReplacementFallback("*"),
New DecoderReplacementFallback("*"))

Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))


Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()

Dim bytes() As Byte = cp1252r.GetBytes(str1)


Dim str2 As String = cp1252r.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
' Round-trip: False
' * * *
' 002A 0020 002A 0020 002A

NOTE
También puede implementar una clase de reemplazo para una codificación. Para más información, vea la sección
Implementing a Custom Fallback Strategy .

Además de QUESTION MARK (U+003F ), el REPLACEMENT CHARACTER de Unicode (U+FFFD ) se suele usar
como cadena de reemplazo, especialmente al descodificar secuencias de bytes que no se puede traducir
correctamente a caracteres Unicode. Sin embargo, se puede elegir cualquier cadena de reemplazo y esta puede
contener varios caracteres.
Exception Fallback
En lugar de proporcionar una reserva con ajuste perfecto o una cadena de reemplazo, un codificador puede
producir EncoderFallbackException si no puede codificar un juego de caracteres y un descodificador puede
producir DecoderFallbackException si no puede descodificar una matriz de bytes. Para producir una excepción en
operaciones de codificación y descodificación, se proporciona un objeto EncoderExceptionFallback y un objeto
DecoderExceptionFallback , respectivamente, al método Encoding.GetEncoding(String, EncoderFallback,
DecoderFallback) . En el ejemplo siguiente se muestra la reserva de excepción con la clase ASCIIEncoding .

using System;
using System.Text;

public class Example


{
public static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii",
new EncoderExceptionFallback(),
new EncoderExceptionFallback(),
new DecoderExceptionFallback());

string str1 = "\u24C8 \u2075 \u221E";


Console.WriteLine(str1);
foreach (var ch in str1)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine("\n");

// Encode the original string using the ASCII encoder.


byte[] bytes = {};
try {
bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);

Console.WriteLine();
}
catch (EncoderFallbackException e) {
Console.Write("Exception: ");
if (e.IsUnknownSurrogate())
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index);
else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index);
return;
}
Console.WriteLine();

// Decode the ASCII bytes.


try {
string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();
}
}
catch (DecoderFallbackException e) {
Console.Write("Unable to decode byte(s) ");
foreach (byte unknown in e.BytesUnknown)
Console.Write("0x{0:X2} ");

Console.WriteLine("at index {0}", e.Index);


}
}
}
// The example displays the following output:
// Ⓢ ⁵ ∞
// 24C8 0020 2075 0020 221E
//
// Exception: Unable to encode 0x24C8 at index 0.
Imports System.Text

Module Example
Public Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii",
New EncoderExceptionFallback(),
New DecoderExceptionFallback())

Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&h24C8), ChrW(&h2075), ChrW(&h221E))


Console.WriteLine(str1)
For Each ch In str1
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
Console.WriteLine()

' Encode the original string using the ASCII encoder.


Dim bytes() As Byte = {}
Try
bytes = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Catch e As EncoderFallbackException
Console.Write("Exception: ")
If e.IsUnknownSurrogate() Then
Console.WriteLine("Unable to encode surrogate pair 0x{0:X4} 0x{1:X3} at index {2}.",
Convert.ToUInt16(e.CharUnknownHigh),
Convert.ToUInt16(e.CharUnknownLow),
e.Index)
Else
Console.WriteLine("Unable to encode 0x{0:X4} at index {1}.",
Convert.ToUInt16(e.CharUnknown),
e.Index)
End If
Exit Sub
End Try
Console.WriteLine()

' Decode the ASCII bytes.


Try
Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
Catch e As DecoderFallbackException
Console.Write("Unable to decode byte(s) ")
For Each unknown As Byte In e.BytesUnknown
Console.Write("0x{0:X2} ")
Next
Console.WriteLine("at index {0}", e.Index)
End Try
End Sub
End Module
' The example displays the following output:
' Ⓢ ⁵ ∞
' 24C8 0020 2075 0020 221E
'
' Exception: Unable to encode 0x24C8 at index 0.
NOTE
También puede implementar un controlador de excepciones personalizado para una operación de codificación. Para más
información, vea la sección Implementing a Custom Fallback Strategy .

Los objetos EncoderFallbackException y DecoderFallbackException proporcionan la siguiente información acerca


de la condición que provocó la excepción:
El objeto EncoderFallbackException incluye un método IsUnknownSurrogate , que indica si el carácter o los
caracteres que no se pueden codificar representan un par suplente desconocido (en este caso, el método
devuelve true ) o un único carácter desconocido (en este caso, el método devuelve false ). Los caracteres
del par suplente están disponibles a partir de las propiedades EncoderFallbackException.CharUnknownHigh
y EncoderFallbackException.CharUnknownLow . El carácter único desconocido está disponible en la
propiedad EncoderFallbackException.CharUnknown . La propiedad EncoderFallbackException.Index indica la
posición de la cadena en la que se encontró el primer carácter que no se pudo codificar.
El objeto DecoderFallbackException incluye una propiedad BytesUnknown que devuelve una matriz de
bytes que no se pueden descodificar. La propiedad DecoderFallbackException.Index indica la posición inicial
de los bytes desconocidos.
Aunque los objetos EncoderFallbackException y DecoderFallbackException proporcionan información suficiente de
diagnóstico sobre la excepción, no proporcionan acceso al búfer de codificación o descodificación. Por tanto, no
permiten reemplazar o corregir datos no válidos dentro del método de codificación o descodificación.

Implementing a Custom Fallback Strategy


Además de la asignación con ajuste perfecto implementada internamente por las páginas de códigos, .NET incluye
las siguientes clases para implementar una estrategia de reserva:
Use EncoderReplacementFallback y EncoderReplacementFallbackBuffer para reemplazar caracteres en
operaciones de codificación.
Use DecoderReplacementFallback y DecoderReplacementFallbackBuffer para reemplazar caracteres en
operaciones de descodificación.
Use EncoderExceptionFallback y EncoderExceptionFallbackBuffer para producir EncoderFallbackException
cuando un carácter no se puede codificar.
Use DecoderExceptionFallback y DecoderExceptionFallbackBuffer para producir DecoderFallbackException
cuando un carácter no se puede descodificar.
Además, puede implementar una solución personalizada que use reserva con ajuste perfecto, reserva de
reemplazo o reserva de excepción siguiendo estos pasos:
1. Derive una clase de EncoderFallback para las operaciones de codificación y de DecoderFallback para las
operaciones de descodificación.
2. Derive una clase de EncoderFallbackBuffer para las operaciones de codificación y de DecoderFallbackBuffer
para las operaciones de descodificación.
3. Para la reserva de excepción, si las clases EncoderFallbackException y DecoderFallbackException
predefinidas no satisfacen sus necesidades, derive una clase de un objeto de excepción como Exception o
ArgumentException.
Derivar de EncoderFallback o DecoderFallback
Para implementar una solución de reserva personalizada, debe crear una clase que herede de EncoderFallback para
las operaciones de codificación y de DecoderFallback para las operaciones de descodificación. Las instancias de
estas clases se pasan al método Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) y actúan como
intermediario entre la clase de codificación y la implementación de reserva.
Cuando se crea una solución de reserva personalizada para un codificador o un descodificador, debe implementar
los miembros siguientes:
La propiedad EncoderFallback.MaxCharCount o DecoderFallback.MaxCharCount , que devuelve el número
máximo de caracteres posible que el reemplazo con mejor ajuste o la reserva de excepción pueda devolver
para reemplazar un único carácter. En el caso de la reserva de excepción personalizada, su valor es cero.
El método EncoderFallback.CreateFallbackBuffer o DecoderFallback.CreateFallbackBuffer , que devuelve una
implementación personalizada de EncoderFallbackBuffer o DecoderFallbackBuffer . El codificador llama al
método cuando encuentra el primer carácter que no puede codificar correctamente o lo llama el
decodificador cuando encuentra el primer byte que no puede descodificar correctamente.
Derivar de EncoderFallbackBuffer o DecoderFallbackBuffer
Para implementar una solución de reserva personalizada, debe crear también una clase que herede de
EncoderFallbackBuffer para las operaciones de codificación y de DecoderFallbackBuffer para las operaciones de
descodificación. El método CreateFallbackBuffer de las clases EncoderFallback y DecoderFallback devuelve
instancias de estas clases. El codificador llama al método EncoderFallback.CreateFallbackBuffer cuando encuentra
el primer carácter que no puede codificar y el descodificador llama al método
DecoderFallback.CreateFallbackBuffer cuando encuentra uno o más bytes que no puede descodificar. Las clases
EncoderFallbackBuffer y DecoderFallbackBuffer proporcionan la implementación de reserva. Cada instancia
representa un búfer que contiene los caracteres de reserva que reemplazarán el carácter que no se puede codificar
o la secuencia de bytes que no se puede descodificar.
Cuando se crea una solución de reserva personalizada para un codificador o un descodificador, debe implementar
los miembros siguientes:
El método EncoderFallbackBuffer.Fallback o DecoderFallbackBuffer.Fallback . El codificador llama
aEncoderFallbackBuffer.Fallback para proporcionar el búfer de reserva con información sobre el carácter
que no puede codificar. Puesto que el carácter que se va a codificar puede ser un par suplente, este método
está sobrecargado. Se pasa a una sobrecarga el carácter que se va a codificar y su índice en la cadena. A la
segunda sobrecarga se le pasa el suplente máximo y mínimo junto con su índice en la cadena. El
descodificador llama al método DecoderFallbackBuffer.Fallback para proporcionar el búfer de reserva con
información sobre los bytes que no puede descodificar. Se pasa a este método una matriz de bytes que no
puede descodificar, junto con el índice del primer byte. El método de reserva debe devolver true si el búfer
de reserva puede proporcionar un carácter o caracteres de mejor ajuste o de reemplazo; de lo contrario,
debe devolver false . En el caso de una reserva de excepción, el método de reserva debe producir una
excepción.
El método EncoderFallbackBuffer.GetNextChar o DecoderFallbackBuffer.GetNextChar , al que llama
repetidamente el codificador o el descodificador para obtener el siguiente carácter del búfer de reserva.
Cuando se han devuelto todos los caracteres de reserva, el método debe devolver U+0000.
La propiedad EncoderFallbackBuffer.Remaining o DecoderFallbackBuffer.Remaining , que devuelve el
número de caracteres que permanecen en el búfer de reserva.
El método EncoderFallbackBuffer.MovePrevious o DecoderFallbackBuffer.MovePrevious , que mueve la
posición actual en el búfer de reserva al carácter anterior.
El método EncoderFallbackBuffer.Reset o DecoderFallbackBuffer.Reset , que se reinicializa el búfer de
reserva.
Si la implementación de reserva es una reserva con ajuste perfecto o una reserva de reemplazo, las clases
derivadas de EncoderFallbackBuffer y DecoderFallbackBuffer también mantienen dos campos de instancia
privados: el número exacto de caracteres del búfer y el índice del carácter siguiente del búfer que se va a devolver.
Ejemplo de EncoderFallback
En un ejemplo anterior se usaba la reserva de reemplazo para reemplazar caracteres Unicode que no
correspondían a caracteres ASCII con un asterisco (*). En el ejemplo siguiente se usa una implementación
personalizada de reserva con ajuste perfecto en su lugar para proporcionar una mejor asignación de caracteres no
ASCII.
En el código siguiente se define una clase denominada CustomMapper que se deriva de EncoderFallback para
controlar la asignación con ajuste perfecto de caracteres no ASCII. Su método CreateFallbackBuffer devuelve un
objeto CustomMapperFallbackBuffer , que proporciona la implementación de EncoderFallbackBuffer . La clase
CustomMapper usa un objeto Dictionary<TKey,TValue> para almacenar las asignaciones de caracteres Unicode no
compatibles (el valor de clave) y sus caracteres de 8 bits correspondientes (que se almacenan en dos bytes
consecutivos en un entero de 64 bits). Para que esta asignación esté disponible para el búfer de reserva, la instancia
de CustomMapper se pasa como un parámetro al constructor de clase CustomMapperFallbackBuffer . Puesto que la
asignación más larga es la cadena "INF" por el carácter Unicode U+221E, la propiedad MaxCharCount devuelve 3.

public class CustomMapper : EncoderFallback


{
public string DefaultString;
internal Dictionary<ushort, ulong> mapping;

public CustomMapper() : this("*")


{
}

public CustomMapper(string defaultString)


{
this.DefaultString = defaultString;

// Create table of mappings


mapping = new Dictionary<ushort, ulong>();
mapping.Add(0x24C8, 0x53);
mapping.Add(0x2075, 0x35);
mapping.Add(0x221E, 0x49004E0046);
}

public override EncoderFallbackBuffer CreateFallbackBuffer()


{
return new CustomMapperFallbackBuffer(this);
}

public override int MaxCharCount


{
get { return 3; }
}
}
Public Class CustomMapper : Inherits EncoderFallback
Public DefaultString As String
Friend mapping As Dictionary(Of UShort, ULong)

Public Sub New()


Me.New("?")
End Sub

Public Sub New(ByVal defaultString As String)


Me.DefaultString = defaultString

' Create table of mappings


mapping = New Dictionary(Of UShort, ULong)
mapping.Add(&H24C8, &H53)
mapping.Add(&H2075, &H35)
mapping.Add(&H221E, &H49004E0046)
End Sub

Public Overrides Function CreateFallbackBuffer() As System.Text.EncoderFallbackBuffer


Return New CustomMapperFallbackBuffer(Me)
End Function

Public Overrides ReadOnly Property MaxCharCount As Integer


Get
Return 3
End Get
End Property
End Class

En el código siguiente se define la clase CustomMapperFallbackBuffer , que se deriva de EncoderFallbackBuffer. El


diccionario que contiene las asignaciones con ajuste perfecto y que se define en la instancia de CustomMapper está
disponible desde su constructor de clase. Su método Fallback devuelve true si cualquiera de los caracteres
Unicode que el codificador ASCII no puede codificar se definen en el diccionario de asignación; de lo contrario,
devuelve false . Para cada reserva, la variable count privada indica el número de caracteres que quedan por
devolver y la variable index privada indica la posición en el búfer de cadena, charsToReturn , del siguiente carácter
que se va a devolver.

public class CustomMapperFallbackBuffer : EncoderFallbackBuffer


{
int count = -1; // Number of characters to return
int index = -1; // Index of character to return
CustomMapper fb;
string charsToReturn;

public CustomMapperFallbackBuffer(CustomMapper fallback)


{
this.fb = fallback;
}

public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)


{
// Do not try to map surrogates to ASCII.
return false;
}

public override bool Fallback(char charUnknown, int index)


{
// Return false if there are already characters to map.
if (count >= 1) return false;

// Determine number of characters to return.


charsToReturn = String.Empty;

ushort key = Convert.ToUInt16(charUnknown);


ushort key = Convert.ToUInt16(charUnknown);
if (fb.mapping.ContainsKey(key)) {
byte[] bytes = BitConverter.GetBytes(fb.mapping[key]);
int ctr = 0;
foreach (var byt in bytes) {
if (byt > 0) {
ctr++;
charsToReturn += (char) byt;
}
}
count = ctr;
}
else {
// Return default.
charsToReturn = fb.DefaultString;
count = 1;
}
this.index = charsToReturn.Length - 1;

return true;
}

public override char GetNextChar()


{
// We'll return a character if possible, so subtract from the count of chars to return.
count--;
// If count is less than zero, we've returned all characters.
if (count < 0)
return '\u0000';

this.index--;
return charsToReturn[this.index + 1];
}

public override bool MovePrevious()


{
// Original: if count >= -1 and pos >= 0
if (count >= -1) {
count++;
return true;
}
else {
return false;
}
}

public override int Remaining


{
get { return count < 0 ? 0 : count; }
}

public override void Reset()


{
count = -1;
index = -1;
}
}

Public Class CustomMapperFallbackBuffer : Inherits EncoderFallbackBuffer

Dim count As Integer = -1 ' Number of characters to return


Dim index As Integer = -1 ' Index of character to return
Dim fb As CustomMapper
Dim charsToReturn As String

Public Sub New(ByVal fallback As CustomMapper)


MyBase.New()
Me.fb = fallback
End Sub

Public Overloads Overrides Function Fallback(ByVal charUnknownHigh As Char, ByVal charUnknownLow As Char,
ByVal index As Integer) As Boolean
' Do not try to map surrogates to ASCII.
Return False
End Function

Public Overloads Overrides Function Fallback(ByVal charUnknown As Char, ByVal index As Integer) As Boolean
' Return false if there are already characters to map.
If count >= 1 Then Return False

' Determine number of characters to return.


charsToReturn = String.Empty

Dim key As UShort = Convert.ToUInt16(charUnknown)


If fb.mapping.ContainsKey(key) Then
Dim bytes() As Byte = BitConverter.GetBytes(fb.mapping.Item(key))
Dim ctr As Integer
For Each byt In bytes
If byt > 0 Then
ctr += 1
charsToReturn += Chr(byt)
End If
Next
count = ctr
Else
' Return default.
charsToReturn = fb.DefaultString
count = 1
End If
Me.index = charsToReturn.Length - 1

Return True
End Function

Public Overrides Function GetNextChar() As Char


' We'll return a character if possible, so subtract from the count of chars to return.
count -= 1
' If count is less than zero, we've returned all characters.
If count < 0 Then Return ChrW(0)

Me.index -= 1
Return charsToReturn(Me.index + 1)
End Function

Public Overrides Function MovePrevious() As Boolean


' Original: if count >= -1 and pos >= 0
If count >= -1 Then
count += 1
Return True
Else
Return False
End If
End Function

Public Overrides ReadOnly Property Remaining As Integer


Get
Return If(count < 0, 0, count)
End Get
End Property

Public Overrides Sub Reset()


count = -1
index = -1
End Sub
End Class
En el código siguiente se crean instancias del objeto CustomMapper y se pasa una instancia del mismo al método
Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) . El resultado indica que la implementación de
reserva con ajuste perfecto controla correctamente los tres caracteres no ASCII de la cadena original.

using System;
using System.Collections.Generic;
using System.Text;

class Program
{
static void Main()
{
Encoding enc = Encoding.GetEncoding("us-ascii", new CustomMapper(), new DecoderExceptionFallback());

string str1 = "\u24C8 \u2075 \u221E";


Console.WriteLine(str1);
for (int ctr = 0; ctr <= str1.Length - 1; ctr++) {
Console.Write("{0} ", Convert.ToUInt16(str1[ctr]).ToString("X4"));
if (ctr == str1.Length - 1)
Console.WriteLine();
}
Console.WriteLine();

// Encode the original string using the ASCII encoder.


byte[] bytes = enc.GetBytes(str1);
Console.Write("Encoded bytes: ");
foreach (var byt in bytes)
Console.Write("{0:X2} ", byt);

Console.WriteLine("\n");

// Decode the ASCII bytes.


string str2 = enc.GetString(bytes);
Console.WriteLine("Round-trip: {0}", str1.Equals(str2));
if (! str1.Equals(str2)) {
Console.WriteLine(str2);
foreach (var ch in str2)
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"));

Console.WriteLine();
}
}
}
Imports System.Text
Imports System.Collections.Generic

Module Module1

Sub Main()
Dim enc As Encoding = Encoding.GetEncoding("us-ascii", New CustomMapper(), New
DecoderExceptionFallback())

Dim str1 As String = String.Format("{0} {1} {2}", ChrW(&H24C8), ChrW(&H2075), ChrW(&H221E))


Console.WriteLine(str1)
For ctr As Integer = 0 To str1.Length - 1
Console.Write("{0} ", Convert.ToUInt16(str1(ctr)).ToString("X4"))
If ctr = str1.Length - 1 Then Console.WriteLine()
Next
Console.WriteLine()

' Encode the original string using the ASCII encoder.


Dim bytes() As Byte = enc.GetBytes(str1)
Console.Write("Encoded bytes: ")
For Each byt In bytes
Console.Write("{0:X2} ", byt)
Next
Console.WriteLine()
Console.WriteLine()

' Decode the ASCII bytes.


Dim str2 As String = enc.GetString(bytes)
Console.WriteLine("Round-trip: {0}", str1.Equals(str2))
If Not str1.Equals(str2) Then
Console.WriteLine(str2)
For Each ch In str2
Console.Write("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Console.WriteLine()
End If
End Sub
End Module

Vea también
Encoder
Decoder
DecoderFallback
Encoding
EncoderFallback
Globalización y localización
Analizar cadenas en .NET
04/11/2019 • 2 minutes to read • Edit Online

Una operación de análisis convierte una cadena que representa un tipo base de .NET en dicho tipo base. Por
ejemplo, se usa una operación de análisis para convertir una cadena en un número de punto flotante o un valor
de fecha y hora. El método que se usa normalmente para realizar una operación de análisis es el método Parse .
Dado que el análisis es la operación inversa del formato (lo que implica convertir un tipo base en su
representación de cadena), se aplican muchas de las mismas reglas y convenciones. Del mismo modo que el
formato usa un objeto que implementa la interfaz IFormatProvider para proporcionar información de formato
según la referencia cultural, el análisis también usa un objeto que implementa la interfaz IFormatProvider para
determinar cómo se interpreta una representación de cadena. Para obtener más información, consulte Aplicar
formato a tipos.

En esta sección
Análisis de cadenas numéricas
Se describe cómo convertir cadenas en tipos numéricos de .NET.
Análisis de cadenas de fecha y hora
Se describe cómo convertir cadenas en tipos DateTime de .NET.
Análisis de otras cadenas
Se describe cómo convertir cadenas en tipos carácter, booleano y enumeración.

Secciones relacionadas
Aplicación de formato a tipos
Se describen los conceptos de formato básicos, como especificadores de formato y proveedores de formato.
Conversión de tipos en .NET
Se describe cómo convertir tipos.
Tipos base
Se describen las operaciones comunes que se pueden realizar en tipos base de .NET.
Analizar cadenas numéricas en .NET
04/11/2019 • 13 minutes to read • Edit Online

Todos los tipos numéricos tienen dos métodos de análisis estáticos, Parse y TryParse , que puede usar para
convertir la representación de cadena de un número en un tipo numérico. Estos métodos permiten analizar
cadenas generadas mediante el uso de las cadenas de formato que se documentan en Cadenas con formato
numérico estándar y Cadenas con formato numérico personalizado. De forma predeterminada, los métodos
Parse y TryParse pueden convertir correctamente las cadenas que contienen dígitos decimales enteros solo en
valores enteros. Pueden convertir correctamente las cadenas que contienen dígitos decimales enteros y
fraccionarios, separadores de grupos y un separador decimal en valores de punto flotante. El método Parse
produce una excepción si se produce un error en la operación, mientras que el método TryParse devuelve false .

Análisis y proveedores de formato


Normalmente, las representaciones de cadena de valores numéricos se diferencian en la referencia cultural. Todos
los elementos de las cadenas numéricas, como los símbolos de moneda, los separadores de grupo (o millares) y
los separadores decimales, varían según la referencia cultural. Los métodos de análisis usan implícita o
explícitamente un proveedor de formato que reconoce estas variaciones específicas de la referencia cultural. Si no
se especifica ningún proveedor de formato en una llamada al método Parse o TryParse , se usa el proveedor de
formato asociado a la referencia cultural del subproceso actual (el objeto NumberFormatInfo devuelto por la
propiedad NumberFormatInfo.CurrentInfo).
Un proveedor de formato se representa mediante una implementación IFormatProvider. Esta interfaz tiene un solo
miembro, el método GetFormat, cuyo único parámetro es un objeto Type que representa el tipo al que se va a dar
formato. Este método devuelve el objeto que proporciona información de formato. .NET es compatible con las dos
implementaciones IFormatProvider siguientes para analizar cadenas numéricas:
Un objeto CultureInfo cuyo método CultureInfo.GetFormat devuelve un objeto NumberFormatInfo que
proporciona información de formato específica de la referencia cultural.
Un objeto NumberFormatInfo cuyo método NumberFormatInfo.GetFormat se devuelve a sí mismo.
En el ejemplo siguiente se intenta convertir cada cadena de una matriz en un valor Double. Primero se intenta
analizar la cadena mediante un proveedor de formato que refleja las convenciones de la referencia cultural Inglés
(Estados Unidos). Si esta operación produce una excepción FormatException, se intenta analizar la cadena
mediante un proveedor de formato que refleja las convenciones de la referencia cultural Francés (Francia).
using System;
using System.Globalization;

public class Example


{
public static void Main()
{
string[] values = { "1,304.16", "$1,456.78", "1,094", "152",
"123,45 €", "1 304,16", "Ae9f" };
double number;
CultureInfo culture = null;

foreach (string value in values) {


try {
culture = CultureInfo.CreateSpecificCulture("en-US");
number = Double.Parse(value, culture);
Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number);
}
catch (FormatException) {
Console.WriteLine("{0}: Unable to parse '{1}'.",
culture.Name, value);
culture = CultureInfo.CreateSpecificCulture("fr-FR");
try {
number = Double.Parse(value, culture);
Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number);
}
catch (FormatException) {
Console.WriteLine("{0}: Unable to parse '{1}'.",
culture.Name, value);
}
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// en-US: 1,304.16 --> 1304.16
//
// en-US: Unable to parse '$1,456.78'.
// fr-FR: Unable to parse '$1,456.78'.
//
// en-US: 1,094 --> 1094
//
// en-US: 152 --> 152
//
// en-US: Unable to parse '123,45 €'.
// fr-FR: Unable to parse '123,45 €'.
//
// en-US: Unable to parse '1 304,16'.
// fr-FR: 1 304,16 --> 1304.16
//
// en-US: Unable to parse 'Ae9f'.
// fr-FR: Unable to parse 'Ae9f'.
Imports System.Globalization

Module Example
Public Sub Main()
Dim values() As String = { "1,304.16", "$1,456.78", "1,094", "152",
"123,45 €", "1 304,16", "Ae9f" }
Dim number As Double
Dim culture As CultureInfo = Nothing

For Each value As String In values


Try
culture = CultureInfo.CreateSpecificCulture("en-US")
number = Double.Parse(value, culture)
Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number)
Catch e As FormatException
Console.WriteLine("{0}: Unable to parse '{1}'.",
culture.Name, value)
culture = CultureInfo.CreateSpecificCulture("fr-FR")
Try
number = Double.Parse(value, culture)
Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number)
Catch ex As FormatException
Console.WriteLine("{0}: Unable to parse '{1}'.",
culture.Name, value)
End Try
End Try
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' en-US: 1,304.16 --> 1304.16
'
' en-US: Unable to parse '$1,456.78'.
' fr-FR: Unable to parse '$1,456.78'.
'
' en-US: 1,094 --> 1094
'
' en-US: 152 --> 152
'
' en-US: Unable to parse '123,45 €'.
' fr-FR: Unable to parse '123,45 €'.
'
' en-US: Unable to parse '1 304,16'.
' fr-FR: 1 304,16 --> 1304.16
'
' en-US: Unable to parse 'Ae9f'.
' fr-FR: Unable to parse 'Ae9f'.

Análisis y valores NumberStyles


Los elementos de estilo (como espacio en blanco, separadores de grupos y separador decimal) que la operación de
análisis puede controlar se definen mediante un valor de enumeración NumberStyles. De forma predeterminada,
las cadenas que representan valores enteros se analizan mediante el valor NumberStyles.Integer, que solo permite
dígitos numéricos, espacio en blanco inicial y final, y un signo inicial. Las cadenas que representan valores de punto
flotante se analizan mediante una combinación de valores NumberStyles.Float y NumberStyles.AllowThousands.
Este estilo compuesto permite dígitos decimales junto con un espacio en blanco inicial y final, un signo inicial, un
separador decimal, separador de grupos y un exponente. Al llamar a una sobrecarga del método Parse o
TryParse que incluya un parámetro de tipo NumberStyles y configurar una o más marcas NumberStyles, puede
controlar los elementos de estilo que pueden estar presentes en la cadena para que la operación de análisis se
realice correctamente.
Por ejemplo, una cadena que contiene un separador de grupos no puede convertirse en un valor Int32 mediante el
método Int32.Parse(String). Pero la conversión se realiza correctamente si usa la marca
NumberStyles.AllowThousands, como se muestra en el ejemplo siguiente.

using System;
using System.Globalization;

public class Example


{
public static void Main()
{
string value = "1,304";
int number;
IFormatProvider provider = CultureInfo.CreateSpecificCulture("en-US");
if (Int32.TryParse(value, out number))
Console.WriteLine("{0} --> {1}", value, number);
else
Console.WriteLine("Unable to convert '{0}'", value);

if (Int32.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands,


provider, out number))
Console.WriteLine("{0} --> {1}", value, number);
else
Console.WriteLine("Unable to convert '{0}'", value);
}
}
// The example displays the following output:
// Unable to convert '1,304'
// 1,304 --> 1304

Imports System.Globalization

Module Example
Public Sub Main()
Dim value As String = "1,304"
Dim number As Integer
Dim provider As IFormatProvider = CultureInfo.CreateSpecificCulture("en-US")
If Int32.TryParse(value, number) Then
Console.WriteLine("{0} --> {1}", value, number)
Else
Console.WriteLine("Unable to convert '{0}'", value)
End If

If Int32.TryParse(value, NumberStyles.Integer Or NumberStyles.AllowThousands,


provider, number) Then
Console.WriteLine("{0} --> {1}", value, number)
Else
Console.WriteLine("Unable to convert '{0}'", value)
End If
End Sub
End Module
' The example displays the following output:
' Unable to convert '1,304'
' 1,304 --> 1304

WARNING
La operación de análisis siempre usa las convenciones de formato de una referencia cultural determinada. Si no pasa un
objeto CultureInfo o NumberFormatInfo para especificar una referencia cultural, se usa la referencia cultural asociada al
subproceso actual.
En la tabla siguiente se enumeran los miembros de la enumeración NumberStyles y se describe el efecto que
tienen en la operación de análisis.

VALOR NUMBERSTYLES EFECTO EN LA CADENA QUE SE VA A ANALIZAR

NumberStyles.None Solo se permiten los dígitos numéricos.

NumberStyles.AllowDecimalPoint Se permiten el separador decimal y los dígitos fraccionarios. En


el caso de los valores enteros, solo se permite cero como
dígito fraccionario. La propiedad
NumberFormatInfo.NumberDecimalSeparator o
NumberFormatInfo.CurrencyDecimalSeparator determina los
separadores decimales válidos.

NumberStyles.AllowExponent Se puede usar el carácter "e" o "E" para indicar la notación


exponencial. Vea NumberStyles para obtener información
adicional.

NumberStyles.AllowLeadingWhite Se permite el espacio en blanco inicial.

NumberStyles.AllowTrailingWhite Se permite el espacio en blanco final.

NumberStyles.AllowLeadingSign Un signo positivo o negativo puede preceder a los dígitos


numéricos.

NumberStyles.AllowTrailingSign Un signo positivo o negativo puede seguir a los dígitos


numéricos.

NumberStyles.AllowParentheses Se pueden usar paréntesis para indicar valores negativos.

NumberStyles.AllowThousands Se permite el separador de grupos. El carácter de separador de


grupo viene determinado por la propiedad
NumberFormatInfo.NumberGroupSeparator o
NumberFormatInfo.CurrencyGroupSeparator.

NumberStyles.AllowCurrencySymbol Se permite el símbolo de moneda. El símbolo de moneda se


define mediante la propiedad
NumberFormatInfo.CurrencySymbol.

NumberStyles.AllowHexSpecifier La cadena que se va a analizar se interpreta como un número


hexadecimal. Puede incluir los dígitos hexadecimales 0-9, A-F y
a-f. Esta marca solo se puede usar para analizar valores
enteros.

Además, la enumeración NumberStyles proporciona los siguientes estilos compuestos, que incluyen varias marcas
NumberStyles.

VALOR NUMBERSTYLES COMPUESTOS MIEMBROS QUE INCLUYE

NumberStyles.Integer Incluye los estilos NumberStyles.AllowLeadingWhite,


NumberStyles.AllowTrailingWhite y
NumberStyles.AllowLeadingSign. Este es el estilo
predeterminado que se usa para analizar valores enteros.
VALOR NUMBERSTYLES COMPUESTOS MIEMBROS QUE INCLUYE

NumberStyles.Number Incluye los estilos NumberStyles.AllowLeadingWhite,


NumberStyles.AllowTrailingWhite,
NumberStyles.AllowLeadingSign,
NumberStyles.AllowTrailingSign,
NumberStyles.AllowDecimalPoint y
NumberStyles.AllowThousands.

NumberStyles.Float Incluye los estilos NumberStyles.AllowLeadingWhite,


NumberStyles.AllowTrailingWhite,
NumberStyles.AllowLeadingSign,
NumberStyles.AllowDecimalPoint y
NumberStyles.AllowExponent.

NumberStyles.Currency Incluye todos los estilos excepto NumberStyles.AllowExponent


y NumberStyles.AllowHexSpecifier.

NumberStyles.Any Incluye todos los estilos excepto


NumberStyles.AllowHexSpecifier.

NumberStyles.HexNumber Incluye los estilos NumberStyles.AllowLeadingWhite,


NumberStyles.AllowTrailingWhite y
NumberStyles.AllowHexSpecifier.

Análisis y dígitos Unicode


El estándar Unicode define puntos de código para dígitos de diferentes sistemas de escritura. Por ejemplo, los
puntos de código de U+0030 a U+0039 representan los dígitos latinos básicos del 0 al 9, los puntos de código de
U+09E6 a U+09EF representan los dígitos de bengalí del 0 al 9, y los puntos de código de U+FF10 a U+FF19
representan los dígitos de ancho completo del 0 al 9. Pero los únicos dígitos numéricos que reconocen los
métodos de análisis son los dígitos latinos básicos del 0 al 9 con puntos de código de U+0030 a U+0039. Si se
pasa a un método de análisis numérico una cadena que contenga cualquier otro dígito, el método producirá una
excepción FormatException.
En el ejemplo siguiente se usa el método Int32.Parse para analizar las cadenas que se componen de dígitos en
sistemas de escritura diferentes. Como muestra la salida del ejemplo, el intento de analizar los dígitos latinos
básicos se realiza correctamente, pero se produce un error en el intento de analizar los dígitos de ancho completo,
árabe-hindús y de bengalí.
using System;

public class Example


{
public static void Main()
{
string value;
// Define a string of basic Latin digits 1-5.
value = "\u0031\u0032\u0033\u0034\u0035";
ParseDigits(value);

// Define a string of Fullwidth digits 1-5.


value = "\uFF11\uFF12\uFF13\uFF14\uFF15";
ParseDigits(value);

// Define a string of Arabic-Indic digits 1-5.


value = "\u0661\u0662\u0663\u0664\u0665";
ParseDigits(value);

// Define a string of Bangla digits 1-5.


value = "\u09e7\u09e8\u09e9\u09ea\u09eb";
ParseDigits(value);
}

static void ParseDigits(string value)


{
try {
int number = Int32.Parse(value);
Console.WriteLine("'{0}' --> {1}", value, number);
}
catch (FormatException) {
Console.WriteLine("Unable to parse '{0}'.", value);
}
}
}
// The example displays the following output:
// '12345' --> 12345
// Unable to parse '12345'.
// Unable to parse '١٢٣٤٥'.
// Unable to parse ' '.
Module Example
Public Sub Main()
Dim value As String
' Define a string of basic Latin digits 1-5.
value = ChrW(&h31) + ChrW(&h32) + ChrW(&h33) + ChrW(&h34) + ChrW(&h35)
ParseDigits(value)

' Define a string of Fullwidth digits 1-5.


value = ChrW(&hff11) + ChrW(&hff12) + ChrW(&hff13) + ChrW(&hff14) + ChrW(&hff15)
ParseDigits(value)

' Define a string of Arabic-Indic digits 1-5.


value = ChrW(&h661) + ChrW(&h662) + ChrW(&h663) + ChrW(&h664) + ChrW(&h665)
ParseDigits(value)

' Define a string of Bangla digits 1-5.


value = ChrW(&h09e7) + ChrW(&h09e8) + ChrW(&h09e9) + ChrW(&h09ea) + ChrW(&h09eb)
ParseDigits(value)
End Sub

Sub ParseDigits(value As String)


Try
Dim number As Integer = Int32.Parse(value)
Console.WriteLine("'{0}' --> {1}", value, number)
Catch e As FormatException
Console.WriteLine("Unable to parse '{0}'.", value)
End Try
End Sub
End Module
' The example displays the following output:
' '12345' --> 12345
' Unable to parse '12345'.
' Unable to parse '١٢٣٤٥'.
' Unable to parse ' '.

Vea también
NumberStyles
Parsing Strings
Aplicación de formato a tipos
Analizar cadenas de fecha y hora en .NET
22/01/2020 • 12 minutes to read • Edit Online

El análisis de cadenas para convertirlas en objetos DateTime requiere que se especifique información sobre cómo
se representan las fechas y horas en forma de texto. Las distintas referencias culturales usan distintos órdenes de
día, mes y año. Algunas representaciones horarias usan el reloj de 24 horas y otras especifican "a. m." y "p. m.".
Algunas aplicaciones solo necesitan la fecha. Otras solo necesitan la hora. Pero otras necesitan especificar la fecha
y la hora. Los métodos que convierten cadenas a objeto DateTime permiten especificar información detallada
sobre los formatos esperados y los elementos de fecha y hora que precisa la aplicación. Hay tres subtareas para
convertir correctamente el texto en un objeto DateTime:
1. Debe especificarse el formato esperado del texto que representa una fecha y hora.
2. Es posible especificar la referencia cultural del formato de fecha y hora.
3. Puede especificarse cómo se establecen los componentes que faltan en la representación de texto en la fecha y
hora.
Los métodos Parse y TryParse convierten varias representaciones comunes de fecha y hora. Los métodos
ParseExact y TryParseExact convierten una representación de cadena que se ajusta al modelo especificado por una
cadena de formato de fecha y hora. (Para obtener más información, vea los artículos sobre cadenas con formato de
fecha y hora estándar y cadenas con formato de fecha y hora personalizado).
El objeto DateTimeFormatInfo actual proporciona más control sobre la forma en que debe interpretarse el texto
como fecha y hora. Las propiedades de un objeto DateTimeFormatInfo describen los separadores de fecha y hora,
los nombres de los meses, días y eras, así como el formato de las designaciones "a. m." y "p. m.". La referencia
cultural del subproceso actual proporciona un objeto DateTimeFormatInfo que representa la referencia cultural
actual. Si quiere una referencia cultural específica o una configuración personalizada, especifique el parámetro
IFormatProvider de un método de análisis. Para el parámetro IFormatProvider, especifique un objeto CultureInfo,
que representa una referencia cultural, o un objeto DateTimeFormatInfo.
Es posible que al texto que representa una fecha y hora le falte alguna información. Por ejemplo, la mayoría de los
usuarios supondría que la fecha "12 de marzo" representa el año actual. Del mismo modo, "Marzo de 2018"
representa el mes de marzo del año 2018. El texto que representa la hora a menudo solo incluye horas, minutos y
una designación "a. m."/"p. m.". Los métodos de análisis controlan esta información que falta mediante valores
predeterminados razonables:
Cuando solo se indica la hora, la parte de fecha utiliza la fecha actual.
Cuando solo se indica la fecha, la parte de hora es la medianoche.
Cuando no se especifica el año en una fecha, se usa el año actual.
Cuando no se especifica el día del mes, se usa el primero del mes.
Si la fecha se indica en la cadena, debe incluir el mes y uno de los dos valores, el día o el año. Si se indica la hora,
debe incluir la hora y los minutos o el designador "a. m."/"p. m.".
Se puede especificar la constante NoCurrentDateDefault para invalidar los valores predeterminados. Cuando se
usa esta constante, las propiedades de año, mes o día se establecen en el valor 1 . El último ejemplo con Parse
muestra este comportamiento.
Además de un componente de fecha y hora, la representación de cadena de una fecha y hora puede incluir una
diferencia horaria que indica cuánto difiere la hora respecto de la hora universal coordinada (UTC ). Por ejemplo, la
cadena "14/2/2007 5:32:00 -7:00" define una hora que es siete horas anterior a la hora UTC. Si se omite la
diferencia horaria de la representación de cadena de una hora, el análisis devuelve un objeto DateTime con su
propiedad Kind establecida en DateTimeKind.Unspecified. Si se especifica la diferencia horaria, el análisis devuelve
un objeto DateTime con su propiedad Kind establecida en DateTimeKind.Local y su valor ajustado a la zona
horaria local del equipo. Puede modificar este comportamiento usando un valor DateTimeStyles con el método de
análisis.
El proveedor de formato también se usa para interpretar una fecha numérica ambigua. No queda claro qué
componentes de la fecha representada por la cadena "02/03/04" son el mes, el día y el año. Los componentes se
interpretan según el orden de formatos de fecha similares del proveedor de formato.

Parse
En el ejemplo siguiente se muestra el uso del método DateTime.Parse para convertir un objeto string en un valor
DateTime. En este ejemplo se usa la referencia cultural asociada al subproceso actual. Si el objeto CultureInfo
asociado a la referencia cultural actual no puede analizar la cadena de entrada, se produce una excepción
FormatException.

TIP
Todos los ejemplos de C# en este artículo se ejecutan en el explorador. Presione el botón Ejecutar para ver el resultado.
También puede modificarlos para experimentar.

NOTE
Estos ejemplos están disponibles en el repositorio de documentos de GitHub para C# y Visual Basic. También, puede
descargar el proyecto como un archivo ZIP para C# o Visual Basic.

string dateInput = "Jan 1, 2009";


DateTime parsedDate = DateTime.Parse(dateInput);
Console.WriteLine(parsedDate);
// Displays the following output on a system whose culture is en-US:
// 1/1/2009 12:00:00 AM

Dim MyString As String = "Jan 1, 2009"


Dim MyDateTime As DateTime = DateTime.Parse(MyString)
Console.WriteLine(MyDateTime)
' Displays the following output on a system whose culture is en-US:
' 1/1/2009 12:00:00 AM

Además, puede definir explícitamente la referencia cultural cuyas convenciones de formato se utilizan cuando se
analiza una cadena. Especifique uno de los objetos DateTimeFormatInfo estándar devueltos por la propiedad
CultureInfo.DateTimeFormat. En el ejemplo siguiente se usa un proveedor de formato para analizar una cadena en
alemán como valor DateTime. Crea un objeto CultureInfo que representa la referencia cultural de-DE . El objeto
CultureInfo garantiza el análisis correcto de esta cadena concreta. Esto impide cualquier opción que se encuentre
en CurrentCulture de CurrentThread.

CultureInfo MyCultureInfo = new CultureInfo("de-DE");


string MyString = "12 Juni 2008";
DateTime MyDateTime = DateTime.Parse(MyString, MyCultureInfo);
Console.WriteLine(MyDateTime);
// The example displays the following output:
// 6/12/2008 12:00:00 AM
Dim MyCultureInfo As New CultureInfo("de-DE")
Dim MyString As String = "12 Juni 2008"
Dim MyDateTime As DateTime = DateTime.Parse(MyString, MyCultureInfo)
Console.WriteLine(MyDateTime)
' The example displays the following output:
' 6/12/2008 12:00:00 AM

Pero, aunque puede usar sobrecargas del método Parse para especificar proveedores de formato personalizados,
el método no admite el análisis de formatos no estándar. Para analizar una fecha y hora expresadas en un formato
no estándar, use en su lugar el método ParseExact.
En el ejemplo siguiente se usa la enumeración DateTimeStyles para especificar que no debe agregarse la
información de fecha y hora actual al valor DateTime en los campos no especificados.

CultureInfo MyCultureInfo = new CultureInfo("de-DE");


string MyString = "12 Juni 2008";
DateTime MyDateTime = DateTime.Parse(MyString, MyCultureInfo,
DateTimeStyles.NoCurrentDateDefault);
Console.WriteLine(MyDateTime);
// The example displays the following output if the current culture is en-US:
// 6/12/2008 12:00:00 AM

Dim MyCultureInfo As New CultureInfo("de-DE")


Dim MyString As String = "12 Juni 2008"
Dim MyDateTime As DateTime = DateTime.Parse(MyString, MyCultureInfo,
DateTimeStyles.NoCurrentDateDefault)
Console.WriteLine(MyDateTime)
' The example displays the following output if the current culture is en-US:
' 6/12/2008 12:00:00 AM

ParseExact
Si se ajusta a uno de los patrones de cadena especificados, el método DateTime.ParseExact convierte una cadena
en un objeto DateTime. Cuando se pasa a este método una cadena que no tiene uno de las formas especificadas,
se genera una excepción FormatException. Puede definirse uno de los especificadores de formato de fecha y hora
estándar o una combinación de los especificadores de formato de fecha y hora personalizados. Con el uso de
especificadores de formato personalizados, es posible construir una cadena de reconocimiento personalizada. Para
obtener una explicación de los especificadores, consulte los temas sobre cadenas con formato de fecha y hora
estándar y cadenas con formato de fecha y hora personalizado.
En el ejemplo siguiente, se pasa al método DateTime.ParseExact un objeto de cadena para que lo analice, seguido
de un especificador de formato y luego de un objeto CultureInfo. Este método ParseExact solo puede analizar
cadenas que sigan el patrón de fecha larga en la referencia cultural en-US .
CultureInfo MyCultureInfo = new CultureInfo("en-US");
string[] MyString = { " Friday, April 10, 2009", "Friday, April 10, 2009" };
foreach (string dateString in MyString)
{
try
{
DateTime MyDateTime = DateTime.ParseExact(dateString, "D", MyCultureInfo);
Console.WriteLine(MyDateTime);
}
catch (FormatException)
{
Console.WriteLine("Unable to parse '{0}'", dateString);
}
}
// The example displays the following output:
// Unable to parse ' Friday, April 10, 2009'
// 4/10/2009 12:00:00 AM

Dim MyCultureInfo As New CultureInfo("en-US")


Dim MyString() As String = {" Friday, April 10, 2009", "Friday, April 10, 2009"}
For Each dateString As String In MyString
Try
Dim MyDateTime As DateTime = DateTime.ParseExact(dateString, "D",
MyCultureInfo)
Console.WriteLine(MyDateTime)
Catch e As FormatException
Console.WriteLine("Unable to parse '{0}'", dateString)
End Try
Next
' The example displays the following output:
' Unable to parse ' Friday, April 10, 2009'
' 4/10/2009 12:00:00 AM

Cada sobrecarga de los métodos Parse y ParseExact tiene también un parámetro IFormatProvider que
proporciona información específica de la referencia cultural sobre el formato de la cadena. Este objeto
IFormatProvider es un objeto CultureInfo que representa una referencia cultural estándar o un objeto
DateTimeFormatInfo devuelto por la propiedad CultureInfo.DateTimeFormat. ParseExact usa también una cadena
o un argumento de matriz de cadena adicional que define uno o más formatos de fecha y hora personalizados.

Vea también
Analizar cadenas
Aplicación de formato a tipos
Conversión de tipos en .NET
Cadenas con formato de fecha y hora estándar
Cadenas con formato de fecha y hora personalizado
Analizar otras cadenas en .NET
04/11/2019 • 3 minutes to read • Edit Online

Además de cadenas numéricas y DateTime, puede analizar cadenas que representan los tipos Char, Boolean y
Enum en tipos de datos.

Char
El método de análisis estático asociado con el tipo de datos Char es útil para convertir una cadena que contiene un
único carácter en su valor Unicode. En el ejemplo de código siguiente se analiza una cadena en un carácter
Unicode.

String^ MyString1 = "A";


char MyChar = Char::Parse(MyString1);
// MyChar now contains a Unicode "A" character.

string MyString1 = "A";


char MyChar = Char.Parse(MyString1);
// MyChar now contains a Unicode "A" character.

Dim MyString1 As String = "A"


Dim MyChar As Char = Char.Parse(MyString1)
' MyChar now contains a Unicode "A" character.

Booleano
El tipo de datos Boolean contiene un método Parse que se puede usar para convertir una cadena que representa
un valor Boolean en un tipo Boolean real. Este método no distingue mayúsculas de minúsculas y puede analizar
correctamente una cadena que contenga "True" o "False". El método Parse asociado al tipo Boolean también
puede analizar cadenas que estén rodeadas por espacios en blanco. Si se pasa otra cadena, se produce una
excepción FormatException.
En el ejemplo de código siguiente se usa el método Parse para convertir una cadena en un valor Boolean.

String^ MyString2 = "True";


bool MyBool = bool::Parse(MyString2);
// MyBool now contains a True Boolean value.

string MyString2 = "True";


bool MyBool = bool.Parse(MyString2);
// MyBool now contains a True Boolean value.

Dim MyString2 As String = "True"


Dim MyBool As Boolean = Boolean.Parse(MyString2)
' MyBool now contains a True Boolean value.
Enumeración
Puede usar el método Parse estático para inicializar un tipo de enumeración en el valor de una cadena. Este
método acepta el tipo de enumeración que se está analizando, la cadena que se va a analizar y una marca Boolean
opcional que indica si el análisis distingue mayúsculas de minúsculas. La cadena que se va a analizar puede
contener varios valores separados por comas, que pueden ir precedidos o seguidos de uno o varios espacios
vacíos (también denominados espacios en blanco). Cuando la cadena contiene varios valores, el valor del objeto
devuelto es el valor de todos los valores especificados combinados con una operación OR bit a bit.
En el ejemplo siguiente se usa el método Parse para convertir una representación de cadena en un valor de
enumeración. La enumeración DayOfWeek se inicializa en Thursday desde una cadena.

String^ MyString3 = "Thursday";


DayOfWeek MyDays = (DayOfWeek)Enum::Parse(DayOfWeek::typeid, MyString3);
Console::WriteLine(MyDays);
// The result is Thursday.

string MyString3 = "Thursday";


DayOfWeek MyDays = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), MyString3);
Console.WriteLine(MyDays);
// The result is Thursday.

Dim MyString3 As String = "Thursday"


Dim MyDays As DayOfWeek = CType([Enum].Parse(GetType(DayOfWeek), MyString3), DayOfWeek)
Console.WriteLine("{0:G}", MyDays)
' The result is Thursday.

Vea también
Parsing Strings
Aplicación de formato a tipos
Conversión de tipos en .NET

También podría gustarte