在创建聊天应用的基础上,我写了一篇关于服务器和浏览器之间的WebSocket通信的文章。用 Java 实现服务器,用 javascript 实现客户端。
[过去关于套接字通信的文章] ・使用 Java 和 JavaScript与 Web 浏览器进行套接字通信① ・使用 Java 和 JavaScript 与 Web 浏览器进行套接字通信②
这一次,我们将在修改聊天应用程序的同时学习“如何处理 JSON 数据”。您还将了解“通过套接字通信发送和接收 JSON 数据”。
在本文中,我将主要描述如何处理 JSON。有关套接字通信的说明,请参阅过去的文章和 google 页面。⇒ 用 Java 实现服务器程序,用 JavaScript 实现客户端程序。
http://www.tohoho-web.com/ex/json.html 示例:{" name ":" Tanaka "," age ": 26} 以关联数组的形式保存值的事物。简而言之,如果你把它想象成一个**只是一个字符串**,就很容易理解了。(虽然不是真的)细节被省略。
JSON 数据可以在 JavaScript 中轻松处理。
对象⇒ JSON 使用JSON.stringify ()方法。
Example of use
var obj = {
name: 'Taro',
age: 30,
area: 'Tokyo'
}
var json = JSON.stringify(obj);
console.log(json);
Execution result
{"name":"Taro Tanaka","age":30}
JSON.stringify (obj)并将其分配给变量json。(转换为 JSON)console.log (json)。查看执行结果,可以看到关联数组格式的对象已经转换为 JSON 格式。⇒键和字符串用“”“括起来。数字保持裸露。
JSON ⇒ 对象 使用JSON.parse ()方法。
Example of use
var obj1 = {
name: 'Taro',
age: 30,
area: 'Tokyo'
}
var json = JSON.stringify(obj1);
//-----JSON data preparation so far-----
var obj2 = JSON.parse(json);
console.log(obj2);
console.log(obj2.name);
Execution result
{name: "Taro", age: 30, area: "Tokyo"}
Taro
JSON.stringify (obj1)并将其分配给变量json。(转换为 JSON) ** ---------- 到目前为止 JSON 数据准备(与上一节中的编码相同) ---------- **JSON.parse (json)并将其分配给变量ʻobj2`。(转换为对象)console.log (obj2)。查看执行结果,可以看到 JSON 数据已经转换为对象。`obj1 (object) ⇒json (JSON) ⇒ ʻobj2(对象)
Java 对象指的是类,不像 JavaScript 那样容易创建。在转换 JSON 和对象时,需要提前创建一个类**,该类具有与 JSON 变量对应的属性。
如果您在 Java 中处理 JSON,建议使用外部库。⇒ 处理 JSON 的 Java 标准 API 也是可用的,但需要大量时间和精力。
以下是处理 JSON 的著名外部库。
基本用法类似,但这次我将使用“杰克逊”。有关如何使用其他库以及如何应用外部库的信息,请酌情查看参考页面或 google。
Object ⇒ JSON 使用writeValueAsString ()ʻObjectMapper` 类的方法进行编码。
how to use
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(Object instance);
Example of use
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
//A class with properties to convert to JSON
class Info {
public String name = "Taro Tanaka";
public int age = 30;
}
//Class to perform encoding
public class Main {
public static void main(String[] args) {
Info info = new Info();//Instantiate a class to convert to JSON
ObjectMapper mapper = new ObjectMapper();//Create an instance of the ObjectMapper class
try {
//writeValueAsString()Encoding by method
String script = mapper.writeValueAsString(info);
System.out.println(script);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Execution result
{"name":"Taro Tanaka","age":30}
Main类来执行编码。class withObjectMapper ObjectMapper mapper = new ObjectMapper()`。mapper.writeValueAsString (info)。这时候就需要用try和catch来处理错误了。System.out.println (script)。查看执行结果,可以看到对象类已经转换为 JSON 格式。每个属性的变量名称和值存储为一对。
JSON ⇒ 对象 使用readValue ()ʻObjectMapper` 类的方法进行解码。
how to use
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(JSON data,Object class.class);
Example of use
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
//A class with properties that are converted from JSON
class Info {
public String name;
public int age;
}
//Class to perform decoding
public class Main {
public static void main(String[] args) {
String script = "{ \"name\":\"Taro Tanaka\", \"age\":30}";//Create JSON data as a string
ObjectMapper mapper = new ObjectMapper();//Create an instance of the ObjectMapper class
try {
//readValue()Decoding by method
Info info = mapper.readValue(script, Info.class);
System.out.println(info.name);
System.out.println(info.age);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Execution result
Taro Tanaka
30
Main类来执行解码。class withObjectMapper ObjectMapper mapper = new ObjectMapper()`。mapper.readValue (script, Info.class)。这时候就需要用try和catch来处理错误了。System.out.println (info. ~)。查看执行结果,可以看到 JSON 数据已经转换为对象类。解码后,可以通过访问指定对象的每个属性来获取值。
服务器程序:Java 客户端程序:JavaScript
描述进行socket通信时用JSON发送和接收的方法。由于 Java 和 JavaScript 的处理方式不同,我们将分别进行解释。
JavaScript 没有什么特别之处。如上所述,您可以通过JSON.stringify ()方法和JSON.parse ()方法轻松地在对象和 JSON 之间进行转换。如果客户端在发送前编码,接收后解码,则没有问题。
对象⇒ JSON
When sending
var obj = { type:'A' , msg:'a' };
var json = JSON.stringify(obj);
socket.send(json);
JSON.stringify ()使用该方法编码为 JSON 。send ()使用WebSocket的方法发送JSON数据JSON ⇒ 对象
When receiving
socket.onmessage = function(e) {
var obj = JSON.parse(e.data);
};
JSON.parse (e.data)当使用 JSON 进行 Java 套接字通信时,它并不像 JavaScript 那样简单。⇒ 需要准备编码器、解码器和对象类。
对象⇒ JSON
通过套接字通信发送 JSON 数据时,请在发送前使用编码器将对象转换为 JSON。
通常sendText ()发送文本数据时使用该sendObject ()方法,但发送JSON时使用该方法。参数是一个对象,由编码器转换为 JSON,然后发送。
1. 创建一个要发送的对象
创建一个具有像普通类一样的属性的类。像往常一样描述构造函数、setter 和 getter。(没有它也可以转换。)
Object class
public class JsonObj {
private String type = "type1";
private String msg = "msg1";
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
2. 创建编码器
编码器实现了`Encoder.Text class in thejavax.websocket package. (There is also the ʻEncoder.Binary类,但是因为是处理二进制数据的类所以省略)
ʻEncoder.Text <> `generics 描述了要编码的对象类。
encoder
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonEncoder implements Encoder.Text<JsonObj>{
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Encoding process(Object → JSON)
public String encode(JsonObj obj) throws EncodeException {
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
@Override//Do nothing to destroy
public void destroy() {}
}
`如果你继承了Encoder.Text`类,你需要重写以下方法。
destroy (): 编码器被破坏时的处理。基本上 ʻinit() anddestroy() do not have to do anything. In ʻencode (Object),将 ** 参数设置为 object ** 并指定 JSON ** 作为编码后的返回值。
3.注册编码器
@ServerEndpoint
//Specify encoder class
@ServerEndpoint(value = "/json" , encoders = JsonEncoder.class)
public class JsonTest {
//Omission
//sendObject()The argument of is an object
//Encoded before sending
session.getAsyncRemote().sendObject(obj)
//Omission
}
使用编码器时,请在 中指定编码器类@ServerEndpoint ()。通过此处指定,将由发送对象时指定的编码器转换为 JSON 数据。
-- sendObject (obj)** ⇒ 编码过程 (obj → JSON) ⇒ 发送 **
JSON ⇒ 对象
通过socket通信接收JSON数据时,在接收前使用解码器将JSON转换为对象。
通常,作为`onMessage()`方法的参数作为String类型的字符串接收,但通过使用解码器,在接收之前进行解码处理,并作为对象接收。
1.创建目标对象
解码时,需要准备一个对象类,该对象类具有对应于 JSON 元素的属性。如果接收多个 JSON 时内容和格式不同,则必须为每个 JSON 准备多个对象类。
在编码的情况下,所有对象都可以转换成JSON随时发送,在解码的情况下,需要提前掌握接收到的JSON的内容,并在解码前准备对象类作为接收端口。
Object class
public class JsonObj {
private String type;
private String msg;
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
2.创建解码器
解码器实现包Decoder.Text中的类 javax.websocket。(还有一个Decoder.Binary类,但是因为是处理二进制数据的类所以省略了。)
在 的泛型中描述解码目的地的对象类Decoder.Text <>。
Decoder
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonDecoder implements Decoder.Text<JsonObj> {
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Judgment of whether decoding is possible
public boolean willDecode(String text) {
return (text != null);
}
@Override//Decoding process(JSON → object)
public JsonObj decode(String text) throws DecodeException {
ObjectMapper mapper = new ObjectMapper();
JsonObj obj = null;
try {
obj = mapper.readValue(text, JsonObj.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return obj;
}
@Override//Do nothing to destroy
public void destroy() {}
}
如果继承Decoder.Text该类,则需要重写以下方法。
willDecode (String text):判断是否执行解码过程。decode (Object obj): 解码过程。destroy (): 解码器被破坏时的处理。基本上ʻinit() anddestroy() do not have to do anything. Set the ** argument ofwillDecode() to JSON **, and if the return value istrue , execute the following decoding. If it is false , it will not be decoded and the subsequent@OnMessage methods will not be executed. Indecode()`,将**参数设置为JSON **并指定object **作为编码后的返回值。
3.注册解码器
@ServerEndpoint
//Specify decoder class
@ServerEndpoint(value = "/json" , decoders = JsonDecoder.class)
public class JsonTest {
//Omission
//@Decoded before the OnMessage method
@OnMessage
public void onMessage(JsonObj obj , Session mySession) {
}
//Omission
}
使用解码器时,请在 中指定解码器类@ServerEndpoint ()。通过此处指定,将由接收数据时指定的解码器转换为对象。⇒@OnMessage方法的参数是**对象类型**。(通常是字符串类型)
-** 接收 ⇒ 解码过程(JSON → obj) ⇒ ** @OnMessage** 方法 **
修改Past中创建的聊天应用。
在 WebSocket 通信中,只有一个套接字用于接收数据。也就是说,因为是一次性的,所以即使有多个来源也无法区分。如果你能分辨,你必须分解字符串的内容来区分它们。无论如何要解码,处理JSON很方便。
其实接收方式有3种:1.Text 2.Binary 3.PingPong,但是由于我们这里只处理文本格式,所以我们认为只有一个socket。
JsonIndex.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Send / receive JSON</title>
<script type="text/javascript" src="JsonSocket.js"></script>
</head>
<body>
<div
style="width: 500px; height: 200px; overflow-y: auto; border: 1px solid #333;"
id="show1"></div>
<input type="text" size="80" id="msg1" name="msg1" />
<input type="button" value="Send" onclick="sendMsg1();" />
<p></p>
<div
style="width: 500px; height: 200px; overflow-y: auto; border: 1px solid #333;"
id="show2"></div>
<input type="text" size="80" id="msg2" name="msg2" />
<input type="button" value="Send" onclick="sendMsg2();" />
</body>
</html>
观点
show1和 show2,文本框分别为msg1和 msg2。使用稍后描述的 JavaScript 文件操作这些。JsonSocket.js
//Object creation for JSON
var obj = { type:null , msg:null };
//WebSocket object generation
var wSck= new WebSocket("ws://localhost:8080/jsonTest/json");
//Action when connecting socket
wSck.onopen = function() {
document.getElementById('show1').innerHTML += "Connected." + "<br/>";
document.getElementById('show2').innerHTML += "I'm connected ~" + "<br/>";
};
//Action when receiving a message
wSck.onmessage = function(e) {
//Decode JSON data into an object
var json = JSON.parse(e.data);
//Change the execution content depending on the type value of JSON data
if(json.type === 'msg1'){document.getElementById('show1').innerHTML += json.msg + "<br/>";}
else if(json.type === 'msg2'){document.getElementById('show2').innerHTML += json.msg + "<br/>";}
};
//Send message 1
var sendMsg1 = function(val) {
var element = document.getElementById('msg1')
obj.type = element.name;//Substitute the contents of the object
obj.msg = element.value;
var json = JSON.stringify(obj);//Encode object to JSON
wSck.send(json);//Send JSON
element.value = "";//Clear the contents
};
//Send message 2
var sendMsg2 = function(val) {
var element = document.getElementById('msg2');
obj.type = element.name;
obj.msg = element.value;
var json = JSON.stringify(obj);
wSck.send(json);
element.value = "";
};
观点
JsonTest.java
package jsonTest;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
//Describe the decoder and encoder in the arguments
@ServerEndpoint(value = "/json" , decoders = JsonDecoder.class , encoders = JsonEncoder.class)
public class JsonTest {
private static Set<Session> user = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session mySession) {
System.out.println("connect ID:"+mySession.getId());
user.add(mySession);
}
//Decoded before this method
@OnMessage
public void onMessage(JsonObj obj , Session mySession) {
for (Session user : user) {
user.getAsyncRemote().sendObject(obj);//What you send is an object(Encoded before sending)
System.out.println(user.getId()+"Second"+mySession.getId()+"I sent the second message!");
}
if(obj.getMsg().equals("bye")) {onClose(mySession);}
}
@OnClose
public void onClose(Session mySession) {
System.out.println("disconnect ID:"+mySession.getId());
user.remove(mySession);
try {
mySession.close();
} catch (IOException e) {
System.err.println("An error has occurred: " + e);
}
}
}
观点
@ServerEndpoint。@OnMesaage并将 JSON 转换为对象。⇒@OnMesaage方法的参数是ʻObj` 类型。sendObject (obj)方法发送对象时,会在发送到客户端之前执行指定的编码器,并将对象转换为 JSON。sendText ()发送字符串时使用,sendObject ()发送对象时使用。JsonObj.java
package jsonTest;
public class JsonObj {
private String type;
private String msg;
//constructor
public JsonObj() {}
//Setter
public void setType(String type) {this.type = type;}
public void setMsg(String msg) {this.msg = msg;}
//Getter
public String getType() {return type;}
public String getMsg() {return msg;}
}
观点
type和 msg。⇒ 创建一个对应于客户端程序对象(接收到的 JSON)的类。type属性值判断来源。JsonEncoder.java
package jsonTest;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonEncoder implements Encoder.Text<JsonObj>{
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Encoding process(Object → JSON)
public String encode(JsonObj obj) throws EncodeException {
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
@Override//Do nothing to destroy
public void destroy() {}
}
观点
writeValueAsString ()ʻObjectMapper` 类的方法进行编码。package jsonTest;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonDecoder implements Decoder.Text<JsonObj> {
@Override//Initialization does nothing
public void init(EndpointConfig config) {}
@Override//Judgment of whether decoding is possible
public boolean willDecode(String text) {
return (text != null);
}
@Override//Decoding process(JSON → object)
public JsonObj decode(String text) throws DecodeException {
ObjectMapper mapper = new ObjectMapper();
JsonObj obj = null;
try {
obj = mapper.readValue(text, JsonObj.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return obj;
}
@Override//Do nothing to destroy
public void destroy() {}
}
观点
Decoder.Text <JsonObj>.decode ()方法的参数是一个字符串(JSON),返回值是一个对象。readValue ()ʻObjectMapper` 类的方法进行编码。JsonIndex.html在 Chrome 中 执行。
聊天字段已增加到两个。您可以在每个聊天字段中独立发送和接收。⇒ 多路径的实现完成。
现在它很长,描述客户端和服务器上发生的事情。
@OnMessage以解码的对象作为参数执行该方法。sendObject ()。type属性值确定来源并向每个来源显示一条消息。-如果接收到未知的JSON数据,会因为没有准备好对应的对象类而出错。⇒有人支持它,所以我可能会尽快检查它。它看起来相当复杂。
- 接收多种 JSON 数据时不支持。⇒ 好像没那么难。可以通过增加解码器和对象类来支持JSON的内容。
- 不知道应该创建什么样的对象类来支持嵌套的 JSON。⇒ 如果你google,它会出来,如果有必要,检查一下。
- 由于对二进制数据的处理不是很了解,所以不支持二进制数据的发送和接收。⇒必要时检查,例如发送和接收图像。
它比我预期的要复杂。我后悔了,因为它变长了。我应该总结得更多。
在Java中处理JSON,使用外部库和准备一个对象类是很麻烦的。使用 JavaScript,它以一行结尾。
Java socket通信中处理JSON时,有编码类和解码类方便吗?必须准备一个编码器类和一个解码器类是很麻烦的。
这很麻烦,但如果你想使用 JSON,你就无能为力了。对如何在 Java 中处理 JSON 有更深入的了解是件好事。看来您可以在个人生产级别使用它。
-使用 JavaScript编码和解码 JSON 数据 -用Java 编码和解码 JSON 数据(Jackson) -用 Java编码和解码 JSON 数据(Jackson 专业化) -用 Java编码和解码 JSON 数据(Jackson 等人) -发送/接收 JSON in Socket Communication -在 Socket 通信中发送/接收 JSON(多对象)
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h