unicornio
Hola, tengo una columna de datos HTML que necesito mostrar como texto. Necesito deshacerme de todas las etiquetas HTML y sustituir los caracteres HTML reservados. Estaba tratando de eliminar recursivamente todas las etiquetas HTML primero. Luego planeo crear una tabla de los caracteres reservados más comunes, los valores para reemplazarlos y generar una lista para llamar a reemplazar para cada fila en esa tabla.
Todavía soy nuevo en M, pero encontré esto para reemplazar las etiquetas HTML. Excepto que solo elimina una sola etiqueta, lo que no es útil.
https://social.technet.microsoft.com/Forums/en-US/7ec64d6d-c3fc-4110-94c7-2e0087171475/how-to-remove…)
Pero cuando trato de expandir eso a una función recursiva, obtengo un error de desbordamiento de pila. Planeo comenzar de nuevo para tratar de aprender M, pero espero que alguien pueda ayudarme mientras tanto con una solución rápida para descubrir qué hice mal. A continuación se muestra mi función. Gracias.
dejar
removeOne = (entrada) =>
dejar
texto = Texto.De(entrada),
longitud = Texto.Longitud(texto),
posición = Texto.PosiciónDe(texto, «<"),
positionEnd = Texto.PosiciónDe(texto, «>»),
rango = posición Posición-final+1,
resultado = si la posición >= 0 entonces Text.ReplaceRange(text, position, range, «») otra entrada
en
resultado,
removeAll = (entrada) =>
dejar
rmvUno = eliminarUno(entrada),
rmvAll = si Text.PositionOf(rmvOne, «l») >= 0 entonces @removeAll(rmvOne) else rmvOne
en
rmv todo,
// Fuente = obtener de la base de datos,
Fuente = «
hola, soy un mensaje de texto para reemplazar, lol
«,
// retorno = eliminarTodo([columnToPassToFunction])
return = removeAll(Fuente)
en
regreso
Marcel Beug
Solo cambia el «|» en «<"
rmvAll = si Texto.PosiciónDe(rmvUno, «<«) >= 0 entonces @removeAll(rmvOne) else rmvOne
De lo contrario, puede obtener resultados inesperados si la cadena contiene < o > que no forman parte de una etiqueta HTML.
Si está interesado, puedo compartir mi código que solo elimina pares de etiquetas, es decir cadenas precedidas por el mismo sin /: <...>
Stejin
Aquí hay un enfoque diferente que usa la función Web.Page incorporada.
Debajo de la función personalizada, reemplace los caracteres especiales como o $amp; y, además, analiza y combina texto en etiquetas HTML.
(Text as any) => let
Source = Text,
Html = Web.Page(Source),
resolve = (t as table) =>
let
Result = List.Accumulate(Table.ToRecords
He leído esto y todavía estoy un poco confundido.
Solo quiero agregar una nueva columna de texto basada en una columna basada en HTML y eliminar las etiquetas HTML como se describe. No estoy seguro de cómo agregar una función personalizada.
¿Se puede hacer todo esto en un solo paso, dentro de la creación de la nueva columna?
Mi nuevo nombre de columna es: NoteText, que se basa en la columna NoteHTML
Gracias
Agregue una función como lo haría con una consulta estándar.
1. Cree una nueva consulta en blanco. Nómbrelo como "Limpiador de HTML".
2. En el Editor avanzado, pegue lo siguiente:
(HTML como texto) =>
dejar
Fuente = Texto.De(HTML),
SplitAny = Texto.SplitAny(Fuente,"<>"),
ListaAlternativa = Lista.Alternativa(DividirCualquiera,1,1,1),
ListSelect = List.Select(ListAlternate, each _<>" "),
TextCombine = Text.Combine(ListSelect, " ")
en
Combinación de texto
3. Cierre el Editor.
4. En su consulta principal, abra el Editor avanzado.
5. Agregue el siguiente paso:
#"Limpieza de HTML" = Table.AddColumn(#"Paso anterior", "NotaTexto", cada uno
Si [NoteHTML] = nulo
entonces nulo
más #"Limpiador de HTML"([NoteHTML])),
Buena suerte.
Gracias, pero desafortunadamente, no hubo suerte. Recibo más de 4000 errores.
Esta es la sintaxis que tengo:
dejar
Fuente = OData.Feed("https://xyzasdf1111.api.crm.dynamics.com/api/data/v9.1", nulo, [Implementation="2.0"]),
new_arcollectioncalls_table = Fuente{[Name="new_arcollectioncalls",Signature="table"]}[Data],
#"Nuevo_propietario_actual ampliado" = Table.ExpandRecordColumn(nueva_tabla_de_llamadas_arcolección, "nuevo_propietario_actual", {"nombre completo"}, {"nuevo_propietario_actual.nombre_completo"}),
#"New_BillingMgr ampliado" = Table.ExpandRecordColumn(#"Nuevo_propietario actual ampliado", "new_BillingMgr", {"fullname"}, {"new_BillingMgr.fullname"}),
#"Nuevas_anotaciones_de_llamada_de_arcolección ampliadas" = Table.ExpandTableColumn(#"Nuevas_anotaciones_de_llamada_de_colección_ampliadas", "nuevas_anotaciones_de_llamada_de_colección", {"creado en", "_valor_id_propietario", "texto de nota"}, {"anotaciones_nuevas_llamada_arcolección.creado en", "nuevas_anotaciones_llamada_arcolección._valor_id_propietario", "nuevas_anotaciones_llamada_arcolección. nota de texto"}),
#"Columnas eliminadas" = Table.RemoveColumns(#"Expanded new_arcollectioncall_Annotations",{"new_arcollectioncall_Annotations._ownerid_value"}),
#"Dividir columna por delimitador" = Table.SplitColumn(Table.TransformColumnTypes(#"Columnas eliminadas", {{"new_arcollectioncall_Annotations.createdon", type text}}, "en-US"), "new_arcollectioncall_Annotations.createdon", Splitter. SplitTextByEachDelimiter({" "}, QuoteStyle.Csv, false), {"new_arcollectioncall_Annotations.createdon.1", "new_arcollectioncall_Annotations.createdon.2"}),
#"Tipo cambiado" = Table.TransformColumnTypes(#"Dividir columna por delimitador",{{"new_arcollectioncall_Annotations.createdon.1", escriba fecha}, {"new_arcollectioncall_Annotations.createdon.2", escriba hora}}),
#"Columnas eliminadas1" = Table.RemoveColumns(#"Tipo cambiado",{"new_arcollectioncall_Annotations.createdon.2"}),
#"Tipo modificado1" = Table.TransformColumnTypes(#"Columnas eliminadas1",{{"new_arcollectioncall_Annotations.createdon.1", type date}}),
#"Filas filtradas" = Table.SelectRows(#"Tipo modificado1", cada uno ([new_status] = verdadero)),
#"Otras columnas eliminadas" = Table.SelectColumns(#"Filas filtradas",{"nuevo_legal", "_nuevo_valor_de_propietario actual", "_valor_de_identificación_de_propietario", "nuevas_notas_de_colección", "nuevas_colecciones", "_creado en nombre de_valor", "nuevo_número_de_cliente", "creado en", "usuariopropietario", "equipopropietario", "id_propietario", "nuevas_anotaciones_llamada_arcolección.creado en.1", "nuevas_anotaciones_llamada_arcolección.notatexto", "nuevo_BillingMgr.nombre completo", "nuevo_propietario_actual.nombre completo"}),
#"Columnas renombradas" = Table.RenameColumns(#"Otras columnas eliminadas",{{"new_arcollectioncall_Annotations.notetext", "NoteHTML"}}),
#"Limpieza de HTML" = Table.AddColumn(#"Columnas renombradas", "Texto de nota simple", cada una
Si [NoteHTML] = nulo
entonces nulo
más #"Limpiador de HTML"([NoteHTML]))
en
#"Limpieza de HTML"
Y la definición de "Consulta en blanco":
"(HTML como texto) =>#(cr)#(lf)let#(cr)#(lf)Source = Text.From(HTML),#(cr)#(lf)SplitAny = Text.SplitAny(Source, ""<>""),#(cr)#(lf)ListAlternate = List.Alternate(SplitAny,1,1,1),#(cr)#(lf)ListSelect = List.Select(ListAlternate, each _< >"" ""),#(cr)#(lf)TextCombine = Text.Combine(ListSelect, "" "")#(cr)#(lf)in#(cr)#(lf)TextCombine"
Desafortunadamente, sin ver los errores y los datos que los generan, no podré ayudar mucho más. Quizás podría crear una tabla 'ficticia' en la consulta, para incluir filas de datos que generan errores y filas que no. Usa el siguiente código:
dejar
Tabla = #tabla( tipo tabla
[
#"NoteHTML" = text
],
{
{"Datos que arrojan un error"},
{"Datos que arrojan un error"},
{nulo},
{"Datos que no"}
}
),
#"Limpieza de HTML" = Table.AddColumn(Table, "PlainNoteText", each
Si [NoteHTML] = nulo
entonces nulo
más #"Limpiador de HTML"([NoteHTML]), teclee el texto)
en
#"Limpieza de HTML"
Hola,
Tengo el mismo problema que tú, pero no estoy seguro de dónde debo copiar y pegar esa función. Tengo una tabla con varias columnas y solo necesito limpiar los datos de las ETIQUETAS HTML en una de ellas. ¿Podría explicar con más detalles cómo lo hizo? eso
Atentamente,
Nicolás
Solo cambia el "|" en "<"
rmvAll = si Texto.PosiciónDe(rmvUno, "<") >= 0 entonces @removeAll(rmvOne) else rmvOne
De lo contrario, puede obtener resultados inesperados si la cadena contiene < o > que no forman parte de una etiqueta HTML.
Si está interesado, puedo compartir mi código que solo elimina pares de etiquetas, es decir cadenas precedidas por el mismo sin /: <...>
Dispara, lo siento gracias. Estaba haciendo muchas pruebas y comencé con una función recursiva para eliminar 'L'. Le daré una oportunidad al código completo ahora. Además, un buen punto sobre los pares de etiquetas. Si no le importa, me encantaría revisar su código para mejorar esto.
Aquí está mi código. Debe llamarse con StartPosition 0. En cada iteración, el código examina la cadena desde esa posición de inicio en busca de pares de etiquetas de código, los elimina si los encuentra y llama a la próxima iteración con una nueva StartPosition, por lo que el código también puede manejar la situación que la cadena incluye una etiqueta final sin la correspondiente etiqueta inicial, o .
Tenga en cuenta que también incluí un mecanismo para detenerse después de un número máximo de iteraciones, lo que es especialmente útil durante el desarrollo, para evitar iteraciones interminables (hasta el desbordamiento de la pila).
fnRHTMLT = (String as text, StartPosition as number, optional Iteration as number, optional MaxIterations as number) as text => let StringFromStartposition = Text.RemoveRange(String, 0, StartPosition), StartPositionEndTag = Text.PositionOf(StringFromStartposition, "</"), PositionsEndTag = if StartPositionEndTag = -1 then -1 else Text.PositionOf(Text.RemoveRange(StringFromStartposition, 0, StartPositionEndTag),">"), StartTag = if PositionsEndTag = -1 then null else "<" & Text.Range(StringFromStartposition, StartPositionEndTag + 2, PositionsEndTag - 1), StartPositionStartTag = if PositionsEndTag = -1 then -1 else Text.PositionOf(Text.Start(String,StartPosition + StartPositionEndTag),StartTag,Occurrence.Last), NewString = if StartPositionStartTag = -1 then String else Text.RemoveRange(Text.RemoveRange(String,StartPosition + StartPositionEndTag, PositionsEndTag + 1),StartPositionStartTag, PositionsEndTag), NextStartPosition = if PositionsEndTag = -1 then -1 else if StartPositionStartTag = -1 then StartPosition + StartPositionEndTag + 1 else StartPosition + StartPositionEndTag - PositionsEndTag, Result = if NextStartPosition = -1 then NewString else if Iteration = null then @fnRHTMLT(NewString, NextStartPosition) else if Iteration = MaxIterations then NewString else @fnRHTMLT(NewString, NextStartPosition, Iteration + 1, MaxIterations) in Result
mmayer
En respuesta a Marcel Beug
Intenté incorporar su código para limpiar el HTML en solo una de mis columnas. Pero me sale el siguiente error: "Expresión.Error: 1 argumentos fueron pasados a la función que espera entre 2 y 4.
Detalles:
patrón =
Argumentos=Lista"
Este es el HTML que estoy tratando de eliminar del [Notes] columna:
Antes:
Después:
La solicitud incluye: indicador de estado para los costos del proyecto y el progreso del trabajo, notificación por correo electrónico a los supervisores de elementos pendientes/incompletos. Se ha enviado TSR. Esperando en TEC. Limpieza de SWS y actualización de datos en curso en preparación de modificaciones del sistema. Sistema limpio y listo para trabajar con TEC en renovación.
Aquí está el código:
let Source = SharePoint.Tables("https://orgname.sharepoint.com/sites/department/", [ApiVersion = 15]), #"2be78719-1e12-4827-8f88-d9edd1a7781f" = Source{[Id="2be78719-1e12-4827-8f88-d9edd1a7781f"]}[Items], #"Renamed Columns" = Table.RenameColumns(#"2be78719-1e12-4827-8f88-d9edd1a7781f",{{"ID", "ID.1"}}), #"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"End Date", type date}, {"Start Date", type date}, {"Today", type date}, {"End Date (Actu", type date}, {"Created", type date}, {"Modified", type date}, {"EndDateT", type text}, {"Completion", Int64.Type}, {"Id", Int64.Type}, {"ID.1", Int64.Type}, {"EditorId", Int64.Type}}), fnRHTMLT = (String as text, StartPosition as number, optional Iteration as number, optional MaxIterations as number) as text => let StringFromStartposition = Text.RemoveRange(String, 0, StartPosition), StartPositionEndTag = Text.PositionOf(StringFromStartposition, "</"), PositionsEndTag = if StartPositionEndTag = -1 then -1 else Text.PositionOf(Text.RemoveRange(StringFromStartposition, 0, StartPositionEndTag),">"), StartTag = if PositionsEndTag = -1 then null else "<" & Text.Range(StringFromStartposition, StartPositionEndTag + 2, PositionsEndTag - 1), StartPositionStartTag = if PositionsEndTag = -1 then -1 else Text.PositionOf(Text.Start(String,StartPosition + StartPositionEndTag),StartTag,Occurrence.Last), NewString = if StartPositionStartTag = -1 then String else Text.RemoveRange(Text.RemoveRange(String,StartPosition + StartPositionEndTag, PositionsEndTag + 1),StartPositionStartTag, PositionsEndTag), NextStartPosition = if PositionsEndTag = -1 then -1 else if StartPositionStartTag = -1 then StartPosition + StartPositionEndTag + 1 else StartPosition + StartPositionEndTag - PositionsEndTag, Result = if NextStartPosition = -1 then NewString else if Iteration = null then @fnRHTMLT(NewString, NextStartPosition) else if Iteration = MaxIterations then NewString else @fnRHTMLT(NewString, NextStartPosition, Iteration + 1, MaxIterations) in Result, #"RemoveHTML" = Table.TransformColumns(#"Changed Type",{{"Notes", fnRHTMLT, type text}}), in RemoveHTML
Grumelo
En respuesta a Marcel Beug
Esta solución es capaz de eliminar etiquetas como
<p> </p>
pero no algo como
<div class="..."> </div>
Un ejemplo de llamada de función sería bienvenido. No entiendo cuál es el significado de "Iteración".
¿Es la cantidad de etiquetas que desea eliminar?
Grumelo
En respuesta a Grumelo
Mi solución para limpiar etiquetas HTML
let TextFromHtml = (HTML as any) => let Source = if HTML = null then "" else Text.From(HTML), SplitAny = Text.SplitAny(Source,"<>"), ListAlternate = List.Alternate(SplitAny,1,1,1), ListSelect = List.Select(ListAlternate, each _<>""), TextCombine = Text.Combine(ListSelect, "") in TextCombine in TextFromHtml
Para principiantes: cree una consulta en blanco y copie y pegue el código anterior; cambie el nombre de la consulta como "TextFromHtml"
Ejemplo de llamar a esta función en una columna llamada Comentario:
= Table.TransformColumns(#"Paso anterior",{{"Comentario", TextFromHtml, escriba texto}})
Referencia: https://social.technet.microsoft.com/Forums/office/en-US/b080d122-14f0-43bc-8a86-f50cdf1c32d8/removi...
omtinol
En respuesta a Marcel Beug
Acabo de probar tu código, pero recibí el error "No se reconoció el nombre 'Iteración'. Asegúrate de que esté escrito correctamente". ¿Alguna sugerencia?
Marcel Beug
En respuesta a omtinol
Probablemente no copiaste mi código correctamente.
De lo contrario: el código debe estar precedido por un "let" adicional y debe agregarse "in fnRHTMLT" al final:
let <code block: see above> in fnRHTMLT
omtinol
En respuesta a Marcel Beug
OK, gracias, eso funcionó. Pero no elimina todo el HTML. Se limpió , ,
- ,
, y algunas otras cadenas de uno y dos caracteres, pero pasó por alto
, , y largo
No veo nada en el código que filtre algunas cadenas de uno o dos caracteres, pero no otras. ¿Cómo puedo adaptar el código para encontrar cadenas de cualquier longitud?
Marcel Beug
En respuesta a omtinol
El código no mira las longitudes, en otras palabras, las longitudes no importan.
El código busca pares de etiquetas como
y
En general: una etiqueta de inicio sin barra oblicua y una etiqueta final con barra oblicua /.
Las etiquetas que no vienen en esos pares no se eliminan.
Puede considerar una solución en la que se elimine cualquier cosa entre "<" y ">" (incluidos estos delimitadores), pero el riesgo es que se eliminen los caracteres que no forman parte de una etiqueta HTML.
Puede encontrar un ejemplo en Technet.
Max01
En respuesta a Marcel Beug
Hola,
Soy muy nuevo en Power BI y trato de usar la solución publicada anteriormente, pero no estoy seguro de qué bits reemplazar y exactamente con qué reemplazarlos. Pegué la consulta en el editor avanzado e intenté reemplazar 'cadena como texto' con el nombre de mi columna, pero no funciona.
¿Puedes ayudarme explicando?
Gracias,
máx.
omtinol
En respuesta a Marcel Beug
Acabo de probar tu código, pero recibí el error "No se reconoció el nombre 'Iteración'. Asegúrate de que esté escrito correctamente". ¿Alguna sugerencia?