Picacodigos
« Comprimiendo y descomprimiendo ficheros ...
|
Mas Reciente
|
VirtualBox »
Apellidos aleatorios (y falsos)
Published 190 weeks, 6 days ago
Fri
Jan
12
2007
Respondiendo al
desafío
planteado por Jon Galloway en su excelente blog, aquí está mi solución para generar apellidos falsos y aleatorios. El código está repleto de comentarios, eso sí en inglés de momento, los traduciré en cuanto pueda. Estás invitado, por supuesto, a hacer preguntas, críticas, o incluso mejor un buen refactorizado! =)
class
Program
{
//Un arraylist que contiene todos los posibles digramas (ver más abajo)
//(Nota: digram en inglés es la combinación de dos caracteres, no sé si en español será sílaba)
private static
ArrayList AllDigrams
= new
ArrayList()
;
//Un arraylist que contiene todas las letras posibles (ver más abajo)
private static
ArrayList AllLetters
= new
ArrayList()
;
//Una semilla aleatoria para el generador aleatorio principal
private static
Random rSeed
= new
Random()
;
//Un array multidimensional que especifica la estructura principal de un apellido.
// "A" representa una vocal, "B" una consonante
//"AB representa un digrama de vocal + consonante, etc...
//Estas combinaciones las he hecho a mano, puedes añadir, modificar o quitar
//combinaciones para ajustar el tipo de apellidos que se obtengan
private static string
[,] SurnameRandomTypes
= new string
[
10
,
6
]
{
{
"A"
,
"BA"
,
"B"
,
"A"
,
"BA"
,
""
},
{
"B"
,
"A"
,
"BA"
,
""
,
""
,
""
},
{
"A"
,
"BA"
,
"A"
,
"B"
,
"A"
,
"BB"
},
{
"A"
,
"B"
,
"B"
,
"A"
,
"BA"
,
""
},
{
"A"
,
"BB"
,
"AB"
,
"A"
,
""
,
""
},
{
"BA"
,
"B"
,
"B"
,
"A"
,
"B"
,
"A"
},
{
"B"
,
"AB"
,
"A"
,
"BB"
,
"A"
,
"AB"
},
{
"B"
,
"AB"
,
"B"
,
"A"
,
"BB"
,
"AB"
},
{
"A"
,
"BB"
,
"A"
,
"B"
,
"AB"
,
""
},
{
"AB"
,
"AA"
,
"B"
,
"A"
,
"B"
,
"A"
},
}
;
static void
Main()
{
bool
exit
= false;
//Cargamos TODOS los posibles digrams en memoria,
//en el arraylist AllDigrams
LoadDigrams()
;
//Lo mismo para las letras posibles,
//en el arraylist AllLetters
LoadLetters()
;
do
{
for
(
int
i
=
0
;
i <
=
20
;
i++)
{
Console.WriteLine(
"Apellido Aleatorio: {0}"
,
GenerateRandomSurname())
;
}
Console.WriteLine(
"Pulsa ENTER para generar otro lote, X para salir"
)
;
string
sInput
=
Console.ReadLine()
;
if
(sInput.ToString()
==
"x"
|| sInput.ToString()
==
"X"
)
exit
= true;
}
while
(exit
== false
)
;
Console.ReadLine()
;
}
/// <summary>
/// Éste método genera un apellido aleatorio y lo devuelve.
/// </summary>
/// <returns></returns>
static string
GenerateRandomSurname()
{
string
sRet
=
""
;
Random r
;
//Nueva semilla aleatoria para el generador de números
r
= new
Random(rSeed.Next(
1
,
1000
))
;
//y obtenemos un índice al azar
//para el array multidimensional SurnameRandomTypes
int
rndIndex
=
r.Next(
0
,
9
)
;
//Entonces leemos las distintas "columnas" de
//esa "fila" y decidimos si necesitamos una vocal,
//una consonante, un digrama vocal-consonante,
//o lo que sea
for
(
int
i
=
0
;
i <
6
;
i++)
{
switch
(SurnameRandomTypes[rndIndex, i])
{
case
"AA"
:
sRet +
=
getDigram(DigramType.TwoVowels)
;
break;
case
"AB"
:
sRet +
=
getDigram(DigramType.VowelAndConsonant)
;
break;
case
"BA"
:
sRet +
=
getDigram(DigramType.ConsonantAndVowel)
;
break;
case
"BB"
:
sRet +
=
getDigram(DigramType.TwoConsonants)
;
break;
case
"A"
:
sRet +
=
getLetter(LetterType.Vowel)
;
break;
case
"B"
:
sRet +
=
getLetter(LetterType.Consonant)
;
break;
default
:
break;
}
}
//Y devolvemos el apellido generado
//convirtiendo a mayúsculas la primera letra
return
sRet.Substring(
0
,
1
).ToUpper() +
sRet.Substring(
1
)
;
}
#region
Letters and Digrams
#region
Structs and Enums
/// <summary>
/// Con esta enumeración sabremos de qué
/// está compuesto el digrama
/// </summary>
private enum
DigramType
{ TwoVowels, VowelAndConsonant, ConsonantAndVowel, TwoConsonants }
/// <summary>
/// Con esta enumeración sabremos si una letra es una
/// vocal o una consonante
/// </summary>
private enum
LetterType { Vowel, Consonant }
/// <summary>
/// Un objeto digrama. Además del propio digrama ("th", por ejemplo)
/// guardamos el rango de frecuencia en el que el digrama aparece
/// en el lenguaje inglés y su tipo
/// </summary>
private struct
Digram
{
public int
iniRange
;
//El principio de su rango.
public int
endRange
;
//El final de su rango.
public string
Value
;
//Su valor
public
DigramType Type
;
//Su tipo, según la enumeración DigramType
}
/// <summary>
/// Una letra. Además de la propia letra ("a", por ejemplo)
/// guardamos el rango de frecuencia en la que aparece
/// en el lenguaje inglés y su tipo
/// </summary>
private struct
Letter
{
public int
iniRange
;
//El principio de su rango.
public int
endRange
;
//El final de su rango.
public string
Value
;
//Su valor.
public
LetterType Type
;
//Su tipo, según la enumeración LetterType
}
#endregion
/// <summary>
/// Este método devuelve el valor
/// de un digrama aleatorio del tipo especificado
/// </summary>
/// <param name="type">El tipo de digrama que queremos obtener</param>
/// <returns>El VALOR del digrama ("th", por ejemplo)</returns>
static string
getDigram(DigramType type)
{
Random r
= new
Random(rSeed.Next(
0
,
1000
))
;
Digram nuDigram
= new
Digram()
;
do
{
//Obtenemos un número aleatorio dentro del rango
//TOTAL de TODOS los digramas
int
freq
=
r.Next(
0
,
5548
)
;
//Ver LoadDigrams()
foreach
(Digram digram
in
AllDigrams)
{
//Y si el número aleatorio está dentro del
//rango de frecuencia del digrama actual,
//tenemos un ganador!
if
(freq >
=
digram.iniRange && freq <
=
digram.endRange)
nuDigram
=
digram
;
}
//Pero sólo si es del tipo que necesitamos
}
while
(nuDigram.Type !
=
type)
;
return
nuDigram.Value
;
}
/// <summary>
/// Obtenemos el VALOR de una sola letra del tipo especificado
/// </summary>
/// <param name="type">El tipo de letra que queremos obtener</param>
/// <returns>El VALOR de la letra</returns>
static string
getLetter(LetterType type)
{
Random r
= new
Random(rSeed.Next(
0
,
1000
))
;
Letter nuLetter
= new
Letter()
;
do
{
//Obtenemos un número aleatorio dentro del rango
//TOTAL de TODAS las letras
int
freq
=
r.Next(
0
,
10025
)
;
//Ver LoadLetters()
foreach
(Letter letter
in
AllLetters)
{
//Y si el número aleatorio
//está dentro del rango de frecuencias de
//la letra actual, tenemos un ganador!
if
(freq >
=
letter.iniRange && freq <
=
letter.endRange)
nuLetter
=
letter
;
}
//Pero sólo si es del tipo que necesitamos
}
while
(nuLetter.Type !
=
type)
;
return
nuLetter.Value
;
}
/// <summary>
/// Simple comprobación booleana para ver si una letra determinada es
/// una vocal o una consonante
/// </summary>
/// <param name="checkLetter">La letra a comprobar</param>
/// <returns>True si es una vocal, false en cualquier otro caso</returns>
static bool
IsAVowel(
string
checkLetter)
{
switch
(checkLetter.ToLower())
{
case
"a"
:
case
"e"
:
case
"i"
:
case
"o"
:
case
"u"
:
return true;
default
:
return false;
}
}
/// <summary>
/// Gracias del departamento de Informática de la Universidad de Bristol
/// (y a Google) he encontrado una lista de todas las letras del
/// alfabeto inglés, con su frecuencia de uso.
/// Como Random maneja enteros, he multiplicado todos estos valores * 100
/// La suma de todos ellos debería ser 10.000, lo que hace que cuando calculamos
/// el rango de números debería ser 10.000 + la cantidad de letras posibles;
/// porque el rango de la primera letra es de 0 a 1.231, y el siguiente
/// rango de letra empezará en 1.232 (el fin del anterior rango +1)
/// En el caso de letras solas esto es correcto, y los rangos van desde
/// 0 a 10.025.
///
/// Pero, no sé porqué, en el caso de los digramas el rango va
/// de 0 a 5.548. El porcentaje de frecuencia de todos los digramas disponibles,
/// todos ellos multiplicados por 100 y sumados NO da 10.000 como debiera.
/// ¿Alguien sabe porqué? A no ser que la lista de digramas que tengo NO esté completa.
/// </summary>
static void
LoadLetters()
{
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
// Porcentaje de frecuencia de letras
//
// E 12.31 L 4.03 B 1.62
// T 9.59 D 3.65 G 1.61
// A 8.05 C 3.20 V 0.93
// O 7.94 U 3.10 K 0.52
// N 7.19 P 2.29 Q 0.20
// I 7.18 F 2.28 X 0.20
// S 6.59 M 2.25 J 0.10
// R 6.03 W 2.03 Z 0.09
// H 5.14 Y 1.88
string
[] _letterValue
=
{
"e"
,
"l"
,
"b"
,
"t"
,
"d"
,
"g"
,
"a"
,
"c"
,
"v"
,
"o"
,
"u"
,
"k"
,
"n"
,
"p"
,
"q"
,
"i"
,
"f"
,
"x"
,
"s"
,
"m"
,
"j"
,
"r"
,
"w"
,
"z"
,
"h"
,
"y"
}
;
int
[] _letterFreq
=
{
1231
,
403
,
162
,
959
,
365
,
161
,
805
,
320
,
93
,
794
,
310
,
52
,
719
,
229
,
20
,
718
,
228
,
20
,
659
,
225
,
10
,
603
,
203
,
9
,
514
,
188
}
;
int
lastEndRange
=
0
;
//Recorriendo los arrays rellenados con esos datos
//guardamos una colección de objetos Letra llamada AllLetters,
//asignando a cada Letra su rango, valor y tipo
for
(
int
i
=
0
;
i < _letterFreq.Length
;
i++)
{
Letter nuLetter
= new
Letter()
;
nuLetter.iniRange
=
lastEndRange
;
nuLetter.endRange
=
lastEndRange + _letterFreq[i]
;
lastEndRange
=
nuLetter.endRange +
1
;
nuLetter.Value
=
_letterValue[i]
;
nuLetter.Type
=
IsAVowel(_letterValue[i]) ?
LetterType.Vowel : LetterType.Consonant
;
AllLetters.Add(nuLetter)
;
}
}
/// <summary>
/// Ver el comentario de LoadLetters
/// </summary>
static void
LoadDigrams()
{
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
// Digramas ingleses y su porcentaje de frecuencia de uso
// TH 3.15 TO 1.11 SA 0.75 MA 0.56
// HE 2.51 NT 1.10 HI 0.72 TA 0.56
// AN 1.72 ED 1.07 LE 0.72 CE 0.55
// IN 1.69 IS 1.06 SO 0.71 IC 0.55
// ER 1.54 AR 1.01 AS 0.67 LL 0.55
// RE 1.48 OU 0.96 NO 0.65 NA 0.54
// ES 1.45 TE 0.94 NE 0.64 RO 0.54
// ON 1.45 OF 0.94 EC 0.64 OT 0.53
// EA 1.31 IT 0.88 IO 0.63 TT 0.53
// TI 1.28 HA 0.84 RT 0.63 VE 0.53
// AT 1.24 SE 0.84 CO 0.59 NS 0.51
// ST 1.21 ET 0.80 BE 0.58 UR 0.49
// EN 1.20 AL 0.77 DI 0.57 ME 0.48
// ND 1.18 RI 0.77 LI 0.57 WH 0.48
// OR 1.13 NG 0.75 RA 0.57 LY 0.47
string
[] _digramValue
=
{
"th"
,
"to"
,
"sa"
,
"ma"
,
"he"
,
"nt"
,
"hi"
,
"ta"
,
"an"
,
"ed"
,
"le"
,
"ce"
,
"in"
,
"is"
,
"so"
,
"ic"
,
"er"
,
"ar"
,
"as"
,
"ll"
,
"re"
,
"ou"
,
"no"
,
"na"
,
"es"
,
"te"
,
"ne"
,
"ro"
,
"on"
,
"of"
,
"ec"
,
"ot"
,
"ea"
,
"it"
,
"io"
,
"tt"
,
"ti"
,
"ha"
,
"rt"
,
"ve"
,
"at"
,
"se"
,
"co"
,
"ns"
,
"st"
,
"et"
,
"be"
,
"ur"
,
"en"
,
"al"
,
"di"
,
"me"
,
"nd"
,
"ri"
,
"li"
,
"wh"
,
"or"
,
"ng"
,
"ra"
,
"ly"
}
;
int
[] _digramFreq
=
{
315
,
111
,
75
,
56
,
251
,
110
,
72
,
56
,
172
,
107
,
72
,
55
,
169
,
106
,
71
,
55
,
154
,
101
,
67
,
55
,
148
,
96
,
65
,
54
,
145
,
94
,
64
,
54
,
145
,
94
,
64
,
53
,
131
,
88
,
63
,
53
,
128
,
84
,
63
,
53
,
124
,
84
,
59
,
51
,
121
,
80
,
58
,
49
,
120
,
77
,
57
,
48
,
118
,
77
,
57
,
48
,
113
,
75
,
57
,
47
}
;
int
lastEndRange
=
0
;
//Recorremos los arrays de datos para rellenar
//la colección de objetos Digram AllDigrams
//asignándole a cada uno su rango,
//valor y tipo de digrama
for
(
int
i
=
0
;
i < _digramFreq.Length
;
i++)
{
Digram nuDigram
= new
Digram()
;
nuDigram.iniRange
=
lastEndRange
;
nuDigram.endRange
=
lastEndRange +
_digramFreq[i]
;
lastEndRange
=
nuDigram.endRange +
1
;
nuDigram.Value
=
_digramValue[i]
;
if
(IsAVowel(_digramValue[i].Substring(
0
,
1
)) &&
IsAVowel(_digramValue[i].Substring(
1
,
1
)))
nuDigram.Type
=
DigramType.TwoVowels
;
else if
(!IsAVowel(_digramValue[i].Substring(
0
,
1
)) &&
IsAVowel(_digramValue[i].Substring(
1
,
1
)))
nuDigram.Type
=
DigramType.ConsonantAndVowel
;
else if
(IsAVowel(_digramValue[i].Substring(
0
,
1
)) &&
!IsAVowel(_digramValue[i].Substring(
1
,
1
)))
nuDigram.Type
=
DigramType.VowelAndConsonant
;
else
nuDigram.Type
=
DigramType.TwoConsonants
;
AllDigrams.Add(nuDigram)
;
}
}
#endregion
}
Colorized by:
CarlosAg.CodeColorizer
Actualización 13/01/2007
.- Traducidos los comentarios del código fuente al español. Éste es un ejemplo de los apellidos que se generan:
Andaso
Estecon
Ovloso
Eleasawh
Athene
Tertore
Setolyiis
Face
Lirsuco
Rofsender
Categorías:
.NET
|
Trucos
|
Comments [1]
Tuesday, January 16, 2007 8:18:15 AM (Romance Standard Time, UTC+01:00)
Me gustaría saber la frecuencia de letras en castellano :-)
espinete
Comments are closed.
Buscar
Estadísticas
Total Posts: 112
This Year: 0
This Month: 0
This Week: 0
Comments: 328
Comentarios Recientes
RE: Microsoft Techdays y...
by Erick Alejan...
RE: Microsoft Techdays y...
by Venkman
RE: Microsoft Techdays y...
by Jesús
RE: Microsoft Techdays y...
by espinete
RE: Microsoft Techdays y...
by Pavleras
Software
Peeker
Acerca de...
Curriculum
Resume
Suscripcion
Suscribirse por correo
Categorias
.NET
Artículos
Blog
Eventos
Gadgets
Hardware
Herramientas
Opinión
Personal
ReSharper
Trucos
Ubuntu
Web
Archivo
January, 2008 (3)
December, 2007 (7)
November, 2007 (13)
October, 2007 (6)
September, 2007 (10)
August, 2007 (1)
July, 2007 (2)
June, 2007 (4)
May, 2007 (3)
March, 2007 (3)
February, 2007 (5)
January, 2007 (5)
December, 2006 (3)
November, 2006 (5)
September, 2006 (2)
August, 2006 (4)
July, 2006 (7)
June, 2006 (3)
May, 2006 (4)
April, 2006 (5)
March, 2006 (5)
February, 2006 (4)
January, 2006 (3)
Los blogs que leo
.Avery Blog
47 hats
Coding Horror
El lado del mal
Haacked
Jon Galloway
NET slave
Rob Conery
secretGeek
The daily WTF
The old new thing
Thinking in .NET
Velocidad de Escape
Contacto
Microblogging
Login
Sign In
Herramientas
Addicted to
The best C# & VB.NET refactoring plugin for Visual Studio 2005
Powered by
newtelligence dasBlog 1.9.7174.0
Tema basado en
Dandelion
, de Tim Sherrill