Categories
Llibres Programació C# Javascript Hardware Fotografia Pelis Anglès Android Series Excursions Cites SQLServer Software HTML/CSS Politikon Estilogràfiques Tintes
Contacte: Àlex
|
| Com fer trossos d'un string llarg |
L'altra dia estava jo fent coses amb strings en C# i hem vaig trovar amb la necessitat de fer trossos de 80 caracters un string llaaaaaarg. Així que dit i fet, una mica de Google i alehop!
private List<string> SplitIntoChunks(string text, int chunkSize)
{
List<string> chunks = new List<string>();
int offset = 0;
int size = 0;
while (offset < text.Length)
{
size = Math.Min(chunkSize, text.Length - offset);
chunks.Add(text.Substring(offset, size));
offset += size;
}
return chunks;
}
| #17/12/2025 19:15 Programació C# Autor: Alex Canalda
|
| OnKeyup vs. Onchange vs. OnInput |
Tenia un bug curiós. En un control input normal d'introducció de text es calculava una funció cada cop que es modificava el valor. Clar, en un principi el vaig posar en el onchange però això no era suficient, perque aquest event només es dispara quan l'usuari abandona el control. Aleshores vaig posar la funció en l'event OnKeyup i llestos, cada cop que l'usuari tecleja, doncs es calcula la funció. Segur? L'usuari es queixa que el tema no acaba de funcionar... vinga a fer proves i en local funciona perfectament, doncs cal anar a veure com treballa l'usuari. Resulta que és l'autocomplete que no dispara el keyup, vist el tema també he fet: botó dret sobre el control i escollir "pegar" i es posa el valor al control sense disparar l'event. Hi ha l'opció de posar al control input l'atribut autocomplete="off", però hi ha una manera millor, és el OnInput que es dispara cada cop que el control rep valors diferents, indepedenment de l'origen, ja sigui "pegar" o "autocomplete". A partir d'ara OnInput .
<input tabindex="9" accesskey="9" id="nom_del_control" name="nom_del_control" size="12" maxlength="12" type="text" oninput="javascript: Calculo();" value="el_valor_aqui" />
| #26/11/2024 10:38 Programació HTML/CSS Autor: Alex Canalda
|
| Funció per comptar l'enessima aparició d'un caracter en SQL Server |
Fent coses he necessitat comptar paraules en una frase. Aquesta frase és un camp en una BBDD d'SQL Server. Allò que et diuen: "talla la frase a partir de la 6 paraula". Doncs cal fer primer una funció d'usuari a SQL Server que compti quants espais ha saltat i et doni la posició de n-essim espai.
USE [LaTevaBBDD]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[CHARINDEX2]
(
@TargetStr varchar(8000),
@SearchedStr varchar(8000),
@Occurrence int
)
RETURNS int
as
begin
declare @pos int, @counter int, @ret int
set @pos = CHARINDEX(@TargetStr, @SearchedStr)
set @counter = 1
if @Occurrence = 1 set @ret = @pos
else
begin
while (@counter < @Occurrence)
begin
select @ret = CHARINDEX(@TargetStr, @SearchedStr, @pos + 1)
set @counter = @counter + 1
if @ret <> 0 set @pos = @ret
end
end
RETURN(@ret)
end
La gracia d'aquesta versió vs. la que circula per Internet, es que si tu demanes la 8 posició i només té 6, retorna 0 enlloc d'un número aleatori. Un cop feta la funció cal posar aquesta sentència:
update UnaTaula set UnCamp=LEFT(UnCamp, dbo.CHARINDEX2(' ', UnCamp, 9)-1) WHERE dbo.CHARINDEX2(' ', UnCamp, 9)>0
Ja posats, si fem tractament de strings en SQLServer el REPLACE va força bé, però si es vol fer substitucions que estiguin a l'inici de la cadena de text:
update UnaTaula set UnCamp=SUBSTRING(UnCamp, 4, LEN(UnCamp)-3) where LEFT(UnCamp, 3)='un '
Feia temps que no trobava coses noves d'SQLServer per fer. Yummi! | #07/02/2023 01:02 Programació SQLServer Autor: Alex Canalda
|
| L'objectiu d'un programa d'ordinador |
Fa uns dies que penso en això. Per alguns pot ser resoldre un problema, per altres gestionar unes dades... I a més a més molts creuen que ha de ser eficient, de fàcil manteniment, que es pugui entendre el codi, etc... Però en realitat tot això és mentida.
L'objectiu d'un programa és que algú pagui diners per ell (si aquest algú és una persona, una empresa o un govern ja és igual).
I es ben bé igual que el programa estigui ben fet, que funcioni com el cul (o directament no funcioni) o que el programa estigui a mig fer, tot es igual sempre que aquest pagament es produeixi. He viscut tots aquests casos, treballant a diferents llocs.
Sobretot maximitzar la diferència entre la quantitat cobrada i el que es paga (a.k.a benefici). Aleshores es nota que per cobrar més cal donar una impressió de complexitat que no sempre s'ajusta a la realitat, afegint sigles o tecnologies que potser no afavoreixen al programa però és igual, millor posar-les, segons la moda del moment (tot el que és nou fa pujar el preu...). I posar noms "fashion" a les coses, en anglès si és possible, també. Sempre intentant jugar amb la ignorància de les persones i ofendre la seva vanitat de que haurien d'admetre que no tenen ni idea de que és el que els estàs explicant.
Després cal pagar, a desenvolupadors, perque facin "algo" (si aquest algo funciona potser es podrà dir programa), però clar, que aquests desenvolupadors tinguin coneixements per fer-ho, o ganes de fer-ho mmmmm...
I poc a poc es va formant un embolic de gent amb tasques, mmmm... rares, que no són ben bé programar. I el client veient com va el tema, també fuig escaldat, i posa a gent a vigilar i la bola es fa gran. Així gira el mon. Però dins d'aquesta bola no cal perdre de vista l'objectiu.
Aleshores, he decidit considerar-me una mini-empresa que ven un servei. Desprès d'anys de fer-ho bé, al final ni pagat ni agraït, aleshores per que matar-se? Estic veient que fent-ho no tan bé al final no passa res. Si l'aplicació enlloc de milisegons té temps de resposta de varis segons... Ningú ho aprecia i la meva mini-empresa cobra el mateix. He vist codi que pffffff, i penso ja posaran un servidor més potent, amb més RAM, total, al cap d'uns anys, s'ha de fer la típica re-enginyeria, llençar tot el que és antic i tornar-ho a fer segons la moda del moment... per repetir el cicle i complir l'objectiu. | #13/04/2022 17:32 Programació Autor: Alex Canalda
|
| Mantenibilitat del codi |
Vaig acumulant anys, i clar, codi antic. Codi que vaig fer jo, codi que van fer altres, però codi al fi i al cap. És com parlar llengües mortes, coses antigues i no tan antigues, inclús coses noves però que canvien les especificacions i s'han de modificar. Aquestes modificacions, ja sigui per millorar o per corregir les ha de fer algú, i últimament aquest algú sóc jo.
I m'adono del que al meu jo futur li molaria trobar per facilitar-me la vida.
- Mai, mai, mai, (potser no m'he expressat bé), mai, fer servir IF immediats, i menys aniuats. Es a dir això totalment prohibit:
var Servicer = filter.Servicer == GlobalConstant.DefaultId.ToString() || filter.Servicer.IsNullOrBlank()
? "" : filter.Servicer == GlobalConstant.ServicerNO
? String.Format(" AND (DEM.SERVICER = '{0}' OR DEM.SERVICER IS NULL)", filter.Servicer) : String.Format(" AND DEM.SERVICER = '{0}'", filter.Servicer);
En realitat, és una sola línia. A l'hora de depurar i veure per on va... mmmm... per on va? No hi ha cap premi a qui escrigui menys línies de codi.
- El tipus "var", a veure si un llenguatge és tipat, doncs fes-ho servir.
- Lambda expressions quilomètriques. Prohibides.
model.DatosVol.Where(x=>x.Value.VOL>0).ToList().ForEach(
x => x.Value.VOL_PCT = ((x.Value.VOL * 100)/
model.DatosVol.Where(y=>y.Value.Tipo_Calculo==x.Value.Tipo_Calculo
&& y.Value.Tipo_Contrato==(int)SLAsCliente_TipoContEnum.Global).Sum(y=>GetDividendo(y.Value.VOL))));
Ves i busca un bug, o corregeix algo de la forma de calcular-se... És la típica lluita entre funcionals vs procedurals, jo sóc procedural.
- Noms de funcions clars. A ser possible en un sol idioma. Res de dir funcions "TRACTAMENT" o "TRACTAMENT2". Si es pot incloure un comentari de que fa la funció ja és una gran millora.
I podria continuar, però això ja donaria per un altra post. I parlar del rendiment... perque veig que per millorar rendiment és més barat tirar de hardware i tancar els ulls. | #28/02/2022 17:39 Programació C# Autor: Alex Canalda
|
| C# - com obrir un fitxer de text sense obtenir caracters estranys |
Seguim amb els petits detalls, res gaire complicat, però que molesten. Quan obres un fitxer de text a vegades té caràcters estranys en els accents quan llegeixes les línies. Normalment és la codificació. Per això cal posar-ho en la funció que fa la lectura.
StreamReader reader = new StreamReader(NombreFichero, Encoding.GetEncoding("iso-8859-1"))
| #02/10/2020 15:55 Programació C# Autor: Alex Canalda
|
| C# - com ensenyar el format espanyol de la data |
Sempre em despito i mai recordo el format... Ainsss, deu ser l'edat.
DateTime.Now.ToString("dd'/'MM'/'yyyy HH:mm:ss");
| #02/10/2020 15:52 Programació C# Autor: Alex Canalda
|
| Javascript: com agafar el valor d'un radiobutton |
A vegades faig programes complicats i sembla que "sàpiga" molt, però no. Avui en dia cal saber unes bases però la resta no cal recordar-ho de memòria, cal saber on trobar-ho i com buscar-ho. Per això hem trobo buscant el mateix de forma repetitiva certs temes. Un d'ells és com recuperar el valor d'un control radiobutton en un formulari des de Javascript (fent servir jQuery). Tenim l'HTML:
<input type="radio" id="Ubicacion" name="ordenarpor" value="Ubicacion" />
<label for="Ubicacion">Ubicacion</label><br />
<input type="radio" id="RefCliente" name="ordenarpor" value="RefCliente" />
<label for="RefCliente">Ref. Cliente</label><br />
<input type="radio" id="FechaEntrada" name="ordenarpor" value="FechaEntrada" />
<label for="FechaEntrada">Fecha entrada</label>
Observar en l'HTML cada radiobutton té un value i un id diferent, el que els lliga i fa que estiguin relacionats és el name. El codi javascript per recollir el valor del radiobutton seleccionat és:
var OrderBy = $('input[name="ordenarpor"]:checked').val();
Job done! | #09/09/2020 18:43 Programació Javascript HTML/CSS Autor: Alex Canalda
|
| HTML5 tag button |
Aquests dies de coronavirus i de quedar-se a casa, intentant sobreviure a conviure tots junts en un espai reduït, aprofito per programar coses. Una d'aquestes vaig pensar: ¿I si enlloc de fer servir un tag input type="button", faig servir el tag button directament? I així estava jo molt content d'aquesta idea inspiradora quan de sobte, un cop posat el tag button, li dono i "ups!" la pàgina navega a un altra lloc.
Els formularis que faig en HTML acostumen a funcionar amb AJAX, tant per recuperar dades com per guardar-les i no "naveguen" a cap lloc, la URL no acostuma a canviar, i en el meu codi javascript no hi havia res que modifiqui la URL. Per això em va estranyar que amb el nou tag button sí. Vaig trigar una bona estona fins trobar el que passava. Resulta que la URL on navegava la pàgina era el "action" del formulari (vaig trigar a adonar-me perque els meus formularis tenen el action="/", no tenen). I el que estava fent el botó era un submit del formulari. I com és que el tag button fa un submit si jo no li dic per javascript? Aaaaah...
La resposta està en l'especificació del tag button de HTML5. Curiosament el tag button té l'atribut type i aquest té uns valors curiosos. Observa:
- submit: envia el formulari mitjançant un HTTP Post a l'action del formulari.
- reset: neteja el formulari.
- button: no fa res, només executa el javascript quan es fa l'event click
La punyeteta està en la següent frase de l'especificació:
The missing value default is the Submit Button state.
Es a dir, que si al tag button no li poses un atribut type, aquell botó fa submit. I jo que tinc un munt de buttons en el formulari... no crec que aquest comportament per defecte sigui el millor i que de sobte tots facin submit. Per defecte hauria de ser "button", així ens estalviaríem coses del capità "obvious" al tenir que posar molts tags "button type="button" ...." tu escrius un button no cal dir-li que a més a més és de tipus... mmmmm... deixam pensar... mmmmmm... a sí, tipus button.
| #16/03/2020 16:28 Programació HTML/CSS Autor: Alex Canalda
|
| Firma AES CMAC - RFC 4493 |
El 3DES ja va quedant enrera i ara cal una nova firma. Clar, ha d'estar basada en el successor del 3DES, el AES. Per això m'ha tocat implementar la firma AES CMAC - RFC 4493 i ho he fet en C#. I de dues formes diferents. Primer fent els passos individuals segons l'especificació, i de la manera comodona: fent servir la llibreria BouncyCastle. Primer fent-ho a màs, pas a pas. La dificultat està en la generació d'una sub-clau, que per això he posat un comentari amb l'especificació de com fer-ho del RFC:
byte[] AESEncrypt(byte[] key, byte[] iv, byte[] data)
{
using (MemoryStream ms = new MemoryStream())
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
}
byte[] Rol(byte[] b)
{
byte[] r = new byte[b.Length];
byte carry = 0;
for (int i = b.Length - 1; i >= 0; i--)
{
ushort u = (ushort)(b[i] << 1);
r[i] = (byte)((u & 0xff) + carry);
carry = (byte)((u & 0xff00) >> 8);
}
return r;
}
byte[] AESCMAC(byte[] key, byte[] data)
{
byte[] L = AESEncrypt(key, new byte[16], new byte[16]);
byte[] FirstSubkey = Rol(L);
if ((L[0] & 0x80) == 0x80)
FirstSubkey[15] ^= 0x87;
byte[] SecondSubkey = Rol(FirstSubkey);
if ((FirstSubkey[0] & 0x80) == 0x80)
SecondSubkey[15] ^= 0x87;
if (((data.Length != 0) && (data.Length % 16 == 0)) == true)
{
for (int j = 0; j < FirstSubkey.Length; j++)
data[data.Length - 16 + j] ^= FirstSubkey[j];
}
else
{
data = AddPaddingAES(data);
for (int j = 0; j < 16; j++) data[data.Length - 16 + j] ^= SecondSubkey[j];
}
byte[] encResult = AESEncrypt(key, new byte[16], data);
byte[] HashValue = new byte[16];
Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
return HashValue;
}
I tot això que sembla tan complicat... només són unes poques linies fent servir BouncyCastle. Però ja es sap... la veritat està en el codi, i amb la llibreria no els veus. I el curiós és que ambdues versions donen el mateix resultat:
Org.BouncyCastle.Crypto.Engines.AesEngine aes = new Org.BouncyCastle.Crypto.Engines.AesEngine();
Org.BouncyCastle.Crypto.Macs.CMac cMac = new Org.BouncyCastle.Crypto.Macs.CMac(aes, 64);
Org.BouncyCastle.Crypto.Parameters.KeyParameter kp = new Org.BouncyCastle.Crypto.Parameters.KeyParameter(key);
cMac.Init(kp);
int MacLenght = cMac.GetMacSize();
byte[] output = new byte[MacLenght];
cMac.BlockUpdate(data, 0, data.Length);
cMac.DoFinal(output, 0);
txtBase64.Text = ConvertByteArrayToHexString(output);
Hi ha un conjunt de proves disponibles a un RFC.
I ja està, una altra firma feta. | #23/01/2020 17:00 Programació C# Autor: Alex Canalda
| |
<< Posts anteriors |
|