Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: **Aincrad** en 26 Diciembre 2018, 21:21 pm



Título: Desglosar un string en partes.
Publicado por: **Aincrad** en 26 Diciembre 2018, 21:21 pm
bueno quiero separar todo este texto en partes. pero no se como hacerlo.

texto>

 
Código
  1.  {"error":false,"title":"Alan Walker - Diamond Heart (feat. Sophia Somajo)","duration":218,"file":"http:\/\/michaelbelgium.me\/ytconverter\/download\/sJXZ9Dok7u8.mp3"}



Quiero separarlo en partes , como cuando se lee un archivo .ini, asi >

el "error": | "title": | "duration" | "file": | quiero obtener el resultado que le sigue. Por ejemplo el de error el resultado es false , es algo así como leer un .ini.

gracias de antemano!!


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 26 Diciembre 2018, 22:16 pm
El formato se conoce como JSON.

Teniendo un string JSON como este (el cual he formateado para que sea legible, pero no es necesario hacerlo):
Código
  1. Dim jsonStr As String =
  2.    <json>
  3.    {
  4.       "error":false,
  5.       "title":"Alan Walker - Diamond Heart (feat. Sophia Somajo)",
  6.       "duration":218,
  7.       "file":"http:\/\/michaelbelgium.me\/ytconverter\/download\/sJXZ9Dok7u8.mp3"
  8.    }
  9.    </json>.Value

Si quieres llevar a cabo una conversión genérica, me refiero, de uso reutilizable, entonces:
Código
  1. Dim dict As Dictionary(Of String, Object) =
  2.    New JavaScriptSerializer().Deserialize(Of Dictionary(Of String, Object))(jsonStr)
...
Código
  1. For Each item As KeyValuePair(Of String, Object) In dict
  2.    Console.WriteLine("{0}: {1}", item.Key, item.Value.ToString())
  3. Next item
...
Código
  1. Console.WriteLine(CBool(dict("error")))
  2. Console.WriteLine(CStr(dict("title")))
  3. Console.WriteLine(CInt(dict("duration")))
  4. Console.WriteLine(CStr(dict("file")))

Si por lo contrario quieres una solución adaptada al string JSON que has mostrado, entonces:
Código
  1. <Serializable>
  2. Public NotInheritable Class MyType
  3.    Public Property [Error] As Boolean
  4.    Public Property Title As String
  5.    Public Property Duration As Integer
  6.    Public Property File As String
  7.  
  8.    Public Sub New()
  9.    End Sub
  10.  
  11.    Public Overrides Function ToString() As String
  12.        Return New JavaScriptSerializer().Serialize(Me).ToString
  13.    End Function
  14. End Class
...
Código
  1. Dim obj As MyType = New JavaScriptSerializer().Deserialize(Of MyType)(jsonStr)
  2. Console.WriteLine(obj.ToString())

PD: Para soluciones algo más sofisticadas siempre puedes utilizar la librería gratuita JSON.NET (la cual usan empresas tan profesionales como Google y Microsoft para algunas de sus APIs para .NET).

Saludos.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 26 Diciembre 2018, 22:22 pm
Gracias de responder como siempre @Elektro, pero estoy trabajando con .net framework 4.0 , en vs 2010.

Código:
El tipo 'JavaScriptSerializer' no está definido.

no quiero usar ningún tipo de librería., simplemente quiero leerlo como si fuera un .txt

No es posible mejor desglosarlo todo como si se estuviera leyendo un .ini?.


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 26 Diciembre 2018, 22:31 pm
Gracias de responder como siempre @Elektro, pero estoy trabajando con .net framework 4.0 , en vs 2010.

Según la documentación oficial, la clase JavaScriptSerializer está disponible a partir de .NET 3.5, por lo tanto no deberías tener problema...
https://docs.microsoft.com/en-us/dotnet/api/system.web.script.serialization.javascriptserializer?view=netframework-4.7.2
Asegúrate de haber añadido una referencia al ensamblado con nombre 'System.Web.Extensions', e importar el esapacio de nombres 'System.Web.Script.Serialization'.

No es posible mejor desglosarlo todo como si se estuviera leyendo un .ini?.

Poder se puede, pero resultaría muy tedioso. Algo muy sencillo sería partir la cadena de texto usando la coma "," como caracter delimitador, con esto obtienes un array, entonces, cada elemento del array lo volverías a partir usando esta vez el caracter ":" como delimitador, y así obtener el nombre y el valor de cada cosa (ej: {"duration", "218"}), pero esto que en principio parece muy sencillo te podría dar problemas si el campo "title" contiene cualquiera de esos dos caracteres, por lo que habría que ingeniárselas mejor, y de ahí que sea tedioso. Sería mejor usar RegEx para capturar los valores (escritos entre comillas), pero no estoy por la labor de ponerme a construir una expresión regular, pudiendo recurrir a soluciones sofisticadas como la clase JavaScriptSerializer, o la librería JSON.NET.

Un saludo.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 26 Diciembre 2018, 22:42 pm
(https://i.ibb.co/jTL8X3w/img1.jpg)

MOD: Imagen adaptada a lo permitido.


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 26 Diciembre 2018, 23:27 pm
Vuelve a leer por favor:

Cita de: Elektro
Asegúrate de haber añadido una referencia al ensamblado con nombre 'System.Web.Extensions', e importar el espacio de nombres 'System.Web.Script.Serialization'.

El espacio de nombres que aparece en la imagen que has mostrado, no es el que he mencionado que debes importar. Y antes de poder importarlo, debes añadir una referencia al ensamblado que también mencioné.

Acabo de compilar en .NET 4.0 el código que mostré, y funciona perfectamente. Por otro lado, la clase JavaScriptSerializer NO está disponible en .NET 4.0 Client Profile. En resumen, el código lo puedes compilar con .NET 4.0 sin problemas, pero no lo puedes compilar en .NET 4.0 Client Profile.

Feliz Navidad.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 26 Diciembre 2018, 23:48 pm
Perdona mi ignorancia, estoy en .NET 4.0 pero sigue con >

Código:
El tipo 'JavaScriptSerializer' no está definido.



(https://i.ibb.co/nD1qJh0/img1.jpg)



(https://i.ibb.co/H45dNsn/descarga.jpg)


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 26 Diciembre 2018, 23:55 pm
¿Puedes mostrar la pestaña "Referencias" o en su defecto pasarme el proyecto?.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 27 Diciembre 2018, 00:24 am
te envié el proyecto por priv,


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 27 Diciembre 2018, 01:34 am
te envié el proyecto por priv,

En tu proyecto falta que añadas una referencia al ensamblado que te dije: System.Web.Extensions.dll. Una vez añadida la referencia, se puede utilizar la clase JavaScriptSerializer.

Dirígete a la pestaña "Referencias" y añade la maldita librería. xD

Saludos


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 27 Diciembre 2018, 02:30 am
Ptamadre si es verdad xd, ya la Solucionado gracias.



Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 27 Diciembre 2018, 06:03 am
Te respondo por aquí al privado...

en esta parte de tu código obtienes una respuesta con un documento en JSON:

Código
  1. Dim URLDATA As String = cliente.DownloadString(url)
  2. TextBox2.Text = URLDATA

Mediante el ejemplo que te mostré, deserializas ese JSON, tal que así:

Cita de: Elektro
Código
  1.    <Serializable>
  2.    Public NotInheritable Class MyType
  3.        Public Property [Error] As Boolean
  4.        Public Property Title As String
  5.        Public Property Duration As Integer
  6.        Public Property File As String
  7.  
  8.        Public Sub New()
  9.        End Sub
  10.  
  11.        Public Overrides Function ToString() As String
  12.            Return New JavaScriptSerializer().Serialize(Me).ToString
  13.        End Function
  14.    End Class

Código
  1. Dim obj As MyType = New JavaScriptSerializer().Deserialize(Of MyType)(URLDATA)

Y por último, en la propiedad MyType.File tienes la url al archivo .mp3 que puedes descargar, por ejemplo usando la función cliente.DownloadFile().

Código
  1. cliente.DownloadFile(obj.File, IO.Path.GetFileName(obj.File))



No tiene que ver con el tema, pero ya que estás abierto a escuchar críticas, pues acabo de fijarme en esta parte del código donde usas esta expresión regular...

Citar
Código
  1.    Private Function getID(ByVal url As String) As String 'Function by Stack Overflow Forum.
  2.        Try
  3.  
  4.            Dim myMatches As System.Text.RegularExpressions.Match
  5.            Dim MyRegEx As New System.Text.RegularExpressions.Regex("youtu(?:\.be|be\.com )/(?:.*v(?:/|=)|(?:.*/)?)([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase) 'This is where the magic happens/SHOULD work on all normal youtube links including youtu.be
  6.            myMatches = MyRegEx.Match(url)
  7.            If myMatches.Success = True Then
  8.                Return myMatches.Groups(1).Value
  9.            Else
  10.                Return ""
  11.            End If
  12.        Catch ex As Exception
  13.            Return ex.ToString
  14.        End Try
  15.    End Function
  16.  

y... bueno. Me limitaré a decir que copiar cosas publicadas por programadores random de Internet con conocimientos mediocres sobre el lenguaje que están manipulando, conlleva a aprender y acostumbrarse a malas prácticas de programación.

En no pocas ocasiones, el uso de expresiones regulares es un planteamiento totálmente innecesario y con un margen de error (falsos positivos y fallos de captura) que puede llegar a ser excesivamente elevado, y por ende, intolerablemente ineficiente. Aparte, si ya de por sí el motor RegEx de .NET (y de cualquier otro) supone un impacto negativo en el rendimiento de la aplicación, las expresiones regulares complejas son sinónimo de un impacto negativo aun mayor.

(en tu aplicación el impacto será inapreciable, insignificante. No es algo de lo que debas preocuparte, pero yo siempre hablo en términos generales.)

RegEx es el recurso fácil y multi-usos. En muchas ocasiones es tan fácil de aplicar una expresión regular que nos olvidamos de que podemos hacer las cosas de forma más eficiente... aunque no será posible hacerlo mejor en todos los casos, pero en muchos sí, cómo este.

A continuación te mostraré como puedes y deberías obtener la id de un video de Youtube usando los miembros built-in más apropiados disponibles en la librería de clases de .NET Framework sin tener que recurrir al uso de expresiones regulares.

Bueno, primero estas funciones reutilizables que he escrito:

Código
  1. Public Shared Function GetQuery(ByVal url As String) As NameValueCollection
  2.    Return GetQuery(url, Encoding.UTF8)
  3. End Function
  4.  
  5. Public Shared Function GetQuery(ByVal url As String, ByVal enc As Encoding) As NameValueCollection
  6.    Return GetQuery(New Uri(url), enc)
  7. End Function
  8.  
  9. Public Shared Function GetQuery(ByVal uri As Uri) As NameValueCollection
  10.    Return GetQuery(uri, Encoding.UTF8)
  11. End Function
  12.  
  13. Public Shared Function GetQuery(ByVal uri As Uri, ByVal enc As Encoding) As NameValueCollection
  14.    Dim queryString As String = uri.GetComponents(UriComponents.Query, UriFormat.UriEscaped)
  15.    Return HttpUtility.ParseQueryString(queryString, enc)
  16. End Function

Y entonces...
Código
  1. Dim query As NameValueCollection = GetQuery("https://www.youtube.com/watch?v=FtcVlSytJF4&feature=em-uploademail")
  2. Dim id As String = query("v")
  3. If String.IsNullOrEmpty(id) Then
  4.    Throw New NullReferenceException()
  5. Else
  6.    ' ...
  7. End If

PD: cabría destacar que, Microsoft, para algunas implementaciones internas hace uso de la clase RegEx, pero usar cualquier miembro de la librería de clases de .NET Framework cuya implementación interna recurra al uso de expresiones regulares, siempre será mejor opción y más seguro que implementar tu propio algoritmo 'home-made' de análisis de string mediante expresiones regulares aleatorias cuya eficacia en no pocas ocasiones es más que cuestionable de lo ofusca que es su sintaxis o los ejemplos de captura (si es que el autor proporciona alguno)...

Saludos.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 28 Diciembre 2018, 02:53 am
Gracias por responder , ya termine la app, pero se blockea un poco al principio cuando esta obteniendo los datos. me puedes ayudar con eso?

otra cosilla >

Código:
'HttpUtility' no está declarado. Puede que esté inaccesible debido a su nivel de protección.	

debo importar algo?


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 28 Diciembre 2018, 03:35 am
Código:
'HttpUtility' no está declarado. Puede que esté inaccesible debido a su nivel de protección.	
debo importar algo?

Sí, debes añadir una referencia el ensamblado System.Web.dll, e importar el espacio de nombres System.Web.

Si colocas el puntero del ratón sobre el nombre "HttpUtility" en esa linea de código que te da error, Visual Studio te dice el ensamblado que debes referenciar. Al menos en Visual Studio 2013, 2015 y 2017; no recuerdo si en VS 2010 también.



se blockea un poco al principio cuando esta obteniendo los datos. me puedes ayudar con eso?

WebClient.DownloadString y WebClient.DownloadFile son métodos sincrónicos, o lo que se conoce como una llamada bloqueante. Debido a que estás llamando a ese método en el thread de la UI, la UI se "bloquea" hasta que el método haya finalizado su ejecución (conectar con el servidor, procesar la query, esperar la respuesta del servidor, etc...) y eso dura un par de segundos... en los que la UI deja de procesar mensajes de ventana.

Para solucionarlo, debes hacer uso de programación asíncrona, y para ello practicamente debes modificar casi todo tu algoritmo. Para empezar, debes usar los métodos asíncronos de la clase WebClient. Puedes recurrir a dos metodologías distintas:

1. Usar los métodos WebClient.DownloadStringAsync() y WebClient.DownloadFileAsync, y suscribirte a los eventos WebClient.DownloadStringCompleted y WebClient.DownloadFileCompleted.

2. Usar las funciones WebClient.DownloadStringTaskAsync() y WebClient.DownloadFileTaskAsync, junto al uso de los operadores Async y Await.

La segunda metodología es más simple/sencilla de aplicar, requiere menos cambios en el código original. Lamentablemente en .NET 4.0 no puedes aplicar dicha metodología, puesto que las funciones mencionadas no están disponibles. Así que estás limitado a tener que recurrir a la primera metodología.

Aquí tienes la documentación oficial del método WebClient.DownloadStringAsync():
  • https://docs.microsoft.com/en-us/dotnet/api/system.net.webclient.downloadstringasync?view=netframework-4.7.2

Y aquí un ejemplo de código:
  • https://stackoverflow.com/a/24901590/1248295

PD: el modo de empleo del método WebClient.DownloadFileAsync es practicamente igual que en el ejemplo provisto, solo cambia el nombre del evento al que debes suscribirte, el cual ya mencioné.

Un saludo.



EDITO: bueno, por si al final te resulta dificil el uso de WebClient.DownloadStringAsync(), y cómo alternativa, la opción más sencilla y cutre para resolver el problema con el mínimo de cambios requeridos en tu código actual, sería de la siguiente forma:

Código
  1. Private Sub descarga(ByVal url As String)
  2.  
  3.    Dim isCompleted As Boolean
  4.  
  5.    Dim t As New Task(
  6.        Sub()
  7.            Try
  8.                Dim URLDATA As String = cliente.DownloadString(url)
  9.                Me.Invoke(Sub()
  10.                              TextBox2.Text = URLDATA
  11.                              If TextBox2.Text = "" Then
  12.                                  alert("error", "No response was obtained from the server.")
  13.                              Else
  14.                                  alert("alert", "Data Obtained, Descripting ...")
  15.                              End If
  16.                          End Sub)
  17.            Catch ex As Exception
  18.                Me.Invoke(Sub() alert("error", ex.Message))
  19.  
  20.            Finally
  21.                isCompleted = True
  22.            End Try
  23.        End Sub)
  24.  
  25.    t.Start()
  26.  
  27.    Do Until isCompleted
  28.        Application.DoEvents()
  29.    Loop
  30.  
  31. End Sub

...pero el uso de ese código implica malas prácticas de programación, tenlo en cuenta.


Título: Re: Desglosar un string en partes.
Publicado por: **Aincrad** en 1 Enero 2019, 17:12 pm
Gracias una vez mas!! ya no se congela. te lo envie para que me digas que tal quedo.

ahora buscare una api para descargar en mp4 y 3gp y la agregare al proyecto.


Título: Re: Desglosar un string en partes.
Publicado por: Eleкtro en 1 Enero 2019, 17:40 pm
ahora buscare una api para descargar en mp4 y 3gp y la agregare al proyecto.

Hace unos años probé 'libvideo' y me funcionó de maravilla...

  • https://github.com/i3arnon/libvideo

Saludos